Tag Archive for: Reporting

Report on Abandoned Conversations with Salesforce Channels

One important piece of information for Service centers is related to abandoned conversations – that is how many people that really wanted to talk to you, gave up while they were waiting for a rep to talk to them. This primarily applies to real-time communication channels like web chat and voice calls, where a customer may abandon the interaction while waiting in queue before being connected to a service rep. This could also include after being handed off from a Bot or AI Agent conversation, to connect with a human.

Why is Abandoned Reporting Important?

This is a hugely important metric, but you probably know that already, that’s why you’re here. But just as a reminder, here are a few key reasons why:

  • Understanding Customer Frustration: High abandonment rates can indicate long wait times or other issues causing customer frustration.
  • Optimizing Resource Allocation: Tracking abandonments helps determine staffing levels and potential bottlenecks in customer service.
  • Improving Customer Experience: Identifying reasons for abandonments leads to process improvements and better overall customer experience.

Great – we know it’s a gap, we know it’s important, how do we solve it?

How to report on Abandoned

First – we are planning an out of the box solution for this (on Enhanced Omni only) where we will write a new ‘AgentWork’ record, with the ‘Status’ of ‘Abandoned’ – but ahead of that change coming in the Winter ‘26 release (October 2025), here are some ways to report on it.

I will go through a simple option, followed by a more complex one the captures more scenarios, but is a lot more difficult to implement and track. The scope of this is to solve it for Enhanced Chat (formally known as Messaging for In-app and Web) and Voice calls.

Step 1 – Add new fields to the objects

Both options involve adding these 3 fields to both the ‘MessagingSession’ and ‘VoiceCall’ records:

  1. Num Times queued (Number) – default 0
  2. Num Agent accepts (Number) – default 0
  3. Was abandoned (Formula (Checkbox)). This formula compares the two values above, plus that the conversation was ended by the end customer/visitor, as opposed to an agent or the application:
    1. For MessagingSession:
      ISPICKVAL(EndedByType, "End User") && ( Num_Times_queued__c > Num_agent_accepts__c)
    2. For VoiceCall:
      DisconnectReason = "CUSTOMER_DISCONNECT" && ( Num_Times_queued__c > Num_Agent_accepts__c)

Step 2 – Update on each accept

Now we need to increment the two counters in the appropriate places – for the number of accepts that is relatively straightforward:

  1. Create a Record Triggered Flow on ‘AgentWork’, and configure the start conditions in this way:
    1. Trigger is ‘A record is created or updated’
    2. Trigger condition for ‘Status’ equals ‘Opened’ and ‘Bot ID’ is Null equals ‘true’ (ignore any time the bot accepts work)
    3. Ensure you select ‘Only when a record is updated to meet the condition requirements’
  2. Add a decision node to check the type of work that was accepted. That decision node should check the ‘Starts With’ of the ‘WorkItemId’ matches the appropriate prefix for the objects we care about:
    1. MessagingSession: 0Mw
    2. VoiceCall: 0LQ
  3. Within each outcome, you’ll add 3 elements
    1. Get Records – load the appropriate record
    2. Assignment – ‘Add’ 1 to the ‘Num agent accepts’ field
    3. Update Records – save the updated value

Step 3 – Update on each routing request

Now we get to the trickier part – updating the record to count each time a routing request was made for the record. For efficiency and ensuring that the work gets delivered, we prevent a lot of automation on the ‘Pending Service Routing’ object, as any errors could cause systems to get out of sync, calls dropped or work not actioned as expected. However, that creates some issues when trying to catch a new routing request of a record – so I have 1 simple, and 1 more complex solution for this.

Simple solution

This involves simply updating the record each time you attempt to route it to a human service rep (don’t do this when routing to a bot or Agentforce Agent) – in the most basic case, this is incrementing the counter within the Omni Flow that you route the object in, similar to the screen shot on the right (this one assumes we’ve previously loaded the Voice Call record in the Flow). 

Assuming you know all the places that you are routing Voice Calls and Messaging Sessions, and when you transfer between users you are using an Omni Flow, then this should lead to an accurate count of routing requests, and therefore abandonments.

