Make and Receive Phone Calls from the Browser with Twilio Programmable Voice, Python and JavaScript

April 21, 2021
Written by
Carlos Mucuho
Contributor
Opinions expressed by Twilio contributors are their own

In this tutorial, we are going to write an application that uses the Twilio Programmable Voice API to make and receive phone calls from a web browser. We will also implement a UI that allows us to make, accept, and reject phone calls.

By the end of this tutorial we will have an application that looks like the following:

Project demo

Tutorial requirements

To follow this tutorial you are going to need the following components:

  • A free or paid Twilio account. If you are new to Twilio create a free account now. If you create your account using this link and later upgrade to a paid account, you will receive $10 in credit.
  • A Twilio phone number capable of making and receiving phone calls. Get one now if you don’t have it.
  • Python 3.6+ installed.
  • ngrok installed. ngrok is a reverse proxy service that creates a secure tunnel from a public endpoint to a locally running web service. We will need to use ngrok to create a secure URL that allows Twilio to connect to our application.
  • A cell phone or telephone capable of making and receiving phone calls, to test the project.

Basic concepts and Application logic

The goal of  this tutorial is to build a web application that allows us to make and receive phone calls in the browser. We will use the Flask framework to implement the required webhooks and serve the client application.

The application client will use the Twilio Client JS SDK (twilio.js) to create a Twilio Device.

A Twilio device is our main entry point for making and receiving phone calls in the browser. In order to  set up a connection between a Twilio device and Twilio’s servers we will need to generate access tokens in our application server.

Access tokens are short-lived credentials that can be distributed safely to client-side applications that we can use to authenticate Twilio Client SDKs likeVoice,Conversations,Sync, and Video. To generate access tokens in our server, we will need to use a Twilio API key.

A Twilio API key is a credential that grants us access to the Twilio API. An API key allow us to:

  • Authenticate with Twilio's API
  • Create and revoke Access Tokens

Access tokens will grant the client access to a TwiML Application (TwiML app). Twilio relies on a TwiML Application within our account to determine how to interact with our server.

TwiML (the Twilio Markup Language) is a set of instructions we can use to tell Twilio what to do when we receive an incoming call, SMS, or fax.

Creating the project structure

In this section, we will create our project directory, and inside this directory, we will create the standard directories for a Flask application. After that, we will create and activate a virtual environment. Lastly, we will install the Python packages needed to build this web application.

Open a terminal window and enter the following commands:

$ git clone git@github.com:CSFM93/tutorial-twilio-in-browser-calling-start.git twilio-in-browser-calls
$ cd twilio-in-browser-calls

Here we cloned a starter project that was created for this tutorial and set the name to twilio-in-browser-calls, after that we navigated into this project directory. This project contains the boilerplate code that we will use to build our application.

You will find the following standard directories for a Flask application inside :

  • static : this is where all static files are stored.
  • templates : this is where all templates are stored

The static subdirectory has the following contents:

  • css - This is where we will store all         CSS files. Inside this subdirectory you will find a file named style.css, this file will be responsible for styling our application client UI.
  • images - This is where we will store all images. Inside this  subdirectory you will find a file named user.png, we will display in our application client UI.
  • js:  This is where we store all our Javascript files.  Inside this directory you will find a file named modals.js. This file contains the code to manage the modals stored in the templates directory.

The templates subdirectory has three files: call_in_progress_modal.html, dial_modal.html and incoming_call_modal.html.

The call_in_progress_modal.html file contains the HTML code that implements a modal that will show during a call. This modal shows the duration of the call in progress, the number you are calling, and a button with a red phone icon that will allow you to end the call. This is how this modal looks:

 

Call in progress page

The dial_modal.html file contains the HTML code that implements a modal that will show when you wish to dial a phone number. This modal shows a number pad and button with a green phone icon. This is how it looks:

dial a number page

The incoming_call_modal.html file contains the HTML code for a template that implements a modal that will only show when you are receiving a call .This modal shows the number that is calling you, and two buttons, one button with a green phone icon and another with a red phone icon. The first button will allow you to accept an incoming call and the second to reject it.

incoming call page

Inside our working directory create a virtual environment and activate it. If you are using a Unix or Mac OS system, run the following commands to do it:

$ python3 -m venv venv
$ source venv/bin/activate

If you are following the tutorial on Windows, run the following commands instead:

$ python -m venv venv
$ venv\Scripts\activate

