Creating a Click to Call Service with Twilio Client, Pusher and Python

July 29, 2014
Written by
Paul Hallett
Contributor
Opinions expressed by Twilio contributors are their own

twilio

Let’s be honest: traditional call centers have a terrible user experience.

You see something interesting on a website that you want more information about. Email takes too long, so that option is out of the question. What do you do? You search for a phone number (hidden in their contact page at the bottom in tiny text), place a phone call, give away all your details, and (eventually) you end up getting to a human who might be able to help you. In this day and age of technology, why can’t the website know what I’m looking at and put me in touch with a human just by clicking a link?

This solution to this does exist and it is called Click to Call.

Click To Call is a bit of a buzz at the moment, with big names like Twitter looking at ways to support ads and user engagement on their platform. Click To Call allows customers to click a link and start an in-browser voice call with a human. While that voice call is being established, contextual information about the customer (such as the item they are looking at, or their name / interests / Facebook likes) is passed over to the person handling the call, who can then provide a highly personalised experience. The customer doesn’t need to tell them their name, or the product / service they’re interested in: Click to Call does this all for you. It gets rid of the annoying parts of call centers and lets you get on with what’s important to you.

In this tutorial I’ll show you to build a Click to Call service, which with the advent of modern technologies such as Twilio Client and Pusher; we can create, complete with real-time updates, in less than a day.

What You’ll Learn

The steps required to create a Click To Call service for adverts on a website are few but include:

  1. Setting up a Twilio Client web application with Python and Flask
  2. Using the Twilio Client JavaScript library
  3. Creating browser-to-browser voice calls through Twilio Client
  4. Passing contextual information about the chosen advert to your call center using Pusher.

We’ll be writing this step-by-step, but you can also find an example project at https://github.com/phalt/call-ads if you’d rather just read the source code.

In order to complete this tutorial you will first need:

  1. A Twilio trial account, you can sign up for free and only takes a minute.
  2. A Pusher trial account so we can send real-time data about the items our users are clicking on.

Setting Up Twilio Client

Let’s start by creating a TwiML app. What is a TwiML app? It’s a reusable TwiML configuration that can be applied to Twilio phone numbers or TwiML applications. Each TwiML app has a unique SID which we use to generate security tokens for Twilio Client.

Head over to the apps page on your account and create a new app by clicking ‘Create TwiML App’:

 

We’re calling our TwiML App ‘Click to Call demo’ because we like being explicit rather than implicit. You’ll need to link the Voice Request URL to a URL on your website. We’ll hit save and this will generate an SID for the TwiML app which we will use later on, so keep it handy.

Getting Into Some Python Code

Now that we’ve generated a TwiML app and set its voice URL let’s start to write some code. Like in the Github example project I’ve made we’ll need to create a few functions in a file called app.py.  The functions are named build_twilio_token, generate_voice_twiml, controller and index. We’ll explore what each one does below.

Generating Capability Tokens

Let’s start with the build_twilio_token function:

def build_twilio_token(client_name):

    # Find these values at twilio.com/user/account
    account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
    auth_token = 'ATXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

    capability = TwilioCapability(account_sid, auth_token)
    # This is the app Sid of your TwiML app
    app_sid = 'APYYYYYYYYYYYYYYYYYYYYYYYYYY'

    capability.allow_client_outgoing(app_sid)
    capability.allow_client_incoming(client_name)

    return capability.generate()

In this function we are using the TwilioCapability object to generate a unique capability token for Twilio Client. This capability token is used to securely set up an instance of Twilio Client and give it access to certain features, such as inbound voice and outbound voice. We’re doing this on the server because, even though the bulk of the Twilio Client code is client-side javascript, we use our account_sid and auth_token keys to generate the token and we want to keep those keys secret.

Using the allow_client_outgoing and allow_client_incoming methods lets us give this instance of Twilio Client access to specific capabilities. We could chose only incoming or only outgoing voice calls if we wanted to but for this app we’ll need both. Why? We want to let users make voice calls from the browser and also let the call center receive voice calls in the browser.

