Salesforce Presence Integration

Simon Maskell Updated by Simon Maskell

The following article describes how the user availability toggles, normally updated via the Distribution Engine widget, could be controlled by whether a user is logged into Salesforce or not.

There are different ways of trying to detect whether a user is logged into Salesforce, but none of them will be 100% accurate. How reliable it is does depend on the security configuration within your org and the actions of the users.
Presence changes will not be reflected in the DE widget until its refreshed, which by default is every 10 minutes or on page load. It is recommended not to show the DE widget if Salesforce sessions are being used to control presence.

There are two main methods of determining whether a user is logged into Salesforce: login/logout events and session polling. Depending on your configuration it may make sense to handle one or both of these methods.

Login/Logout Events

Salesforce allow for a Flow to be initiated when a user logs into the org. As part of this, logic can be added to automatically toggle that user on within DE. See Create a Login Flow with Flow Builder for more information.

Salesforce can also be configured to publish events when users log out of the org, which can be captured by a Trigger to automatically toggle that user off within DE. See Create Logout Event Triggers for more information.

As per Salesforce's documentation, these events are only published when a user logs out of the Salesforce UI, not when they just close their browser.

Step 1 - Create the flow

  • Go to Setup > Process Automation > Flows
  • Click New Flow
  • Select "Screen Flow"
  • Click Create

Step 2 - Create the user id variable

  • In the Toolbox on the left, click New Resource
    • Resource Type: Variable
    • API Name: LoginFlow_UserId
    • Data Type: Text
    • Available for input: Check

Other input variables can also be created, which will be passed in from from the login event, see Login Flow Examples for more information.

Step 3 - Filter to DE users

To avoid potential overhead, it is worth adding a Decision step to determine whether the user is a DE user, and therefore should have their trigger updated. This could, for example, be based on an attribute on their user record or a permission set. As part of the configuration you'll do later, the login flow will be associated to a profile, so that may be enough, or you may require additional filtering. Therefore, this step will change depending on your specific requirements.

  • Click the Add Element button and select "Decision"
    • Label: Should Toggle User
    • Outcome details Label: Is DE User
    • Condition: <Based on your requirements>
    • Default outcome details Label: Is Not DE User

Step 4 - Toggle user on

This step uses the DE Availability API, see this article for more information.

  • In the "Is DE User" branch, click the Add Element button and select "Action"
  • In the category "Distribution Engine" search for the action "DE Toggle Users"
    • Label: Toggle User On
    • Toggle user online?: {!$GlobalConstant.True}
    • User id: {!LoginFlow_UserId}
  • Click Done

  • You will end up with the following Flow

Step 5 - Save the flow

  • Click Save on the toolbar
    • Flow Label: Toggle DE User On Login
  • Click Save
  • Click Activate on the toolbar
This is an example flow, it is recommended to include fault handling and fully test the flow before activating in production.

Step 6 - Associate the flow with the login event

  • Go to Setup > Identity > Login Flows
  • Click New
    • Type: Flow
    • Name: Toggle DE User On Login
    • Flow: Toggle_DE_User_On_Login
    • User License: Salesforce
    • Profie: <Desired profile>
  • Click Save

Step 7 - Create logout trigger

Standard development practices for writing code in your org should be followed.

  • Use the below code to create a trigger for the logout event
    • Include your own logic to determine whether to run the trigger for the user
trigger LogoutDEEventTrigger on LogoutEventStream (after insert) {
LogoutEventStream event = Trigger.new[0];

/* Logic to determine whether the user is relevant to DE */

List<n2de.DistributionEngineGlobal.ToggleUserDTO> userDtoList = new List<n2de.DistributionEngineGlobal.ToggleUserDTO>();
userDtoList.add(new n2de.DistributionEngineGlobal.ToggleUserDTO(event.UserId, false, 'Logged out of Salesforce'));
n2de.DistributionEngineGlobal.toggleUsers(userDtoList);
}

This step uses the DE Availability API, see this article for more information.

Step 8 - Enable logout event streaming

  • Go to Setup > Events > Event Manager
  • Click on the row menu for "Logout Event" and click Enable Streaming

Session Polling

There is an object within Salesforce called AuthSession that holds session information for users. This object can be used to determine whether a user has an active session within Salesforce. A session can extend beyond when a user has closed their browser, if they did not explicitly log out, and will depend on your org settings for sessions, so that needs to be taken into consideration.

A job can be created to poll this object every so often and toggle users on/off based on whether they have an active session. Below is an example of a queueable job that will continue indefinitely until aborted, running about every 5 minutes. This queries the AuthSession object for application login types and UI session types, but that may need to change based on your specific use case. You also need to make sure that this job runs under a user that can query all records in the AuthSession object.

public with sharing class ToggleDEUserBasedOnSession implements System.Queueable {

public void execute(QueueableContext context) {
// Fetch all DE user ids
Map<Id, Map<Id, Boolean>> teamUserAvailability = n2de.DistributionEngineGlobal.getUserAvailabilityAllTeams();
Set<Id> allDEUserIds = new Set<Id>();
for (Map<Id, Boolean> teamAvailability : teamUserAvailability.values()) {
allDEUserIds.addAll(teamAvailability.keySet());
}

// Collect the UI auth sessions for the users
List<AuthSession> authSessions = [SELECT UsersId, LastModifiedDate, NumSecondsValid FROM AuthSession WHERE UsersId IN :allDEUserIds AND SessionType = 'UI' AND LoginType = 'Application' ORDER BY LastModifiedDate ASC];
Set<Id> usersWithSessions = new Set<Id>();
for (AuthSession authSession : authSessions) {
if (authSession.LastModifiedDate.addSeconds(authSession.NumSecondsValid) > now) {
usersWithSessions.add(authSession.UsersId);
}
}

// Determine whether the users are online
List<n2de.DistributionEngineGlobal.ToggleUserDTO> userDtoList = new List<n2de.DistributionEngineGlobal.ToggleUserDTO>();
for (Id userId : allDEUserIds) {
Boolean active = usersWithSessions.contains(userId);
userDtoList.add(new n2de.DistributionEngineGlobal.ToggleUserDTO(userId, active, active ? null : 'No active session'));
}

// Toggle the users
n2de.DistributionEngineGlobal.toggleUsers(userDtoList);

// Schedule the next job in 5 minutes
System.enqueueJob(new ToggleDEUserBasedOnSession(), 5);
}

/**
* Static method to start the queueable job
*/
public static void startJob() {
System.enqueueJob(new ToggleDEUserBasedOnSession());
}

/**
* Static method to abort any pending or running queueable jobs
*/
public static void abortJob() {
List<AsyncApexJob> jobs = [SELECT Id, Status FROM AsyncApexJob WHERE Status IN ('Holding', 'Queued', 'Prepared', 'Processing') AND ApexClass.Name = :ToggleDEUserWithSession.class.getName()];
if (!jobs.isEmpty()) {
System.abortJob(jobs.get(0).Id);
}
}
}

To start the job running, in anonymous Apex execute the command ToggleDEUserBasedOnSession.startJob(); which will start the queueable job running until it is aborted. If you want to abort the job you can execute ToggleDEUserBasedOnSession.abortJob();. If preferred, the same code could be scheduled to run within a scheduled job.

How did we do?

Omni-Channel Presence Integration

Invalid Email trigger

Contact