Now that we created and activated our virtual environment we can install the libraries that we need to create our application:

$ pip install twilio flask python-dotenv 

In the command above we used pip the Python package installer, to install the following packages that we are going to use in this project:

  • Twilio, a Python package for communicating with the Twilio API.
  • Flask, a Python micro-framework for building web applications. We will use it to create a webhook to interact with Twilio and to create the client UI to make and receive phone calls.
  • Python-dotenv, a library that reads key-value pairs from a file and adds them as environment variables. We will use this module to retrieve our Twilio credentials stored in a .env configuration file.

For your reference, at the time this tutorial was released these were the versions of the above packages and their dependencies tested:

certifi==2020.12.5
chardet==4.0.0
click==7.1.2
Flask==1.1.2
idna==2.10
itsdangerous==1.1.0
Jinja2==2.11.3
MarkupSafe==1.1.1
PyJWT==1.7.1
python-dotenv==0.17.0
pytz==2021.1
requests==2.25.1
six==1.15.0
twilio==6.55.0
urllib3==1.26.4
Werkzeug==1.0.1

Aside from the Python packages mentioned above, we will use the following front end libraries:

  • Bootstrap, a powerful front-end framework used to create modern websites.
  • Twilio Client JS SDK (twilio.js), a library that allows you to make voice calls from a web browser.
  • JQuery, a fast, small, and feature-rich JavaScript library that makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler. We will use it to perform some DOM manipulation and event handling.
  • Font Awesome, a popular iconic SVG, font, and CSS toolkit. We will use some of the icons designed by them in our application client.

Creating a TwiML Application

In this section, we will use the Twilio console to create a “TwiML App”, in which we will later store the URL of the webhook we’ll build.

Open a new browser window and navigate to Twilio account Console > Voice > TwiML > TwiML Apps. Click in the “Create new TwiML App” button, or the red “+” icon if you already have other TwiML apps.

 

TwiML Apps

Enter the name for your TwiML app in the “Friendly Name” field, for example, in-browser calls. Leave the other fields empty for now. Click the “Create” button to create the TwiML application.

TwiML App page

You will be redirected back to the TwiML Apps dashboard. Click on the TwiML App you just created. On the page for this app, select the SID value and copy it to the clipboard.

TwiML App page

In the project’s root directory, create a file named .env and enter the following contents in it:

TWIML_APP_SID="paste your TwiML app SID here"

Creating a Twilio API key

For the next step we are going to create a Twilio API Key for the Voice API. The API Key is going to be used to generate access tokens, which will allow the front end running in the browser to make calls to Twilio APIs.

Navigate to Twilio console > Voice > Settings > API Keys in your browser. Click the “Create new API Key” button, or the red “+” icon if you already have other API keys.

Twilio API keys

Enter the name for your API key in the “Friendly Name” field, for example, in-browser calls. Leave the “Key Type” as “Standard”. Click the “Create API Key” button to create the API key.

New API Key

You will be redirected to a page where you will find information about your new API key. Copy the “SID” and “Secret” values and paste them in your .env file as TWILIO_API_KEY_SID and TWILIO_API_KEY_SECRET. Your .env file should now look as follows:


TWIML_APP_SID="paste your TwiML app SID here"
TWILIO_API_KEY_SID="paste your API key SID here"
TWILIO_API_KEY_SECRET="paste your API key secret here"

Check the “Got it!” field, and then click the “Done” button.

API Key created

Now go to the Twilio Console home page and copy the Twilio Account SID value to the .env file as follows:


TWIML_APP_SID="paste your TwiML app SID here"
TWILIO_API_KEY_SID="paste your API key SID here"
TWILIO_API_KEY_SECRET="paste your API key secret here"
TWILIO_ACCOUNT_SID="paste your Twilio Account SID here"

Next, go to your Twilio account console > Phone Numbers > Manage Numbers > Active Numbers, select the number that you purchased for this tutorial and you will be redirected to a page where you can configure this number. Locate the “Phone Number” field, copy the phone number that shows under this field and paste it in the .env file as TWILIO_NUMBER. Remove any spaces between the digits, but leave the initial plus sign, ensuring the number is in E.164 format.

Twilio phone number

Your .env file should look like the following once the phone number is added:


TWIML_APP_SID="paste your TwiML app SID here"
TWILIO_API_KEY_SID="paste your API key SID here"
TWILIO_API_KEY_SECRET="paste your API key secret here"
TWILIO_ACCOUNT_SID="paste your Twilio Account SID here"
TWILIO_NUMBER="paste your Twilio phone number here"

Creating the Flask Application

In this section, we are going to create the logic of our Flask application, which will provide the supporting functions needed by the front end to make and receive phone calls.

Creating the application server

In this subsection, we are going to create the endpoints needed to make and receive phone calls. We will need to create the following endpoints:

  • / - this endpoint will be responsible for serving the application UI (client).
  • /token - this endpoint will be responsible for generating and returning access tokens to the client.
  • /handle_calls -  this endpoint will be responsible for generating the TwiML instructions needed for making and receiving phone calls.

In the root directory of your project, create a file named main.py. Open it using your favorite text editor and then add the following code to it:

from flask import Flask, render_template, jsonify
from flask import request
 
from twilio.jwt.access_token import AccessToken
from twilio.jwt.access_token.grants import VoiceGrant
from twilio.twiml.voice_response import VoiceResponse, Dial
 
from dotenv import load_dotenv
import os
import pprint as p

Here, we imported all the packages that we are going to need to build our server application:

  • flask will be used to define the endpoints of the application.
  • The twilio package will be used to interact with the Twilio API, allowing us to make and receive phone calls through the Twilio device that will be created in the client.
  • load_dotenv will be used to import our Twilio account credentials from the .env file.
  • pprint will be used to format and print the data received when Twilio sends a request to the /handle_calls endpoint to notify that there is a call.
  • os will be used alongside load_dotenv to retrieve the credentials stored in the .env file

Add the following code to the bottom of the main.py file:

load_dotenv()

account_sid = os.environ['TWILIO_ACCOUNT_SID']
api_key = os.environ['TWILIO_API_KEY_SID']
api_key_secret = os.environ['TWILIO_API_KEY_SECRET']
twiml_app_sid = os.environ['TWIML_APP_SID']
twilio_number = os.environ['TWILIO_NUMBER']

app = Flask(__name__)


@app.route('/')
def home():
    return render_template(
        'home.html',
        title="In browser calls",
    )

The application starts by importing the environment variables stored in the .env file with a call to load_dotenv(). This allows us to retrieve the five configuration variables that we need for this application.

We then create a Flask application instance in a variable named app and with that, we create the / endpoint of our application. This route is serving a template named home.html that we will create later on.

Add the following code bellow the / route :

@app.route('/token', methods=['GET'])
def get_token():
    identity = twilio_number
    outgoing_application_sid = twiml_app_sid

    access_token = AccessToken(account_sid, api_key,
                               api_key_secret, identity=identity)

    voice_grant = VoiceGrant(
        outgoing_application_sid=outgoing_application_sid,
        incoming_allow=True,
    )
    access_token.add_grant(voice_grant)

    response = jsonify(
        {'token': access_token.to_jwt().decode(), 'identity': identity})

    return response

This adds the /token endpoint, which will be invoked by the client to request an access token.

When this endpoint is triggered, we create a variable named identity and assign to it our Twilio number. An identity is unique to a user and may be signed in on multiple devices simultaneously. On  an application server meant to be used by multiple users, we would need to decide, based on the token request that would be sent to us, who the user is and what they are allowed to do. To figure out who the user is (their identity), we would use our existing login system or identity provider (e.g. session cookies, an API token, or any other mechanism that is used to secure your API requests). In this tutorial, however, we are the only user, so we do not need to work with multiple identities and the Twilio number that we purchased for this tutorial works well for this purpose.

We then use the account_sid, api_key, api_key_secret,  and identity to create an access token. The token needs to be provisioned with “grants”, which determine what operations the client presenting the token is allowed to perform. For this application we create a voice grant object that is configured with the sid of the TwiML App created earlier.

To complete the endpoint we return the access_token and identity to the client in JSON format.

Add the following code bellow the /token route :

@app.route('/handle_calls', methods=['POST'])
def call():
    p.pprint(request.form)
    response = VoiceResponse()
    dial = Dial(callerId=twilio_number)

    if 'To' in request.form and request.form['To'] != twilio_number:
        print('outbound call')
        dial.number(request.form['To'])
        return str(response.append(dial))

    return ''


if __name__ == "__main__":
    app.run(host='0.0.0.0', port=3000, debug=True)

This block adds an endpoint named /handle_calls. This endpoint will be invoked by Twilio whenever we are making or receiving a phone call.

