How to run a Salesforce license audit yourself

A license audit answers three questions: what you pay for, who it's assigned to, and who actually uses it. You can answer all three from Setup and a handful of read-only SOQL queries. This guide walks through each step.

By Pratik Poddar · Updated 23 October 2026 · About 9 minutes

Before you start: the access you need

Run the audit as a System Administrator if you can. If not, you need at least these permissions, according to Salesforce's documentation:

  • View Setup and Configuration to see the User Licenses list on Company Information.
  • Manage Users or Monitor Login History to read login history for everyone (the LoginHistory object).
  • Manage Users to read the UserLogin object, which tells you who is frozen.

Every query below is a SELECT. Nothing in this guide changes your org. Run them in the Developer Console (Query Editor), Workbench, or the Salesforce CLI (sf data query).

Step 1: List what you own on Company Information

From Setup, find and select Company Information, then scroll to the User Licenses related list. The same page has Permission Set Licenses and Feature Licenses lists. For each license you'll see Total, Used and Remaining counts.

Two things to know about this page:

  • Salesforce says it can take up to 24 hours for the counts to refresh after you add or remove licenses or activate or deactivate users. Don't panic if a deactivation doesn't show straight away.
  • The total is what's provisioned in the org. Salesforce's own glossary notes that provisioned and purchased amounts can differ, for example when a renewal order hasn't been processed yet. Check the totals against your order form, not just this screen.

Step 2: Pull the same counts with SOQL

The UserLicense object gives you the same numbers in a form you can paste into a spreadsheet:

SELECT Name, MasterLabel, TotalLicenses, UsedLicenses, Status
FROM UserLicense

UsedLicenses is the number of licenses assigned to active users. Since API version 64.0 you can't filter on it in a WHERE clause, so pull every row and filter in the sheet. Most orgs care about a few rows: Salesforce (the full CRM seat), Salesforce Platform, and Salesforce Integration.

Total minus Used is your first, easiest finding: seats you pay for that nobody holds.

Step 3: Find active users who don't log in

Next, list active users with their license and last login. Users who have never logged in show a blank LastLoginDate.

SELECT Id, Name, Username, Profile.Name, Profile.UserLicense.Name,
       LastLoginDate, CreatedDate
FROM User
WHERE IsActive = true
  AND (LastLoginDate < LAST_N_DAYS:90 OR LastLoginDate = null)
ORDER BY LastLoginDate ASC NULLS FIRST

Ninety days is a common threshold, not a Salesforce rule. Pick a number your managers will accept (60 or 90 are typical) and use it consistently. Exclude people on leave and brand-new hires (check CreatedDate) before you call anyone inactive.

Separate people from integrations

A "last login" can be an integration calling the API on someone's behalf. Login history tells you how each login happened. Salesforce's Login History page shows up to 20,000 records for the past 6 months, and the download covers the same 6 months and includes API logins.

SELECT UserId, LoginTime, LoginType, Application, Status
FROM LoginHistory
WHERE LoginTime = LAST_N_DAYS:90

Keep only successful logins (filter the Status column in your sheet), then look at LoginType and Application per user. A user whose only logins are API or OAuth calls from one application is probably an integration, not a person. Those are often candidates for a cheaper license type; see how to reclaim unused Salesforce licenses.

Step 4: Find frozen users who still hold a seat

Freezing is a common step when someone leaves, and it's easy to forget the second half. Salesforce is explicit: "Freezing user accounts doesn't make their user licenses available for use in your organization. To make their user licenses available, deactivate the accounts."

SELECT UserId, IsFrozen
FROM UserLogin
WHERE IsFrozen = true

Match the UserId values to your Step 3 export. Every active, frozen user is a paid seat doing nothing.

Step 5: Check permission set licenses

Add-ons such as CPQ or Field Service are often sold as permission set licenses. Their counts live on PermissionSetLicense:

SELECT MasterLabel, DeveloperName, TotalLicenses, UsedLicenses, ExpirationDate
FROM PermissionSetLicense
ORDER BY MasterLabel