More complex solution

A more complex solution is to use ‘Change Data Capture’. You can enable this in Setup, and add the ‘Pending Service Routing’ object to the ‘Selected Entities’ – you can only enable 5 entitles without purchasing an add-on for more. This will then allow you access to the ‘PendingServiceRoutingChangeEvent’, which you can add an Apex Trigger to – yep we’re going to need to write Apex for this one, hence the added complexity.

trigger PSR_CDC_Trigger on PendingServiceRoutingChangeEvent (after insert) {
    // Iterate through each event message.
    for (PendingServiceRoutingChangeEvent event : Trigger.New) {
    // Get some event header fields
        EventBus.ChangeEventHeader header = event.ChangeEventHeader;
        List<String> recordIds = event.ChangeEventHeader.getRecordIds();
        System.debug('Received change event for ' + header.entityName + ' for ' + header.recordIds + ' of type ' + header.changeType + ' operation.');
        if (header.changetype == 'CREATE')
        {
            // New PSR record created - check the object type for the work item
            System.debug('event.WorkItemId: ' + event.WorkItemId);            
            // Ensure we aren't routing to a Bot/AI Agent
            if (event.BotId == null) {
            	for (String recordId : recordIds) {
                    if (event.WorkItemId.getSobjectType() == Schema.VoiceCall.SObjectType)
                    {
                        // VoiceCall - load record and increment num times queued.
                        System.debug('PSR for a Voice Call created.');
                        VoiceCall call = [SELECT Id, Num_Times_queued__c from VoiceCall where Id = :event.WorkItemId LIMIT 1];
                        call.Num_Times_queued__c++;
                        update call;
                    }
                    else if (event.WorkItemId.getSobjectType() == Schema.MessagingSession.SObjectType)
                    {
                        // MessagingSession - load record and increment num times queued.
                        System.debug('PSR for a Messaging Session created.');
                        MessagingSession ms = [SELECT Id, Num_Times_queued__c from MessagingSession where Id = :event.WorkItemId LIMIT 1];
                        ms.Num_Times_queued__c++;
                        update ms;
                    }
                }
            }
        }
    }
}

This is an example of the Apex Trigger that would increment the value – you can copy and paste this into the ‘Developer Console’ after going to ‘File’ → ‘New’ → ‘Apex Trigger’. Name it ‘PSR_CDC_Trigger’, and select the ‘PendingServiceRoutingChangeEvent’ object.

That should capture all creations of PSR records, and increment the routing requests as appropriate. 

Step 4 – Create the report

To keep this post a reasonable length, I’m not going to go into details on how to create reports, but it should be pretty straightforward to create a report for each object to report on this, and there is lots of helpful content out there. Follow the usual reporting steps to create a ‘Report Type’, ensuring it has the ‘Was Abandoned’ field included, and then create a report using the report type. You will need to create two separate reports, 1 per object – but I suggest dropping them both onto a single dashboard. You likely also want an abandonment rate – you can use a summary level formula to calculate this in standard reporting for a time period – below is an example of how you might do this, if you grouped by date:

Limitations

There will be a few limitations to this solution, particularly with regards to the Voice channel:

  • The ‘Disconnected Reason’ needs to come from the telephony system. With the ‘AWS Connect’ integration, this can take a while after the call disconnects before it is populated. It may also be populated differently (or not at all) by other telephony providers.
  • To use the Omni Flow solution, you will need to be calling Omni-Flow from your telephony provider.
  • Transfers may need some thought, and you’ll need to decide if you want to count conversations that drop when being transferred between teams or service reps as abandoned or not.
  • Only unauthenticated Messaging Sessions can be ended/abandoned, so may not totally cover all abandoned scenarios related to web chats.
  • There will be some edge cases, error scenarios etc. that may not be captured by this setup

Conclusion

While out of the box Salesforce does not track abandoned yet, this custom solution can fill the gap. By implementing appropriate methods and metrics, organizations can effectively measure and analyze abandonments in both Messaging and Voice channels, leading to improved customer service and operational efficiency. Let me know how you get on, and if there are any issues or remaining gaps this misses.

