You sure live up to your Community Rockstar title, Lawrence. Thank you!
Original Message:
Sent: 03-14-2025 18:35
From: Lawrence Drayton
Subject: Chat Utilization and Adherence
Hey @Amanda Frankeberger,
Sure thing!
This workflow automates updating agent presence statuses in Genesys Cloud to a 'Pre-Break' state based on their upcoming scheduled breaks. It's implemented using an internal platform called 'Integrate' (Based on N8N), leveraging HTTP calls and custom JavaScript logic.
Workflow Steps
1. Scheduled Trigger
- Purpose:
- Triggers the workflow at predefined intervals using a cron schedule.
2. Fetch Active Users
- Genesys Cloud API call:
- Authentication: OAuth2 credentials.
- Retrieves active user details: presence, routing status, and conversations.
3. Extract User Data
- Code logic:
- Processes user information, extracting relevant details:
- User ID
- User Name
- System Presence
- Routing Status
- Active Conversations Count
- Presence Definition (mapped to specific presence ID)
- Logic to calculate active conversations/user information:
javascript
// Get the users from the previous node's response
const users = items[0].json.entities;
// Function to compute active conversations
function getActiveConversations(conversationSummary) {
let totalActiveConversations = 0;
if (!conversationSummary) {
return 0;
}
for (const mediaType in conversationSummary) {
const mediaSummary = conversationSummary[mediaType];
if (mediaSummary.contactCenter) {
totalActiveConversations += mediaSummary.contactCenter.active || 0;
totalActiveConversations += mediaSummary.contactCenter.acw || 0;
}
if (mediaSummary.enterprise) {
totalActiveConversations += mediaSummary.enterprise.active || 0;
totalActiveConversations += mediaSummary.enterprise.acw || 0;
}
}
return totalActiveConversations;
}
// Extract user data
const userData = users.map(user => {
// Get the presenceDefinition id
const presenceId = user.presence?.presenceDefinition?.id || null;
// Map the presenceDefinition id to desired value
let presenceDefinition = presenceId;
if (presenceId === 'e3bedde6-f747-4dbb-bb76-45684b9180b6') {
presenceDefinition = 'preBreak';
}
return {
id: user.id,
name: user.name,
systemPresence: user.presence?.presenceDefinition?.systemPresence || null,
routingStatus: user.routingStatus?.status || null,
activeConversations: getActiveConversations(user.conversationSummary),
presenceDefinition: presenceDefinition
};
});
// Extract user IDs
const userIds = userData.map(user => user.id);
// Return the userData array and userIds
return [
{
json: {
userIds,
userData
}
}
];
3. Calculate Dates
- Purpose:
- Generates the current day's start and end times based on Sydney's local timezone.
- Converts these times to UTC ISO format for Genesys API compatibility.
- Key Functions:
javascript
const { DateTime } = require('luxon');
// Get current date and time in Sydney timezone
const nowSydney = DateTime.now().setZone('Australia/Sydney');
// Start of the day in Sydney time
const startSydney = nowSydney.startOf('day');
// End of the day in Sydney time
const endSydney = nowSydney.endOf('day');
// Convert to UTC ISO strings
const startDateUTC = startSydney.toUTC().toISO();
const endDateUTC = endSydney.toUTC().toISO();
// Return startDate and endDate
return [
{
json: {
startDate: startDateUTC,
endDate: endDateUTC
}
}
];
4. Retrieve Agent Schedules
- Genesys Cloud API call:
POST https://api.mypurecloud.com.au/api/v2/workforcemanagement/managementunits/{managementUnitId}/agentschedules/search
- Payload:
json
{
"startDate": "<UTC start date>",
"endDate": "<UTC end date>",
"userIds": [List of User IDs]
}
- Retrieves agent schedules within the defined Sydney time range.
5. Determine Agents to Update
- Logic:
- Checks agent shifts occurring within the next 10 minutes.
- Identifies agents who are currently "On Queue" (systemPresence = 'On Queue', routingStatus either 'IDLE' or 'INTERACTING').
- Identifies agents scheduled for specific activities (activityCodeId '1' or '2') that warrant a pre-break status update.
- Code snippet for filtering agents:
javascript
// Get the agent schedules from the 'Get Agent Schedules' node
const agentSchedules = $node['Get Agent Schedules'].json.result.agentSchedules;
// Get the user data from the 'Get User IDs' node
const userData = $node['Get User IDs'].json.userData;
// Ensure that userData is defined and is an array
if (!Array.isArray(userData)) {
throw new Error('userData is not an array. Check the output of the "Get User IDs" node.');
}
// Initialize an array to hold agents who need presence updates
let agentsToUpdate = [];
// Get current time in UTC
const nowUTC = new Date();
// Get time 15 minutes from now
const nowPlus15 = new Date(nowUTC.getTime() + 10 * 60 * 1000);
// Loop over each agent's schedule
for (let agentSchedule of agentSchedules) {
const userId = agentSchedule.user.id;
// Find the user's data
const user = userData.find(u => u.id === userId);
if (!user) {
continue; // User data not found
}
const systemPresence = user.systemPresence;
const routingStatus = user.routingStatus;
// Only proceed if the agent is 'On Queue'
// Assuming 'On Queue' means systemPresence is 'On Queue' and routingStatus is 'IDLE' or 'INTERACTING'
if (systemPresence !== 'On Queue' || (routingStatus !== 'IDLE' && routingStatus !== 'INTERACTING')) {
continue; // Agent is not 'On Queue'
}
// Get the agent's shifts
const shifts = agentSchedule.shifts;
if (!shifts) {
continue; // No shifts found for this agent
}
// Loop over each shift
for (let shift of shifts) {
// Get the activities within the shift
const activities = shift.activities;
if (!activities) {
continue; // No activities found in this shift
}
// Loop over each activity
for (let activity of activities) {
const activityCodeId = activity.activityCodeId;
// Check if activityCodeId is '1' or '2'
if (activityCodeId === '1' || activityCodeId === '2') {
// Get the activity start time
const activityStart = new Date(activity.startDate);
// Check if activity start time is within the next 15 minutes
if (activityStart >= nowUTC && activityStart <= nowPlus15) {
// Agent needs presence update
agentsToUpdate.push({
id: userId,
presenceDefinition: {
id: 'e3bedde6-f747-4dbb-bb76-45684b9180b6' // Replace with your 'pre break' presence ID
},
source: 'PURECLOUD'
});
// Break the loop since we found a matching activity
break;
}
}
}
}
}
// Return the agentsToUpdate array as a property of 'json'
return [
{
json: {
agentsToUpdate: agentsToUpdate
}
}
];
6. Bulk Update Agent Presence
- Genesys Cloud API call:
- Request payload:
json
{{ JSON.stringify($json.agentsToUpdate) }}
- Updates all selected agents' presence to "Pre Break".
7. Conditional Execution (Switch Node)
- Checks if the `agentsToUpdate` array is not empty before executing the update to avoid unnecessary API calls.
Credentials
- OAuth2 credentials are required and configured in n8n for authentication with the Genesys Cloud APIs.
You'll need to create your activity code "pre break" Or whatever you want to call it, and use that in the presence definition when doing the bulk update.
------------------------------
Lawrence Drayton
Original Message:
Sent: 03-14-2025 16:29
From: Amanda Frankeberger
Subject: Chat Utilization and Adherence
Hi, @Lawrence Drayton! Thank you for your replies. Very helpful information you're sharing.
Are you able to expand more on how you've set up this system that checks users? This is something we would like to explore with our setup.
------------------------------
Amanda Frankeberger
Original Message:
Sent: 03-11-2025 18:06
From: Lawrence Drayton
Subject: Chat Utilization and Adherence
Hey @Gina Palmer
Unfortunately not a Genesys out-of-the-box option, I have built a system that checks users, then gets all their IDs, calculates the correct date, pulls the agent schedules and then runs a bit of code to see at that time if there are any agents on queue that are <= 10 min away from a break, and then updates the agents presence.
Happy to share what I have done around this - you would just need a dev to slap together the components and host it somewhere it can run :)
------------------------------
Lawrence Drayton
Original Message:
Sent: 03-11-2025 12:29
From: Gina Palmer
Subject: Chat Utilization and Adherence
Hi @Lawrence Drayton,
How did you set it up so that the agent is automatically put into the pre-break code? Is this a Genesys radio-button thing that I just missed?
------------------------------
Gina Palmer
Manager, Workforce Management
Papa, Inc.
Original Message:
Sent: 03-09-2025 20:11
From: Lawrence Drayton
Subject: Chat Utilization and Adherence
Hey Mandy,
This is a super interesting one - we (and I'm sure many others) have the same issue.
What we have done is;
- We have a 10min "pre break" activity code (base code is busy) that an agent has on their roster before each break
- We have a system that automatically puts the agent into the "pre break" code - therefore stopping them from getting any interactions from that time and still ensuring all AHT metrics are correct
- Agent then puts themselves into break/meal when their last chat finishes.
It's not perfect, but it's better than the other way. You still get some exceptions if they finish quickly and then go on break early (and then finish early based on their actual break times)
Just an idea, I don't think there is another way that's built into Gen
------------------------------
Lawrence Drayton
Original Message:
Sent: 03-05-2025 13:26
From: Amanda Frankeberger
Subject: Chat Utilization and Adherence
When an agent goes to lunch or break and is taking two chats concurrently, the only way to stop additional chats from coming in is to go "off queue" or put themselves in "available." On busy days, the agents are struggling with maintaining their adherence because of going off queue or going into available while waiting for the other interaction to wrap up.
My question: Is there a best practice or solution for the agents needing to go on break and not get another chat? Would it be best to have the agents stay in ACW for their first interaction while their second interaction is concluding? Any assistance would be greatly appreciated!
#Monitoring/Adherence
------------------------------
Amanda "Mandy" Frankeberger
------------------------------