RIO Education License Usage Calculation
Table of Contents
Administrators can access an overview of the RIO Education licenses and features that are currently provisioned in a particular Salesforce Org by following the below steps:
- Click on App Switcher
- Search for RIO Education Settings
On this RIO Education Settings page, you will be greeted with a screen that shows you the profiles and permission sets that are currently granting RIO Education licenses, alongside the specific users who are assigned to either one of the Admin, Faculty or Student types.
(Depending on your version of RIO Education, this screen may look slightly different. If you a running a version prior to 3.22, please follow the instructions here to recreate these reports.)

Understanding Licenses in RIO Education
In RIO Education, there are three types of licenses:
- Admin
- Faculty
- Student
Licenses are tracked based on whether users are assigned specific Custom Permissions - these are not the same as standard Permission Sets, but they can be included within them.
The custom permissions used for licensing are:
- REDU_Admin
- REDU_Faculty
- REDU_Student
These custom permissions can be assigned to users in two ways:
- Directly through a user’s Profile
- Through a Permission Set that includes the custom permission
How Licensing Is Counted
An active user will count toward a license if they are assigned one of the above custom permissions, whether it comes from their profile or a permission set.
Examples:
- If a user is assigned a profile and/or permission set that includes REDU_Admin, they use one Admin license.
- If a user is assigned both REDU_Admin and REDU_Faculty, they use one Admin license and one Faculty license.
- A user can consume multiple license types if they have multiple custom permissions.
Key Clarification
While Permission Sets are a way to group access and assign it to users, it is the Custom Permissions (REDU_Admin, REDU_Faculty, REDU_Student) that actually trigger license usage. Think of custom permissions as license flags, and permission sets as containers that might hold those flags.
When Does RIO Calculate the License Usage?
A scheduled batch job, REDU_License_SCHED, runs every Sunday at midnight to calculate license usage. This information is then sent back to RIO Education's license management portal for reporting purposes.
If you do not see the scheduled job in Salesforce Setup > Environments > Jobs > Scheduled Jobs, it can be reinstated by navigating to the RIO Education Settings app page again as an administrator.
This license information is displayed as Feature Parameters under the customer's subscriber information in the LMO.

In the event that the stats need to be refreshed and not wait for the scheduled job, the following execution can be performed via the Developer Console > Debug > Open Execute Anonymous Window > Execute
Prior to v3.22
rio_ed.REDU_License_BATCH batchJob = new rio_ed.REDU_License_BATCH('REDU_Admin');
Database.executeBatch(batchJob, 2000);v3.22 onward (definining License Type is no longer necessary)
rio_ed.REDU_License_BATCH batchJob = new rio_ed.REDU_License_BATCH();
Database.executeBatch(batchJob, 2000);Script For License Count
The following are the queries and scripts we use to identify the relevant license usage. Feel free to adapt and run these in your own Org if you would like more information about your license usage.
Profiles and Permission Sets
//Change the custom permission name here: REDU_Admin, REDU_Faculty, REDU_Student
List<CustomPermission> cpList = [SELECT Id, DeveloperName FROM CustomPermission WHERE DeveloperName = 'REDU_Admin'];
Set<String> permissionSetNames = new Set<String>();
Set<String> profileNames = new Set<String>();
for (SetupEntityAccess sea : [SELECT SetupEntityId, ParentId, Parent.Name, Parent.Profile.Name FROM SetupEntityAccess WHERE SetupEntityType = 'CustomPermission' and SetupEntityId IN: cpList]) {
if (String.isNotBlank(sea.Parent.Profile.Name)) {
profileNames.add(sea.Parent.Profile.Name);
} else {
permissionSetNames.add(sea.Parent.Name);
}
}
System.debug('Profiles :: ' + JSON.serialize(profileNames));
System.debug('Permission Sets :: ' + JSON.serialize(permissionSetNames));
Users Assigned RIO Licenses
//Change the custom permission name here: REDU_Admin, REDU_Faculty, REDU_Student
List<CustomPermission> cpList = [SELECT Id, DeveloperName FROM CustomPermission WHERE DeveloperName = 'REDU_Admin'];
Set<Id> permissionSetIds = new Set<Id>();
for (SetupEntityAccess sea : [SELECT SetupEntityId, ParentId FROM SetupEntityAccess WHERE SetupEntityType = 'CustomPermission' and SetupEntityId IN: cpList]) {
permissionSetIds.add(sea.ParentId);
}
Set<Id> userIds = new Set<Id>();
for (PermissionSetAssignment psa : [SELECT AssigneeId
FROM PermissionSetAssignment
WHERE PermissionSetId IN :permissionSetIds
AND Assignee.IsActive = TRUE
]) {
userIds.add(psa.AssigneeId);
}
Integer usersCount = userIds.size();
Permission Set Users Only
//Change the custom permission name here: REDU_Admin, REDU_Faculty, REDU_Student
List<CustomPermission> cpList = [SELECT Id, DeveloperName FROM CustomPermission WHERE DeveloperName = 'REDU_Admin'];
Set<Id> permissionSetIds = new Set<Id>();
for (SetupEntityAccess sea : [SELECT SetupEntityId, ParentId, Parent.ProfileId FROM SetupEntityAccess WHERE SetupEntityType = 'CustomPermission' and SetupEntityId IN: cpList]) {
if (String.isBlank(sea.Parent.ProfileId)){
permissionSetIds.add(sea.ParentId);
}
}
Set<Id> userIds = new Set<Id>();
for (PermissionSetAssignment psa : [SELECT AssigneeId
FROM PermissionSetAssignment
WHERE PermissionSetId IN :permissionSetIds
AND Assignee.IsActive = TRUE
]) {
userIds.add(psa.AssigneeId);
}
Integer usersCount = userIds.size();