The client_name variable given to the allow_client_incoming method is used by our Click to Call app to define the name of the current user.  In our app we have two users, ‘anonymous’ which is the default user by our app and ‘Admin’ which is the the agent in the call center.  By providing different names to the allow_incoming_method, we can create separate “users” of our app that can call each other.

The allow_client_outgoing function takes the app_sid variable from our TwiML app (which we created earlier) and it will use the Voice Request URL we defined there for outgoing calls.

Finally, we return a token, generated from the capability object with the generate method.

Now we’ve got the code to generate our capability tokens, let’s use it in our Flask views.

Building Some Views

We need to create two views for our application, one for the customer which lets them initiate a call, and one for the agent who answers those calls. The default route (‘/’) in our app represents a customer facing webpage. In Flask, we link the route to a function which we’ve called index:

@app.route('/', methods=['GET'])
def index():

    token = build_twilio_token(client_name)

    return render_template('index.html', token=token)

Flask links routes to functions using the decorator on the first line. The index function takes the token from the build_twilio_token method we just created.  We then return a render_template method, which is provided by Flask to generate web pages. In this method we are passing the token variable to be used later on, and a template name as a string. For the templates to work, you’ll need to place them in a folder called templates, in the same directory that app.py is in, like this:

my_app/
    app.py
    templates/
        index.html
        control.html

The HTML template we’ll use for the front end of our Click To Call app can be found on the example project here. There are a few parts of this file that are particularly important to us.

First, we’re including the jQuery and Twilio Client javascript libraries. Twilio Client does not require jQuery, but in this example we’ll need it for some front-end manipulation later.

<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script>
<script src='//static.twilio.com/libs/twiliojs/1.1/twilio.min.js'></script>

Next, remember we passed the token variable into the template back in our Python logic? We’ll use the magic of jinja2, which is used by Flask, to render that token now in the Twilio.Device.setup method. This method is crucial for setting up our Twilio Client application and should always be the first thing we do.

Twilio.Device.setup('{{ token }}');

To start voice calls we’re using anchor tags with the onClick attribute set to call a javascript function call_about. This function is declared near the bottom of the file:

function call_about(item_of_choice) {
    var params = {'item': item_of_choice, 'name': 'anonymous'};
    Twilio.Device.connect(params);
}

The function call_about takes a single parameter: item_of_choice. This is then placed in a Javascript key/value pair we’ve called params. Finally we initiate a voice call to Twilio by calling the Twilio.Device.connect method and passing in the params variable.

You should now be able to open a browser window at the home page of this application and see a few clickable items.

Screen Shot 2014-05-28 at 12.26.26.png

If you tried to create a call right now you will see errors on your account dashboard. We have not yet built the instructions that tells Twilio what to do once the client establishes a call into Twilio, nor have we created the backend view to receive the call.

Generating TwiML

In order to get the calls to work, we need to generate some TwiML instructions. These instructions will instruct Twilio to connect the caller to a specific Twilio Client user. We only want it to place calls to the call center, so the TwiML we need is actually pretty basic.

Add this to the app.py file:

@app.route('/voice/', methods=['GET', 'POST'])
def generate_voice_twiml():
    return '<Response><Dial><Client>Admin</Client></Dial></Response>'

We’re creating a route at /voice/ on the server that accepts GET and POST HTTP requests. The method this route links to, generate_voice_twiml returns a basic string with the <Client> TwiML tags. This tag is used to connect a call to a Twilio Client user with the name between the tags.

At this point we can try to start a call. The /voice/ URL will successfully pick up and will ring indefinitely. This is because there is no way for the call to be picked up. We need to build the backend view to allow the call center agent to receive the calls.

The Backend View

The second view, created by the controller method in our app.py file, is very similar to the index method but with a few differences. Let’s look at the code:

@app.route('/control/', methods=['GET'])
def controller():
    token = build_twilio_token('Admin')
    return render_template(
        'control.html',
        token=token,
        client_name='Admin'
    )

The two differences between this method and the index method are 1) the template we’re using – control.html, and 2) the fact we’re generating a different token using the ‘Admin’ name instead. The final difference is the changing of client_name to be ‘Admin’ too.