Reporting on Service Cloud channels

Reporting on Salesforce Service Cloud can sometimes feel like navigating a labyrinth. While the platform offers immense flexibility, it often leaves users yearning for more guidance. This blog aims to demystify the process, providing you with the insights and tools needed to harness the full power of Salesforce Service Cloud reporting.

Simplifying the Complexity

Historically, we’ve made it challenging for our customers by offering a plethora of reporting options without clear direction, or even making them aware of the options out there. Many customers will start with a single channel and build reports on that single object with some success. However, what happens when you add more channels and want consistent reporting across them all? The flexibility is there in the application, but the guidance on how to do it has been lacking. This blog, and future ones coming, are intended to help bridge that gap, making it easier for you to create meaningful reports and understand the data at your fingertips.

Harnessing the Power of Omni-Channel

One of the most powerful features of Salesforce Service Cloud is Omni-Channel. This tool is not only a powerhouse for work classification and routing, but also allows you to report consistently across all channels using a unified object model.

There are 2 objects that are critical to this consistent reporting:
1. AgentWork Object: This object is your go-to for tracking all the work assigned to agents and their performance. By analyzing the AgentWork object, you can gain insights into how efficiently your agents are handling their tasks, and the volumes you are handling.

This is where you find key performance indicators like average handle time, wait time (speed to answer) and wrap up time (after conversation time). For a work focused view, remember to group by the WorkItemId to find all the work performed for a given case or conversation, or alternatively for a service rep focused view, group by the UserId to find all the important metrics for your team.

For those with more advanced routing configurations, this object joins to the AgentWorkSkill object, where you can find if additional skills were dropped or not, and the relevant performance per skill.

2. UserServicePresence Object: To monitor user presence and capacity throughout each day, the UserServicePresence object is invaluable. It helps you keep track of when agents were available, busy, or offline, providing a clear picture of your team’s capacity and workload over time.

This contains important information related to how busy your team was, and how they are spending their time while logged in. You’ll want to group by user, presence status and date, to identify how long they are in each status each day, as well as analyze their idle time and average capacity, to see where you are potentially over or under staffed.

Recent Reporting Enhancements

We’ve recently enhanced our reporting capabilities to make it even easier to join Omni-Channel data with channel-specific data in Custom Report Types. For example, you can now join the AgentWork object with Case, MessagingSession, and VoiceCall objects (amongst others). This capability allows for a more comprehensive view of your service operations, enabling you to make data-driven decisions with greater confidence, and create consistent reports across channels.

This allows more in-depth analysis per channel, for instance determining which Case Types have a higher average handle time than others, or which customers you are spending the most time supporting. You will need to create separate reports for each object you want to join, but you will then be able to put them all on the same dashboard with common filters, allowing you to identify trends around volume or performance.

Existing Reporting Gaps

While we’ve made some strides in improving our reporting capabilities, we acknowledge that there are still some gaps that you can’t report accurately on (or at all) without customization. Two of the most common gaps we hear about are related to abandoned and transferred work – stay tuned for future blogs in this series, where we’ll provide tips and tricks to help you navigate these gaps until we can address them natively in the product.

In the Summer ’25 release we are going to be adding some reports and dashboards that you can install from the Setup screens, with the intention of giving you some basic reporting right away, with the flexibility to customize and enhance to your hearts desire – we’d love you feedback on those once they are available.

Future Topics

This blog is largely an introduction and some high level guidance, with some extra posts planned in the coming weeks, including more in depth guides on building these reports, as well as work arounds to address the known gaps. I’ll also call attention to these two new help docs related to reporting on Messaging:

Future blog topics include:

  • Step by step instructions on how to report on the AgentWork object
    • Extra: How to report on Skills
  • Step by step instructions on how to report on the UserServicePresence object
    • Extra: Utilization & Concurrency
  • How to report on Transfer
  • How to report on Abandoned

Let me know if there is something else I’m missing that you’re wanting to learn more about – these aren’t in a particular order, so those that are most desired I can start with.