Routing for Salesforce Chat


Traditionally with Chat, there was a 1:1 relationship between the Chat Button and a Queue, so it was never easy to build dynamic routing logic in. If we wanted some chats to go to the sales team, and others to service, or if we wanted to prioritize VIP customers over others, we had to either use a Chatbot as a proxy, or code it into the pre-chat form somehow.

As of Winter ’22 though, it’s so much easier, with the launch of Omni Flows for Chat, and this post will help show us how to do that.

Two notes before we start, Omni Flow routing isn’t supported when using an Einstein Bot, though it is on the roadmap.

Also, make sure that you’ve read Build your first Omni Flow

Setup guide

We start off by building an Omni Flow. There’s a pre-built template for Chat or we can make it from scratch. The good thing about the template is that it gives an example of loading pre-chat data and using it to route based on that data.

Pre-chat data

When an Omni Flow is configured on a chat button, any customer inputs collected in the Embedded Service pre-chat form will be passed in automatically. If you’re not using the template, make sure to define an input variable of type Conversation Context Entry, with the ‘Allow multiple values’ checkbox selected.

Within the flow, you can loop over that collection, and check the Title (pre-chat field name) and Value (customer input) of each entry. This can then be used for whatever you need in the flow, linking the Contact, Creating a Lead or Case, or informing a Routing decision.

Decide where to Route the Chat

Once we’ve got the pre-chat data and loaded the Contact or other related information, we need to decide where to Route it.

The Route Work action will support us sending to a Queue, to a set of Skill Requirements, or Direct to a named Agent.

We can also set the Priority and Size of the Chat by changing the Routing Config or moving into a Queue with different values (allowing for us to escalate VIP customers to the front of the queue), and define what records will open when the agent accepts the chat via the Screen Pop action.

The below screenshot shows a simple example of a routing decision based on the subject in pre-chat, but we can ultimately define any logic that we want to (which is the great power of Flow, combined with all of the data about the Chat).

Add routing requirements to the Chat Button

Once we’ve built the Omni Flow, the last step is to map it to the Chat Button.
Now, if selecting the Omni-Channel routing type, you have the option to either provide a Queue (for simple scenarios) or to define an Omni Flow (for dynamic routing).

Update it by checking the box and selecting the Omni Flow that we just created, then we’re good to go. All new chats to this button will use that Flow to decide where to go!

Note: The go-forward routing type is Omni-Channel and we should use this for all newly configured Chat Buttons.

Extra notes

Heads up, when configuring the Flow from one of the templates, the Route Work actions are pointed to placeholder Channels, Queues, and Routing Configurations, and so you’ll need to swap these out for your own routing requirements before the Flow will work.

Using Flow To Enhance Salesforce Knowledge

Traditional Knowledge is managed using page layouts and records. Let’s look at how a flow-based approach allows your Knowledge implementation to tap into new capabilities. We’ll also see where the current Flow infrastructure is limited relative to today’s Knowledge experience.

Below is an example of a new Knowledge solution that uses Flow and NBA, placed immediately above the standard out-of-the-box Knowledge component:

By delivering Knowledge via this new approach, we gain some new features. Specifically, we’ll demonstrate how you can do the following things that are not possible with the OOTB Knowledge solution:

  • Accurate View Counts Filtered By Time Slice (“Last 30 days”)
  • Conditional Field Visibility (Only show this text block if that check box is checked)
  • Hide Required Fields (Suppress fields that are required by the Knowledge record, such as urlName, so they don’t clutter the screen

Here’s a video demonstrating these features:

Creating a New Article

Let’s start by creating a new article. When the user clicks the New Article button, they receive a choice of templates:

Selecting one runs a screen flow that presents a form for creating the article:

Importantly, this is actually a screen from a screen flow instead of the traditional record edit form for a Knowledge record. The end result (create a new Knowledge record) will be exactly the same, but because we’re tapping into the more sophisticated Flow screen technology, we get some immediate advantages:

Conditional Visibility

Some fields only appear if other fields have particular value. Here the Impact Reason field only shows up if the Impact Rating is above 7:

Additionally, note that the undesirable urlName field is absent. Here you can see that in a typical Knowledge layout, you can’t remove urlName because it’s required:

This field is auto-generated and many customers don’t want their article creators to have to think about it.

When we fill out the form and click Next, a new Knowledge record is created.

Searching for a Knowledge Record

Let’s first take a look at how Knowledge NG works. As can be seen here, we’re interacting with a flow called Knowledge NG and specifying a ‘strategyName’:

The Knowledge NG flow consists of a single screen with a single LWC:

The ‘Display Knowledge NBA Recommendations’ component tells us that we’re actually using the NBA framework to query for Knowledge. When a search is initiated in the component….

… the component runs a Recommendation Strategy Flow, using the strategyName passed in by the page builder. That flow has an invocable action that calls the existing Knowledge search API. Here’s what this flow looks like:

As is the case with all Recommendation Strategy Flows, this one queries a ‘source of insight’ and converts the results to the standard recommendation object format.

Viewing a Knowledge Record

When the View button is clicked on a Knowledge record, the solution launches the same flow that was used to create the record. Here’s what it looks like:

Here we see some of the limitations of the current Flow-based approach. Flow doesn’t distinguish between Edit mode and Read mode, so all of the fields are shown in edit mode. The rich text is supported here by an installable extension, but there’s no way to increase the visible lines of that field, or show it in edit mode. These elements are on Flow’s roadmap, but not expected in 2022.

Reporting on Knowledge Activity

Since the Get Knowledge action shown above is basically just calling the existing Knowledge api endpoint, why go through the trouble of running it through the NBA framework? One reason is that we inherit NBA’s relatively strong reporting infrastructure. Each time a user clicks the View button on a search result in our Knowledge NG solution, it’s recorded as a ‘recommendation accept’. As a result, we can create powerful reports that are not currently available to Lightning Knowledge users. This report shows the number of times articles were viewed in a recent 1 week period:


This project can not currently be package, but can be deployed via sfdx. It’s available here.

First, make sure your org has the prerequisite files installed:

This package requires the following pre-requisite packages, installed in order:

  1. Flow Actions Base Pack and the Flow Screen Components Base Pack. Install them here.
  2. Navigate Everywhere. Install it here.
  3. ExecuteNBAStrategy. Install it here. (never was packaged. currently seems to need Spring 22, so has to wait until sandboxes get updated)
  4. Open URL Install it here
  5. GenerateFlowLink Install it here

From Munawir: Access Dozens of String functions with String Wizard

String Wizard is an Invocable Action that can be used in Flow. It provides no-code access to all of the string functions that Apex developers have access to use.

It enables you to do string processing that was previously only accessible in apex and not in the Salesforce formula.

Main Features

1. Lets you process your String (or text) with selected method

2. Minimizes the need for complex Flow formulas

Configuration Part 1: Select the Method

This picklist lists the available string functions.

When you select a string function, the custom property editor displays its description and provides a link to official documentation.

The admin is also shown the anticipated outputs.

Configuration Part 2: Configure the Inputs

Based on the method you select, appropriate inputs are shown, taking advantage of the dynamic capabilities of custom property editors. In the example below, the method substringBetween has been selected. This method lets you provide three strings and searches the first string to return everything between the second string and the third string. Here’s what it looks like in the property editor of StringWizard:

To check what types of input allowed, you can also use popup help text.

There, you can also check whether the field is required.


To accommodate the many different string functions, the StringWizard makes 6 different types of output available:

  1. String Result : Text Variable
  2. Integer Result : Number Variable
  3. Boolean Result : Boolean Variable
  4. String List Result : Collection of Text Variable
  5. Integer List Result : Collection of Number Variable

Make sure you map downstream inputs to the correct output. If you’re having difficulty, use Debug mode to see where the output is showing up.

Sample Case


  1. Method not Selected

2. Mandatory Input not Filled

3. Wrong data type mapping in the inputs



Your org must first have the ActionBasePack and ScreenComponentsBasePack.

Version 1.0 1-28

Install Production

Install Sandbox

View Source

Source Code

Change Log

InvocableStringWizard 1.0 : Initial Release

Developer Note

All of these are combinations between Invocable Method in Apex and CPE. The invocable method itself is just a collection of small methods that will be invoked based on the method input.

Input variables in Invocable Method (without CPE config):
1. Method (String, mandatory) : Apex String method available in Apex
2. Main String (String, optional) : available whenever the method requires
3. Integer 01 (Integer, optional) : available whenever the method requires
4. Integer 02 (Integer, optional) : available whenever the method requires
5. String 01 (String, optional) : available whenever the method requires
6. String 02 (String, optional) : available whenever the method requires
7. Integer List (List, optional) : available whenever the method requires
8. String List (List, optional) : available whenever the method requires

Output variables in invocable method :
1. Boolean Result
2. Integer List Result
3. Integer Result
4. String Result
5. String List Result

The CPE in this invocable method stored the mapping for the list of methods available, what should be shown to the flow developer, and some validations. Mapping stored inside invocableStringWizardEditorMapping.js and that includes method, description, output, and fields input configuration (to show or not, mandatory or not, what label to show, what help text to show). And utilizing CPE flow combobox to let flow developers be able to see the list of available variables.

List of Mapping from Invocable Method to CPE :

Preview: Powerful Approvals Orchestrations from Forcelution Apps

You can build powerful approvals solution on Orchestrator, but if you want a polished out-of-the-box solution, you’ll want to consider this upcoming Approval Orchestrator Add-On from Forecelution Apps. They already provide a powerful extension to Legacy Approval Processes and have set out to provide a solution that makes it easier to create approvals in Orchestrator.

The main goal is to provide the ease of use of the dedicated configuration experience that Legacy Approval Processes are used to while enabling the high degree of customization that Orchestrator provides. Check out this preview:

As you can see here, they provide dedicated UI that makes it easy to define Approval Processes without going into Flow Builder:

Their solution auto-generates the appropriate parts of the underlying orchestration. At that point, it’s possible to open up the individual steps and customize them.

Learn more about the new Approvals Orchestrator here.

Learn more about their existing add-on for Legacy Approval Processes here, and keep your eyes open for update posts here at

Routing for Service Cloud Voice with Omni Flow


In Spring 22 there’s a massive leap forward in making the setup for Routing both easier and more powerful with the GA of Omni Flows for Service Cloud Voice (for Amazon Connect).

In the past, we needed to configure all of the Routing Requirements inside an Amazon Contact Flow. While an incredibly powerful tool, this comes with a few challenges that are resolved by moving the Routing Setup inside of Salesforce.

Some key benefits:

  1. Configure routing rules for ALL channels in one place, inside Salesforce
  2. Easily leverage Salesforce data and shared business rules in Routing requirements for Voice and other channels
  3. Share all Voice Queue data to Omni Supervisor, and in general for Reports inside Salesforce

This Blog post is to get you a quick start in trying out, but make sure that you’ve read Build your first Omni Flow before going any further.

Setup guide

For more information on how this works under the covers, see Service Cloud Voice Routing – Technical deep dive. There’s a video version of this at the bottom of the post as well.

We start off by building an Omni Flow. There’s a pre-built template for Voice or we can make it from scratch. The good thing about the template is that it gives a simple but great example right from the start of the power that we get, where we can easily look up the Contact, and use data in Salesforce to drive the Routing decision.

Note: As inputs to the Flow, you should get in both the Voice Call record (with data on it like the customer phone number) and any custom IVR variables that you choose to pass in from Amazon.

Create the Queues inside Salesforce and Amazon

The key to making this work is mapping of the Queues. To do this, we create the queues in both systems (stay tuned for an upcoming release where we’ll be automating the Amazon part!).
There’s a simple 3-step process to do this.

Step 1: Create the queues in Salesforce
Create the queue the same way that you would any Omni Channel queue, but with a few key and critical notes to make sure:

  1. Voice Call is the only object in the Queue
  2. The Routing Configuration is marked as External Routing in the Routing Model field

Optional: If you want to report on it or see in Omni Supervisor, you should add users to the Queue. Note that currently this data isn’t used, as membership is defined in Amazon (step 2). Also note that Amazon doesn’t support adding individuals to queues, only groups (via Routing Profiles) so I’d recommend managing the membership via Public Groups to keep it easy.

Step 2: Create the queues in Amazon

As above, log into the Amazon Connect management console and configure the same queues.
Note that these queues are the master source for queue membership.

Step 3: Map the Queues in Salesforce

Inside Setup→Amazon Contact Centers, select your contact center and scroll down to see a few new sections. This first of these, Queue Mapping, allows you to add a new entry for each Queue.

Mapping the Omni Flow to the Phone Number

The last step to do is to define the Routing requirements for the Phone number.

Inside Setup→Amazon Contact Centers, for your CC, you can now add each Phone number as a Channel (exactly like how we setup SMS phone numbers in Messaging). Within that, we’re offered the option to either route all queues to a specific queue (for simple use-cases) or to define our Omni Flow created above. And that’s it! No need to configure anything more in Amazon, the system will automatically take care of it for us.

[Upgrade notes] for Voice Orgs created before Spring ’22 or without Omni Flows

If your Org was created prior to Spring ‘22, or didn’t have these new features enabled, then it’s likely that the routing rules are defined inside an AWS Contact Flow and you’ll need to make some small changes to get it working. Don’t fear though, we’ve made it really easy to do.

Just go into the Contact Flow, remove any existing routing logic (Transfer to Queue nodes), drag on the Subflow node, and point it to the new “Sample SCV Inbound Subflow”. And that’s it, no need to do anything else. We’ll cover in other posts how to pass in IVR data, but for now you should be good to go, Salesforce will use the details from the setup screens above to drive everything else.

Video walkthrough

A video guide of setting it up in an org.

UnofficialSF has a new Service Cloud Channels Section has added a new section devoted to Service Cloud channel functionality, which is increasingly driven by flow-based services.

Check it out here. If you know of a good post or page on the topic, don’t hesitate to let us know via the form on the home page.

Build your first Omni Flow

So, you’re ready to build your first Omni Flow? Here’s a quick blog post to walk you through some of the basics. We’ll set up routing for a Case, but the fundamentals here will be true for other channels like Voice, Chat, SMS, Leads, Custom objects, or whatever you want to route.

In your Omni Flow, you’ll see we’ve exposed all of the Omni inputs as Actions on the left hand pallet. Now you’ll have complete flexibility to use any logic you like to determine what those inputs to the routing engine are, Queue/Skills/Agent, Priority, Size, you name it. Plus also, because it’s a flow, you can encapsulate all of your other business logic for the channel in here as well, like Creating a Case or linking the Contact.

You’ll also see some exciting new features that are only available in Omni Flow, like routing Direct to an Agent, or defining Screen Pop rules.

Either follow the steps below, or watch the video guide at the bottom of the post. Either way, you should be up and running in less than 10 minutes!

Create the Flow

Let’s start with the basics. There’s now a dedicated Flow type of Omni Flow to help you get started. (though some of the actions we’re about to see can be used in other Flows like autolaunched, record-changed, or screen flows).

Go to Setup→Flows, hit new Flow, then in All+Templates section create a new/blank Omni-Channel Flow.

Overview of the Actions

There are three key actions on the left hand-side (with more to come, and access to all other standard Flow actions)

  1. Route Work – This is where you define the routing requirements:
    1. What Queue, Skills, Agent to go to,
    2. What the size or priority of the work is,
    3. etc.
  2. Add Skill Requirements – Helps you to build up a list of Skill requirements for Skills-based routing
  3. Add Screen Pop – Define what records will open on the screen when the agent accepts the work

Quick Guide

I’ll write other posts on more complex scenarios, but just to get you started we’ll show how to build a quick bit of Queue based routing logic. In this scenario we’ll check for some keywords in the Case.

Step 1: Define Flow input variables

Once created, you’ll need to define an input variable to get in the ID of the work item that you plan to route. Optionally, you can also pass in the record itself. These aren’t critical for Case routing as you could manually grab the ID if you wanted, but for the real-time channels like Voice or Chat they’re passed in and so you’ll need to define them to be able to use them later.

  • recordId – type Text
  • input_record – type Record

Step 2: Add some routing logic to the Flow

Let’s grab a decision node and check the Case subject. Here I made one that looks for some keywords like Billing or Tech Support.

Step 3: Route the work

Herein lies the fun part. Drag on the Route Work action where we’ll see a whole range of inputs to decide where we want to route the Case, and it’s priority.

Some key things to define:

  • Record ID – this is the ID of the Work Item to route
    • use the recordId variable from before
  • Service Channel – the object type that we’re routing
    • select ‘Cases’ or whatever you’ve named your Case Service Channel
  • Route to – the type of routing you want to use (Queue, Skills, Direct to Agent)
    • select Queue here
  • Queue – the name of the Queue that you want
    • Use the lookup and pick a Queue from your org to route to

Step 4 (last one): Invoke the Omni Flow

For real-time channels like Chat, Messaging, or Voice you can define the Omni Flow to run from their setup screens.

For other objects like Cases, Leads, or Custom-objects though you can invoke routing at any point, so here we’ll just use a trigger flow to kick it off whenever the case is created. Alternatively you might build a screen flow for transfer, or another record triggered flow to route whenever a customer re-opens the case. The world is your oyster.

We can kick off the Omni Flow as a sub-flow, just make sure to pass in the Case ID to the recordId input variable!


And with that, you’re good to go. Create a Case and test it. Then come back and share what you built, or read some other posts for more advanced scenarios like Skills-based routing, or the exciting new Direct to Agent routing options!

Video Guide

Omni-Channel Flows, an Introduction


With Salesforce, we’re fortunate to have an incredibly powerful and flexible work/channel routing engine, that has helped thousands of customers to automate the assignment of Support Cases.

With great power and flexibility though came a lot of variation in the setup options available. Whether it was Case assignment rules, Queues on Chat buttons, Skills-based routing rules, Apex code, external logic for Voice systems, Bots calling flows or apex, there were a lot of ways to configure routing requirements, and not every channel supported every feature.

Now ALL of the above can be consigned to the history books.

With the Winter ’22 release Salesforce GA’d Omni-Channel Flows, which are now the place you should go to configure routing requirements for all scenarios and use-cases.

With this, it achieved 3 key benefits:

  1. Provided a unified setup experience for routing rules across all channels (Voice, Chat, Messaging, Case, and others)
  2. Increased flexibility to write business rules, while at the same time making it easier to set up and configure
  3. Built a Channel Orchestration layer for upfront Business rules, with a lot more planned than just routing to come (Sneak peak for Screen Pop, Channel-Object Linking, Einstein Case Classification, Einstein Bots, Einstein Article Recommendations, and much more to come)

It’s also a platform on which all new Omni features will be centralized, meaning that as soon as a new Omni capability is launched, it’ll be available for all channels right away. Read more for some exciting examples, like the new Direct to Agent routing.

If you want to get started, I wrote up another post on how to Build your first Omni Flow

Upsert Records Now Can Take a JSON String

The upcoming Quick Records use case enables the user running the flow to specify an object then and there. To make that work, some of the components have been enhanced to support an alternative JSON input solution. For Upsert Records, this takes the form of two new optional inputs:

serializedRecordDatatext. This should be a JSON string of key value pairs where the keys are the names of fields on a single object. for example: {‘AnnualRevenue’: ‘400000’, ‘Rating’: ‘Hot’}
objectNamethe name of the object that the serialized key value pairs belong to. Example ‘Case’

Datatable is being updated to output these two pieces of data, and they are also available in the outputs of the imminent Quick Record component. So the idea is that you would use those components to make changes to records (through inline editing, filtering, and the like) and then you’d pass the resulting serialized record data to this Upsert, which now knows how to turn the string back into records and save them.

Available as of Version 1.32.

36,000 Point Slamdown From Ryan Mercer: You can now create “Web-to-Case” that supports Case Attachments

15 years ago an Idea popped up on the Idea Exchange. The Idea was simple enough: “I would like the ability to generate or write into the HTML code the ability to attach files to cases before they are submitted through the online form.” Unfortunately the implementation is tricky. So tricky that Salesforce had to punt their proposed GA release of the feature from Summer ‘22 to an undetermined date in the future.

I write with good news, however! With version 1.7 of File Upload Improved, you can create a “Web-to-Case” form on your website that enables files to be uploaded and automatically added to the newly created case.  

The snippet of code that you add to your website is different from the one generated by Setup —> Web To Case because you’re actually embedding a screen flow on your site using Lightning Out. What’s powerful about this is that you can tap into all of the power of flow to craft your web form and process the resulting customer data.

Security Considerations

As always, when you allow guest users to run flows, you need to consider the security ramifications. We have included tips below to mitigate any security exposures, but we recommend a careful review of the permissions granted to your Guest User and Profile, and your sharing settings.

Video Walkthrough

I’ve recorded a video that illustrates an end-to-end walkthrough of how to implement this in your own org. I’ve also included a high level overview of the steps below, with links to the applicable parts of the video.

Step 1

Install File Upload Improved

3:10 in video

Step 2

Create your Screen Flow.

Two points to note:

1. You might consider NEVER setting How to Run the Flow field on the Flow Properties configuration screen to System Context in order to limit unnecessary access. Never heard of this? Don’t worry, this is not the default option, and would require you to manually make the selection.

2. As an extra layer of security, you might consider restricting access to ALL of your Flows across the board to only those profiles (or permission sets) who need them. You can do this by selecting Edit Access from the down arrow drop down on the right of the Flow Definitions screen…

… and then selecting the appropriate profiles to enable access.

3:33 in video

Step 3

Create a Site or Community (aka Experience)

8:28 in video

Step 4

Grant permissions to the Guest User’s profile that match the scope of the operation of the Screen Flow. In our example, we are granting the Guest User the ability to Create Cases as well as Edit the Supplied Name, Email, Subject, and Description fields of the Case object.

It’s also important to assign the File Upload Improved permission set to the Guest User.

10:24 in video

Step 5

Create an Aura Component and update the .cmp file with this code:

<aura:component  implements="flexipage:availableForAllPageTypes,lightning:availableForFlowActions" access="GLOBAL">
    <aura:handler name="init" value="{!this}" action="{!c.init}" />
    <lightning:flow aura:id="flowData"/>

… and the Controller.js file with this code:

    init : function (component) {
        var flow = component.find("flowData");

Importantly, replace the ‘YOUR_FLOW_API_NAME’ string with the name of the flow you want to run. A simple flow that has a single screen and then creates a case is a good choice. Use the File Upload Improved screen component to upload attachments.

It’s important to realize that if a user knows (or can guess) another Flow API Name, they could access that flow. This is why, in Step 2, we recommend restricting access to ALL flows to only those who need the access. With that extra security measure, even if the user knew (or could guess) another Flow API Name, they wouldn’t have the access permission.

11:48 in video

Step 6

Create an Aura Application and update the .app file with this code:

<aura:application access="GLOBAL" extends="ltng:outApp" implements="ltng:allowGuestAccess">
    <aura:dependency resource="c:embedFlowInExternalWebsite"/> 

Step 7

Add your website’s domain to the CORS Allowed Origins List.

16:20 in video

Step 8

To make it work, you embed a small piece of code (a ‘snippet’) on your webpage:

<script src=""></script>

<div id="lightningLocator"></div>

        function() {
                { },                  
                function(cmp) {}

Importantly here, you need to insert the URL to your Salesforce org in 2 places.

17:21 in video