The template we’re loading here, control.html, is similar to index.html but with a few differences in the javascript. You can view the entire file here.

Twilio.Device.incoming(function (conn) {
    conn.accept();
});

function hangup() {
    Twilio.Device.disconnectAll();
}

Here we are telling Twilio Client to listen for incoming connections with the Twilio.Device.incoming method and then to accept all calls with conn.accept(); when a call is received. In the hangup function we’re disconnecting all current calls (if there are any).

Testing The Calls

You should now be able to open both the index and controller web pages in separate browsers and place a phone call! That’s Twilio Client calling established, but how do I do all the cool contextual stuff? We’ll need to edit some of the code we’ve previously written.

Adding Contextual, Real-Time Information with Pusher

In order to use Pusher we need to do the following:

  • Set up the frontend subscriber which listens for new events on a particular channel
  • Set up the backend publisher which triggers a new event when called.

We can edit the current controller.html webpage to include the Pusher library at the top of the page:

<script src='http://js.pusher.com/2.2/pusher.min.js' type='text/javascript'></script>

We can then add some extra Javascript below the Twilio Client javascript to start the subscriber:

var pusher = new Pusher('{{pusher_key}}');

var channel = pusher.subscribe('twilio_call_center');

channel.bind('new_caller', function(data) {
    $('.warning').val(data['name'] + ' wants a ' + data['item']);
});

Here we create a new pusher object and subscribe to the channel we call ‘twilio_call_center’. Because we subscribe to it; any messages that are sent to this channel will cause the javascript method to run. In this case our method changes the value of a <div> in our code.

The {{pusher_key}} variable needs to be provided by our backend view, so let’s go and add this to the controller method now.

Near the top of the app.py file add your Pusher account credentials:

# Pusher credentials found at https://app.pusher.com/
p_app_id='PUSHER_APP_ID'
p_key='PUSHER_KEY'
p_secret='PUSHER_SECRET'

Then further down in the controller method we want to add p_key into the list of variables we pass to the template:

@app.route('/control/', methods=['GET', 'POST'])
def controller():
    token = build_twilio_token('Admin')
    return render_template(
        'control.html',
        token=token,
        client_name='Admin',
        pusher_key=p_key
    )

You can view the final code for this method on github.

That will now allow us to subscribe to the pusher channel and update the backend view whenever an event occurs on that channel.

Now we need to publish events to that channel. We’re going to modify the code of the generate_voice_twiml method found here in app.py:

@app.route('/voice/', methods=['GET', 'POST'])
def generate_voice_twiml():
    item = request.values.get('item', None)
    name = request.values.get('name', None)

    p = Pusher(p_app_id, p_key, p_secret)

    p['twilio_call_center'].trigger(
        'new_caller',
        {
            'item': item,
            'name': name
         }
    )

    return '<Response><Dial><Client>Admin</Client></Dial></Response>'

The first thing this code does is retrieve the parameters we’re sending alongside the Twilio.client.connect from the http request. We’ll store these in variables called item and name for later use. After that we generate a new Pusher object with our Pusher account details.

When the code below it is run, this will update the subscribing javascript code almost instantaneously.

Save the file and load both the frontend page and the backend page in separate browsers (make sure you’re on a live server or using ngrok) and click a link on the homepage. This will trigger a voice call. The backend page should start ringing, and now the list should update with details about the caller:

Et voila: Click to Call links with real-time contextual information.

Moving Forward

See, I told you it was easy to do!

This is a very basic implementation, designed to show you the possibilities of a real time Click to Call service using Twilio Client and Pusher. You can use this blog post and the open source code to extend the tutorial and begin building your own applications.

Here are some ideas to get your brain juices flowing on how you could use real-time information like this with Click to Call:

  • Bring up caller information as the call is made to speed up calls.
  • Gather location data from callers to automatically geographically place them.
  • Use it in a video game to quickly share gamer profiles or user data between callers as calls are made.

If you’ve enjoyed this post, or you want to ask me a question, I’m available at paul@twilio.com. Happy hacking!