When this endpoint is triggered, we use pprint to print the contents of the request.form, and then we create a TwiML response object and a TwiML dial object. In the dial object we set the callerId to the Twilio number that we purchased for this tutorial, this way when we call a phone number using this application the recipient’s phone will show this number instead of anonymous.

After that, we use conditional logic to check if the request.form object has the property named To, and if this property value isn’t the same as our twilio_number. What this test achieves is make sure the invocation of the endpoint was for making a call (and not receiving one), which is the first case we will handle.

Once we are sure this is a request to make a calll, we set the number that we want to dial to the  value in request.form['To'], append the dial object to the response object, and return the response object as a string back to Twilio, which will execute these instructions and dial the requested number.

The bottom part of the script is a standard conditional that executes the Flask development server on port 3000 when the script is invoked from the command line.

Creating the application client

In this subsection, we will create the front end that will allow us to make and receive phone calls in the browser.

Creating the home page

Create a file named home.html inside the templates directory. Open it and then add the following code to it:

<!DOCTYPE html>
<html>
<head>
    <title>In browser calls</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" />
    <link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
    <div class="container">
        <!-- log output -->
        <div class="card text-center log-container">
            <h3>Device log</h3>
            <div id="log"></div>
            <div class="btn-container">
                <button type="button" id="btnOpenNumberPad" class="btn btn-default btn-circle btn-lg">
                    <i class="fa fa-phone fa-flip-horizontal " aria-hidden="true" style="color: green;"></i>
                </button>
            </div>
        </div>

        <!-- Modal dial -->
        {% include 'dial_modal.html' %}

        <!-- Modal call in progress -->
        {% include 'call_in_progress_modal.html' %}

        <!-- Modal incoming call -->
        {% include 'incoming_call_modal.html' %}


        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <script type="text/javascript" src="https://media.twiliocdn.com/sdk/js/client/v1.8/twilio.min.js"></script>
        <script type="text/javascript" src="/static/js/main.js"></script>
        <script type="text/javascript" src="/static/js/modals.js" defer></script>
</body>

</html>

This template implements a page that shows a console where we can monitor the state of the Twilio device that we will create soon using JavaScript. We have included in this template the call_in_progress_modal.html, dial_modal.html and incoming_call_modal.html templates that came with this project’s boilerplate. This page also shows a button with a phone icon. Whenever we press this button a modal will open and in this modal, we will enter the number we wish to call.

Aside from the Bootstrap, jQuery, FontAwesome, and twilio.js files, please notice how we are including the following files in this template :

  • style.css - this file contains some of the CSS used for styling our application
  • main.js - this javascript file contains the code for creating a Twilio device and connecting it  to our TwiML Application .
  • modals.js - this javascript file contains the code for managing the modals of our application.

The style.css and modals.js files came inside the project’s boilerplate repository. We are going to create the main.js file in the next subsection.

Creating the Twilio device

Create a file named main.js inside the static/js directory. Open  it and then add the following code to it:

$(function () {
    var device;

    log("Requesting Access Token...");
    // Using a relative link to access the Voice Token function
    $.getJSON("./token")
        .then(function (data) {
            log("Got a token.");
            console.log("Token: " + data.token);

            // Setup Twilio.Device
            device = new Twilio.Device(data.token, {
                // Set Opus as our preferred codec. Opus generally performs better, requiring less bandwidth and
                // providing better audio quality in restrained network conditions. Opus will be default in 2.0.
                codecPreferences: ["opus", "pcmu"],
                // Use fake DTMF tones client-side. Real tones are still sent to the other end of the call,
                // but the client-side DTMF tones are fake. This prevents the local mic capturing the DTMF tone
                // a second time and sending the tone twice. This will be default in 2.0.
                fakeLocalDTMF: true,
                // Use `enableRingingState` to enable the device to emit the `ringing`
                // state. The TwiML backend also needs to have the attribute
                // `answerOnBridge` also set to true in the `Dial` verb. This option
                // changes the behavior of the SDK to consider a call `ringing` starting
                // from the connection to the TwiML backend to when the recipient of
                // the `Dial` verb answers.
                enableRingingState: true,
                debug: true,
            });

            device.on("ready", function (device) {
                log("Twilio.Device Ready!");
            });

            device.on("error", function (error) {
                log("Twilio.Device Error: " + error.message);
            });

            device.on("connect", function (conn) {
                log('Successfully established call ! ');
                $('#modal-call-in-progress').modal('show')
            });

            device.on("disconnect", function (conn) {
                log("Call ended.");
                $('.modal').modal('hide')
            });

        })
        .catch(function (err) {
            console.log(err);
            log("Could not get a token from server!");
        });

    // Bind button to make call
    $('#btnDial').bind('click', function () {
        $('#modal-dial').modal('hide')

        // get the phone number to connect the call to
        var params = {
            To: document.getElementById("phoneNumber").value
        };

        // output destination number
        $("#txtPhoneNumber").text(params.To)
        

        console.log("Calling " + params.To + "...");
        if (device) {
            var outgoingConnection = device.connect(params);
            outgoingConnection.on("ringing", function () {
                log("Ringing...");
            });
        }

    })

    // Bind button to hangup call

    $('.btnHangUp').bind('click', function () {
        $('.modal').modal('hide')
        log("Hanging up...");
        if (device) {
            device.disconnectAll();
        }
    })

    // Activity log
    function log(message) {
        var logDiv = document.getElementById("log");
        logDiv.innerHTML += "<p>&gt;&nbsp;" + message + "</p>";
        logDiv.scrollTop = logDiv.scrollHeight;
    }

});