To see who holds each one, list the assignments and match AssigneeId to your user export from Step 3 (include inactive users):

SELECT PermissionSetLicense.MasterLabel, AssigneeId
FROM PermissionSetLicenseAssign
ORDER BY PermissionSetLicense.MasterLabel

Total minus Used shows idle permission set licenses; assignments to inactive or non-logging-in users show the rest. Check the order form too: some permission set licenses come with an edition or add-on rather than being bought one by one, so they may not be separately reducible.

Step 6: Check managed package seats

AppExchange apps you license per user have their own seat counts on PackageLicense:

SELECT Id, NamespacePrefix, AllowedLicenses, UsedLicenses, ExpirationDate, Status
FROM PackageLicense

Then list who holds a seat:

SELECT PackageLicenseId, UserId
FROM UserPackageLicense

Match UserId against all users (active and inactive) in your sheet. This matters because Salesforce documents that a deactivated user "will continue to count against the available licenses associated to managed packages that were previously assigned to the user" until you remove the seat under Setup › Installed Packages › Manage Licenses. Sites licensed to every user (site licenses) won't show individual assignments.

Step 7: Put it in one sheet and price it

For each license type, write down:

  1. Owned (from your order form) and provisioned (Company Information).
  2. Assigned to active users.
  3. Assigned to users with no human login in your window.
  4. Assigned to frozen users.
  5. Unassigned.
  6. Add-on and package seats held by inactive or idle users.

Multiply each line by what you pay per seat per month. Use your contract price, not list price: discounts vary a lot. That total is your renewal opportunity. It usually isn't money you get back this year, because standard Salesforce terms don't let you reduce quantities mid-term (more on that in our renewal negotiation guide).

Before you deactivate anyone, confirm with their manager, transfer record ownership where needed, and check whether a "full" Salesforce seat could become a cheaper one instead. See Sales Cloud vs Platform license.

Where RenewalReady fits

Done by hand, this can take an admin a few hours, and it goes stale as people join and leave. RenewalReady runs the same read-only queries (users, login history, user licenses, permission set licenses, package seats, frozen users), separates human logins from API logins, flags users who own or edit no Leads, Opportunities, Cases or Campaigns as possible Platform candidates, and prices each finding at the prices you enter. It recommends; it never changes your org. You get a named-seat list and a PDF renewal pack for finance.

Skip the spreadsheet

Run a free, read-only scan. It takes under a minute for most orgs, and the free scan stores nothing from your org on our servers.

Run a free scan

FAQ

How often should I audit Salesforce licenses?

At minimum, before your renewal window opens. Salesforce's renewal FAQ says the window for changes starts 90 days before the contract end date, so finish the audit before then. Many admins also review quarterly so leavers don't pile up.

Does freezing a user free up their Salesforce license?

No. Salesforce's documentation says freezing doesn't make the license available; you have to deactivate the user to do that.

Do deactivated users count against my licenses?

A deactivated user doesn't count against your available user licenses, but deactivating doesn't reduce the number of licenses you're billed for. Managed package seats stay assigned to deactivated users until you remove them.

Can I run these SOQL queries without changing anything?

Yes. Every query in this guide is a read-only SELECT. You need permissions such as View Setup and Configuration and Manage Users (or Monitor Login History) to see all rows.

Sources

  1. Salesforce Help, View Your Org's User Licenses in Setup
  2. Salesforce Help, Digital Wallet glossary (provisioned vs purchased)
  3. Salesforce Help, Monitor Login History
  4. Salesforce Help, Freeze or Unfreeze User Accounts
  5. Salesforce Help, Considerations for Deactivating Users
  6. Salesforce Help, Inactive users assigned package licenses (000386472)
  7. Salesforce Object Reference: UserLicense, LoginHistory, UserLogin, PermissionSetLicense, PackageLicense, UserPackageLicense
  8. Salesforce Help, Salesforce Renewal FAQ (005167138)