How We Built TR Hello!
A contact centre solution with Twilio, inside Google Chrome
A few months ago, on June 27th, we celebrated World Touring Day. Beyond hosting a big party where we got the chance to meet some of our investors and partners, we also had one of our biggest sales of the year. The next day, nursing our hangovers, we discovered that we had a lot of customers calling us and not getting through to our agents to have their questions answered. We received feedback from our customer support agents that the current phone solution (a web page plugin dating back to 2014) was unstable, not working properly, and that, in most cases, it was just wasting their time. When a customer was calling, instead of the call directly going to one specific agent, it was ringing for all agents who were online. If we had 50 agents online, then one call would generate 50 notifications until somebody picked up. Obviously, this solution was causing a lot of frustration not only for our agents, who were wasting productive time with all these notifications but also for our customers, who were waiting a long time before reaching an available agent. We needed something that would make answering calls easier, provide a better experience, and increase response times.
In order to find the best solution, we decided to take on the challenge with an open mind. But first, we needed to understand what a day in the life of our customer support agents was really like. As a team, we began spending time with our agents to get a real feel for how they handled calls. We saw that while on a call, an agent would browse multiple web pages to gather relevant information or to complete forms. This exercise taught us that whatever solution we brought needed to incorporate changes fast, scale-up, and provide accurate and detailed data about the calls.
With these as our main focuses, we began brainstorming and researching. After a few days of trials, proof of concepts and iterations we decided on 3 major aspects:
- Build a chrome extension that we could easily integrate on every page
- Make as much use of Twilio’s service as possible (since they are specifically built for automatic voice solutions like this)
- Build up a microservice that glues all of the parts together and serves as a basis for future real-time communication projects
The Chrome Extension
This was our first real challenge since nobody on the team had any extensive experience building chrome extensions. The chrome extension provides one big feature: it stays with our customer support agents on every page. While they’re on a call and going through multiple forms or looking for information, they have the customer information with them and can retrieve and update data without navigating to a separate page. This leverages several components that Chrome provides.
Chrome extensions are zip archives of scripts and pages with a configuration file, the manifest.json. Inside the manifest.json you can specify the scripts, stylesheets or resources that can be inserted in a page using the [content_scripts][1] tag.
"content_scripts": [
{
"matches": ["https://*/*", "http://*/*"],
"css": ["pageInjection/style.css"],
"js": ["background/env.js", "background/config.js", "pageInjection/overlay.js"]
}
]
- Matches — a regex for the pages where the scripts should be active, in our case we want this for all pages.
- CSS — additional stylesheets that will be made available on that page (Note: The CSS will conflict with the pages’ existing stylesheets.)
- JS — javascript files that will be loaded in an isolated world, without access to other javascript on the page, but with access to DOM and Chrome browser APIs.
Next, we configured a background page where we put all the logic that we wanted for handling voice calls. This background page is kept open by Chrome at all times, the user can not see it and it communicates with the injected scripts using the chrome tabs API.
When the user clicks a button inside the injected scripts, then an event is sent to the background page and processed. When a call is coming through, first it reaches the background page and then an event is sent to the injected scripts of every open tab and the UI gets updated.
"background": {
"page": "background/background.html",
"persistent": true
}
One thing we discovered when injecting scripts is that injected CSS will conflict with whatever CSS is already on that page. While the rules on how CSS child and parent work are complicated, there are 3 simple things that work on 99% of the pages where we injected HTML for the extension:
- Adding unique names for classes and identifiers: a prefix such as f8434cFm_injected_ will not interfere with other CSS.
- Using the highest z-index value for the injected elements, which is 2147483647.
- Always putting the parent and the child in the rule. For example, if you have
<ul>
<li class=“list_element”>Element</li>
</ul>
And you want to define styles for .list_element, define it for ul li.list_element instead of .list_element
One cool feature that Chrome Extensions provides is direct access to the Google oAuth client inside Chrome. So instead of having the user login using a web page or other mechanism, the user can easily login into the browser and the extension can continue to use the JWT token provided to make API calls to a backend.
The drawback with chrome extensions is that any release takes one hour to happen on the Chrome Store and the extension doesn’t update automatically to all users at the same time. This is a technical limitation coming from the Google Chrome store itself and the way the Google Chrome browser is engineered. Therefore all our releases for the chrome extension need to be backwards compatible in order to not break current calls that agents have.
The Twilio Integration
Twilio has been our partner for voice calls since day 1, but our initial implementation was a few years old and it wasn’t taking advantage of the service’s most recent features. During our analysis, we discovered that Twilio provides a lot of solutions for handling voice calls that would automate processes that would, in turn, save us time since we wouldn’t have to reinvent the wheel in terms of how customer contact centres operated.
The first things we needed for answering our customers' calls were a phone number and a phone. But we didn’t want just any phone number, we wanted toll free numbers in all the countries where our customers are located. Also, we didn’t need one phone, we needed a phone for every customer support agent that talks to our customers. This is when we start looking at Twilio, our external partner that offers an out of the box cloud voice service. The core solution is Twilio Voice, which allows for calls to be handled in the browser using a JS SDK. It’s a really simple and powerful solution for voice services, allowing a complete integration with just a few lines of code. It abstracts away all sound integrations between the browser and audio devices while connecting to Twilio’s backend services using WebSockets, which is way more convenient than the classical approach with landlines and a telephone on every desk.
Next, we wanted to connect customers who’ve already booked a tour to agents that could provide detailed information about the specifics of the tour and answer our customers most frequently asked questions automatically. We needed an IVR, or Interactive Voice Response. This is what all major customer contact centres use when you call them and hear: “for English, press one. To get in touch with a customer support representative, press 2”.
Traditionally these IVRs are configured using complicated XML files or code, but Twilio built an interface for this which saved us weeks of development work. It’s called Twilio Studio and it’s intuitively simple. You just go to the workflow interface, add a widget, configure the message that should be played to the customer (MP3 file or auto-generated) and connect the workflow to a phone number (see screenshots here).
The last piece of the puzzle was having a call ring to only one agent (as opposed to 50). This meant “ringing” a call from one agent to another while making sure that the customers who are waiting for the longest time have priority. One way we could do this was by implementing a classic FIFO queue-ing mechanism, however, we discovered that Twilio TaskRouter was a better solution. It’s a system that can route anything from calls to SMS messages based on different configurations, has a JS SDK and communication is done via WebSockets. After integrating it in our extension we found out that it’s the same solution that ING Bank uses to handle their calls globally.
RTCS
We glued all of the above together by building the RTCS microservice which connects the background page and the Twilio services together. On top of managing the integrations of the extension and Twilio, RTCS also aggregates events launched from Twilio for business intelligence purposes. This brings us closer to a true microservices architecture, not only for our internal services but also for integrating with our 3rd party partners.
When a customer calls one of our phone numbers, he or she is put through the IVR (right side of the diagram). After several interactions with the IVR, the call gets enqueued in TaskRouter (red lines). During this time, Twilio makes various API calls to RTCS and the events are collected and stored for future reference (brown lines). When the call gets enqueued, the customer support agents receive notifications about the incoming call and they have the option to accept or decline. Once a call is accepted a web socket is opened that connects Twilio’s voice services to the browser and so audio is being sent back and forth. At the end of the call, all the information saved by the agent is sent to the Chrome background page which does an API call to the RTCS backend to save the call information.
All in all, by building TR Hello we managed to give our customers a better experience by reducing call waiting times by 10% and the number of missed calls by 40%. By using Twilio IVR and TaskRouter we leveraged most of the existing solutions instead of building everything ourselves which in the end saved us development time. For future developments, we plan on introducing chat to the extension so that our customer support agents have a more centralised communication tool and we plan on migrating everything to React components and GraphQL since these bring the user experience closer to a real-time service.
Interested in joining TourRadar and helping provide life-enriching travel experiences? We’re always looking for talented and passionate individuals to join our engineering team!