Here we creat the Twilio device that will allow us to make and receive phone calls in the browser.

First, we use the getJSON() function provided by jQuery to send a GET request to the /token endpoint in our application server and retrieve an access token. After retrieving the token, we use twilio.js and the token to create a Twilio device and connect it to our TwiML Application.

After creating the Twilio device, we add a few event listeners to this device and some code that will allow us to interact with this device using the UI.

Making Outbound Phone Calls

In this section, we are going to use our application to make outbound phone calls. But before we can do that, we need to run the application, set up ngrok, and configure our TwiML app.

Open a second terminal window in our project directory, activate the Python virtual environment, and start the application by running the following command:

$ python main.py
``

Open another terminal window and start `ngrok` on it:

After running the command above you should see something similar to this:

Ngrok output

Copy the https ngrok URL to the clipboard. Then go to your Twilio account Console > Voice> TwiML > TwiML Apps dashboard and select the TwiML app you created for this tutorial.

Configure voice webhook in TwiML App

Locate the “Voice” section of the TwiML App configuration and paste the https:// URL provided by ngrok followed by /handle_calls in the “Request URL” field and click the “Save” button. This will create a webhook that connects your application to the TwiML App.

In this example, the ngrok URL is https://48dcc810632b.ngrok.io/handle_calls. The first part of the URL will be different every time ngrok is launched.

Now, connect a headset with a microphone to your computer, after that open your browser and type http://localhost:3000/ in the address bar. You should see something similar to this:

 

Initial application page

Once you see a message saying Twilio.Device Ready!, your Twilio device is working as it should. Click on the button with the green phone icon, and you should see the dial modal:

phone dialer

Use the numbers in the pad to insert the number that you would like to call or just type it in using your keyboard in the insert field above the pad, and once you are ready click the green phone to make the call.

Once you click this button, your browser will ask for your permission to use the microphone, grant the permission. Once the number that you are calling answers your call you will see the call in progress modal:

Call in progress page

Go to the terminal running our Flask application, and the request data that Twilio sends to our /handle_calls endpoint will  look similar to the following:

{'AccountSid': 'ACe6c069eb8828c025719e6bbb20d63c75',
 'ApiVersion': '2010-04-01',
 'ApplicationSid': 'AP596a0557d23b118259f2cf355fb3693a',
 'CallSid': 'CAc8356bdd69dec58624588f7d578e5668',
 'CallStatus': 'ringing',
 'Called': '',
 'Caller': 'client:+1xxxxxxxxxx',
 'Direction': 'inbound',
 'From': 'client:+1xxxxxxxxxx',
 'To': '+1xxxxxxxxxx'}
outbound call

Since the value of the property To (the number we called) isn’t equal to our Twilio number, the code inside the if statement in the handle_calls endpoint  ran.

Responding to Incoming Phone Calls

In the previous section, you were able to use your application to make phone calls but so far the application can’t receive any calls. To be able to receive calls, we will need to add some additional code to main.py, main.js, and home.html, as well as configure the number that we purchased for this tutorial in the Twilio console to be able to receive phone calls.

Go back to the main.py file and replace the code in the /handle_calls endpoint with the following:

@app.route('/handle_calls', methods=['POST'])
def call():
    p.pprint(request.form)
    response = VoiceResponse()
    dial = Dial(callerId=twilio_number)

    if 'To' in request.form and request.form['To'] != twilio_number:
        print('outbound call')
        dial.number(request.form['To'])
    else:
        print('incoming call')
        caller = request.form['Caller']
        dial = Dial(callerId=caller)
        dial.client(twilio_number)

    return str(response.append(dial))

Here we have added the else statement to the /handle_calls endpoint. The code in this part will run if the number receiving the call is the number that we purchased for this tutorial, which means that we have an incoming call.

We are setting the callerId in the TwiML dial object to the value of the Caller property in request.form. As the name suggests, Caller is the number that is calling our Twilio number. This is so that we can see who is calling us in our application UI. We are also setting the client in the dial object to the identity value that we used when we created an access token in the /token endpoint.

To complete the incoming call flow, we append the dial object to the TwiML response object, and then return this response object as a string.

Go back to your main.js file and add the following code bellow the device.on(‘disconnect') listener :

device.on("incoming", function (conn) {
    console.log(conn.parameters)
    log("Incoming connection from " + conn.parameters.From);
    $("#callerNumber").text(conn.parameters.From)
    $("#txtPhoneNumber").text(conn.parameters.From)

    $('#modal-incomming-call').modal('show')

    $('.btnReject').bind('click', function () {
        $('.modal').modal('hide')
        log("Rejected call ...");
        conn.reject();
    })

    $('.btnAcceptCall').bind('click', function () {
        $('.modal').modal('hide')
        log("Accepted call ...");
        conn.accept();
    })

});

Here we have added an event listener that will allow your Twilio device to monitor incoming calls and show the incoming call modal once it detects one.

Go to your Twilio console > Phone Numbers > Manage Numbers > Active Numbers dashboard and select the number you purchased for this tutorial.

Locate the “Voice & Fax” section of the phone number configuration and select “TwiML App” in the “Configure With” field, after that select the name of the TwiML app you created for this tutorial in the “TwiML App” field. This will bind the Twilio number you purchased for this tutorial with the TwiML App you created, this way every time this number receives a phone call it will retrieve the webhook URL and other configurations in the TwiML App and use it to respond to the call.  In our case, it will send a POST request to https://48dcc810632b.ngrok.io/handle_calls containing the caller number and other useful information.

Go back to your browser and navigate to http://localhost:3000/, wait for the Twilio.Device Ready! message to show on the page, and then use a device capable of making phone calls to call the Twilio number you purchased for this tutorial. Once the number is ringing you should see the incoming call modal :

 

Incoming call page

Press the button with the green icon to accept the call, and the one with the red phone icon to reject it.

Go to the terminal running our Flask application, and the request data that Twilio sends to our /handle_calls endpoint will  look similar to the following:

{'AccountSid': 'ACe6c069eb8828c025719e6bbb20d63c75',
 'ApiVersion': '2010-04-01',
 'ApplicationSid': 'AP596a0557d23b118259f2cf355fb3693a',
 'CallSid': 'CAf0eb0489e54978471b96dd258dff4de9',
 'CallStatus': 'ringing',
 'Called': '+17146134152',
 'CalledCity': 'SILVERADO',
 'CalledCountry': 'US',
 'CalledState': 'CA',
 'CalledZip': '92676',
 'Caller': '+17205752613',
 'CallerCity': '',
 'CallerCountry': 'US',
 'CallerState': 'CO',
 'CallerZip': '',
 'Direction': 'inbound',
 'From': '+17205752613',
 'FromCity': '',
 'FromCountry': 'US',
 'FromState': 'CO',
 'FromZip': '',
 'To': '+17146134152',
 'ToCity': 'SILVERADO',
 'ToCountry': 'US',
 'ToState': 'CA',
 'ToZip': '92676'}
incoming call

 

Conclusion

In this tutorial, we learned how to use the Twilio Voice API to make and receive phone calls in the browser. We learned how to use the Flask framework to build the application client that allowed us to interact with a Twilio device created with the Twilio Client JS SDK.

The code for the entire application is available in the following repository https://github.com/CSFM93/twilio-in-browser-calls.

Carlos Mucuho is a Mozambican geologist turned developer who enjoys using programming to bring ideas into reality. https://github.com/CSFM93