In the world of telephony, an automated call distribution (ACD) system is a system that distributes incoming calls to a specific group of agents based on the customer’s selection, customer’s telephone number, selected incoming line to the system, or time of day the call was processed. We also call this a call center.
A couple years ago, Twilio’s Charles Oppenheimer (https://github.com/choppen5) built a demo of a Salesforce-embeddable ACD (https://github.com/choppen5/client-acd) using Twilio Client and Ruby. Much credit to Charles in this regard.
We have simply taken Charles’ demo and converted it to Node.js with a Flybase-powered backend to handle the distribution of calls, rather than the original Ruby/Mongo system. The result is a cleaner call center that’s easy to modify and integrate into other CRMs.
Flybase.io (https://flybase.io/) as our backend, handling storing data, passing events, and our call queues.
Heroku will be used as our web host, but you can host your call center anywhere you’d like.
Salesforce Open CTI (https://developer.salesforce.com/page/Open_CTI) is an open API to allow third-party CTI vendors to connect telephony channels into the Salesforce CRM interface. In our demo, we use Open CTI to house our softphone and drive the click-to-dial/text functionality. The demo requires no plugins or installed software, thanks to the design of Open CTI.
The actual Salesforce integration is optional, and you can easily insert your softphone into another CRM. Part 2 of this tutorial will actually use Flybase to build a simple CRM with the softphone included as a widget.
You can find the full source code here: https://github.com/flybaseio/callcenter.
First, let’s set up our Node.js app.
Recapping the Code
There’s a lot happening in this file. First, we require our various libraries and set up express. Then we start our actual work.
- callsRef connects to our calls table and handles storing and retrieving information for incoming calls.
- agentsRef connects to our agents table and handles storing and retrieving information for agents.
The first backend task we handle is checking our Twilio queues to retrieve the queueId or our call queue, or else create it if it doesn’t exist. We use this queue for storing incoming calls if there are no agents available in our call center, and they stay inside the queue until an agent is available.
- agent-removed: When an agent logs out, then we update their user record to set them to not ready.
- get-ready-agents: Just returns the number of agents currently set to Ready.
- /dial is a POST request that is handled by Twilio to make outgoing calls between the agent’s web browser and a phone number.
- /voice is a POST request that handles incoming calls from phone numbers. This works by finding the agent that has had their status set to Ready for the longest time and assigning them to the call. If the agent is not Ready, then we place the caller in a queue and check it later.
- /handDialCallStatus is a POST request that is called when a call finishes. It checks to see if the call was answered or not answered and, depending on the DialCallStatus returned from Twilio, either places the caller back into the queue and takes the agent out of the Ready status or hangs up the call as it assumes the call is done.
- /token is a GET request called via an AJAX call on the frontend to assign a Twilio Client capability token to the agent while they are logged in.
- /getconfig is a GET request called also via an AJAX call from the client that returns the call center’s Flybase settings for the softphone to use in the frontend.
- / is a GET request that displays the softphone and assigns a name to the client based on the ?client query string.
- getLongestIdle is a function that checks for either an agent whose status is set to Ready or “DeQueuing” and returns that agent’s client name. In the case of no agents being found, then we return false, and it places the caller in the queue. “DeQueuing” is a special status we’ll be setting at the end of our code as an agent becomes available.
- update_agent will take the agent’s ID and update their account in the Flybase database with new info, such as status updates when on a call, going offline, etc.
- update_call is used in the same way as update_agent but for tracking calls.
It enters into a loop to return all callers in the call queue.
If there are callers waiting to connect to agents, then it will look for the agent with their status set to Ready and who has been Ready the longest by sorting by the readyTime field.
If an agent is Ready, then we set that agent’s status to DeQueuing and connect the caller at the Front of the queue to that agent by calling our dqueueurl.
If no agents are Ready or no callers are in the queue, then we set a timeout to call the function again in 3 seconds and return to step 1 of the “checkQueue” loop.
Update this file to contain your Twilio information and your Flybase information.
For the Twilio information, you’ll need to create a TwiML app inside your Twilio account. Create the app and have it POST to your call center website at /dial.
Also, create a new phone number inside Twilio and have that phone number POST to your call center website at /voice.
There is a variable called queueName , which is the name of the queue you want your call center to use, and also a variable called dqueueurl, which is the URL to your website with /voice appended to it. You will need this for the dequeuing task as Twilio requires an absolute URL.
This is our index file, which handles the output of our softphone for agents to use to accept and make calls.
Inside the public folder, create a folder called “css” and include the following two files :
Finally, we want to set up our softphone frontend code.
Softphone Frontend Code
Create a folder inside public called js and add softphone.js.
/getconfig to return our Flybase info and enable our agentsRef and callsRef variables. Once agentsRef returns isReady from Flybase, then we trigger a call to our startWebSocket function. isReady is a function that we can use with the Flybase client when we wait to until our connection has been established before performing other actions.
/token to which we pass the agent’s name and which returns a Twilio capability token to let the agent make and receive calls.
/getCallerId to return the outgoing phone number for the call to use.
We use the startWebSocket function (which was based on the original) to set up three event listeners and to update the agent’s status as LogginIn and the time they came online.
We are going to listen for agents-ready and in-queue events from our backend to tell the softphone to update the display to show the number of agents who are set to Ready and waiting for a call and then the number of callers who are in the queue waiting for an agent.
Finally, we’re going to use the onDisconnect event to fire off an agent-removed trigger when the agent goes offline for some reason, such as closing the browser, logging off, etc.
You’ll also notice a clone of our update_agent function in this file. One of the nice things about using Flybase is we can handle our database updates from either the frontend or the backend, so that lets us do a lot that we couldn’t before.
The rest of the softphone.js file is actually the same as it was before. It talks to Twilio Client on incoming and outgoing calls, and it either gets the client name from the?client query string or it gets it from Salesforce, if you are displaying your softphone inside Salesforce.
In update_agent, we use promises to either return an existing agent record so we can update or create a brand-new record.
Deploying to Heroku (Optional)
This step is optional, and you can deploy anywhere you like.
You’ll want a Heroku account and also to have the Heroku Toolbelt (https://toolbelt.heroku.com/) installed.
heroku login to log into Heroku
heroku create to create the application within Heroku
git add --all . to add all of your new files to the repo
git commit -am 'first commit' to store the files inside the repo
git push heroku master to push your git repository to Heroku
heroku open to open your browser at your new, custom URL
The call center is now working. You can add ?client=ANYNAMEYOUWANT to the end of the URL, and it will set you up as the agent.
Configuring Salesforce (Optional)
This step is optional. The call center works without Salesforce, and in part 2, we’ll build a basic CRM that you can integrate this into as well.
Go to Call Centers ➤ Create:
- Import a call center, config included, TwilioAdapter.xml. After import, change the parameter CTI Adapter URL to the Heroku URL created in the first steps: https:/<insert yourherokuappurl.
- Add yourself to the call center under “Manage Call Center Users” ➤ Add More Users ➤ Find.
You should now see a CTI adapter under the Contact tab. However, you want to use the Service Cloud Console for all CTI calls (which prevents browser refreshes that would hang up calls).
To create a Service Cloud Console
- Go to Setup ➤ Create ➤ Apps ➤ New.
- Choose “Console” for the type of app.
- Give it a name, such as “Twilio ACD.”
- Accept default for logo.
- For tabs, add some tabs to your Service Cloud Console, such as Contacts, Cases, etc.
- Accept default for step 5, “Choose how records display.”
- Set visibility to all (for dev orgs).
- You’ve now created an app! You will see your console in the App dropdown, for example, “Twilio ACD.”
- You can configure a screenpop response, such as to pop the search screen, in Setup ➤ Call Centers ➤ (your call center) ➤ Softphone Layout.
These steps were borrowed from Charles’ original post as they haven’t changed.
Now you’ve got a working real-time call center ACD system that can be used stand-alone (as a lone softphone), in a CRM such as Salesforce, or in a CRM built entirely around it, which we’ll do in part 2. If you’re familiar at all with the original client-acd, then not much has changed, other than being rewritten in Node and using Flybase as the backend/signal system, and that was the plan with this chapter as I wanted to demonstrate how Flybase can be used within a call center, and this one has always been a go-to for various projects.
Just a reminder, you can find the full source code here: https://github.com/flybaseio/callcenter.