Updating Twilio phone calls in real time with Node.js

November 14, 2019
Written by
Sam Agnew
Twilion

Copy of Generic Blog Header 2.png

Twilio use TwiML to programmatically define the actions that take place during a phone call. But this doesn't have to be a rigid script that every call follows. You can also use the Twilio REST API to update these phone calls in real time.

For example, given a Call SID, a unique identifier to a phone call resource, you can redirect which TwiML the phone call is using with the following code:

const client = require('twilio')();

client.calls('CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  .update({method: 'POST', url: 'http://demo.twilio.com/docs/voice.xml'})

Let's walk through how to set up a Twilio phone number to receive phone calls, and test this out for yourself.

Development Environment Setup

Start by making sure you have the right software installed and set up that you'll need to use for the rest of this post. Throughout this post, you will need:

Here is a good guide to follow in general if you are going to be doing more with Twilio and Node.js and have any more questions.

To install these npm modules, navigate to the directory where you want this code to live and run the following command in your terminal to create an npm package for this project.

npm init --yes

The --yes argument just runs through all of the prompts that you would otherwise have to fill out or skip. Now that we have a package.json for our app, let’s install the necessary libraries with the following shell commands:

npm install twilio@3.33.0 --save
npm install express@4.17.0 --save

After this you should be good to write some code!

Setting up an Express server to receive the incoming call

Open a file called index.js in the same directory as your package.json and add the following code to it:

const http = require('http');
const express = require('express');
const { urlencoded } = require('body-parser');
const VoiceResponse = require('twilio').twiml.VoiceResponse;

const app = express();
app.use(urlencoded({ extended: false }));

app.post('/call', (req, res) => {
  const twiml = new VoiceResponse();

  // Print the Call SID so that we can use it to update the call later.
  console.log(`${req.body.CallSid}`);

  twiml.say('Please wait.');

   // Do nothing until the call is asynchronously updated.
  twiml.pause({
    length: 100
  });

  res.writeHead(200, {'Content-Type': 'text/xml'});
  res.end(twiml.toString());
});

http.createServer(app).listen(3000, () => {
  console.log('Express server listening on port 3000');
});

This code sets up an Express app, defines a route on the app to handle incoming phone calls, and then has it listen on port 3000 for incoming requests. In the /call route, we are responding to the HTTP request Twilio sends when a phone call is received with some TwiML that tells Twilio to pause for 100 seconds. We're going to have the call do nothing until the call is updated and redirected to another URL.

You can run this code with the following command:

node index.js

Leave this Express app running in your terminal because we will use it in a little bit.

Setting up your Twilio account

Before being able to receive phone calls, you’ll need a Twilio phone number. You can buy a phone number here (it’s free if you’re using the number to test your code during development).

Your Express app will need to be visible from the internet in order for Twilio to send requests to it. We will use ngrok for this, which you’ll need to install if you don’t have it already. In your terminal run the following command:

ngrok http 3000

If you’ve just installed ngrok and that previous command didn’t work, you might have to run it like ./ngrok http 3000 from the directory that the ngrok executable is in.

ngrok forwarding url

This provides us with a publicly accessible URL to the Express app. Configure your phone number in your Twilio Console as seen in this image by adding your ngrok URL with "/call" appended to it to the "A Call Comes In" section:

Configuring your phone number

You are now ready to receive a phone call to your new Twilio number. If you call now, the phone call will be answered, but nothing else will happen until we update the call using the Twilio REST API.

Asynchronously updating the phone call

All we need to update a Twilio phone call is the Call SID, a unique identifier for the call. In the previous code for the Express app that answers a phone call, we are printing the call SID for this purpose once the call is received.

When updating a live call, there are three things you can do:

  1. Redirect the call to a new URL that provides updated TwiML to use.
  2. Directly give TwiML to update the call.
  3. End the call automatically.

Let's walk through all of these. Before running any of the following code samples, make sure to grab your Account SID and Auth Token from your Twilio Console, and save them as environment variables named TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN, which the Twilio Node library will grab automatically when you run your code.

In a new terminal window, enter the node command in the same directory as your index.js file. Call your Twilio Phone number, and then enter the following code in your console to redirect it to a TwiML URL that we use in the Twilio documentation, remembering to replace the Call SID with the value printed by your Express app when you made the phone call:

const client = require('twilio')();

client.calls('CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  .update({method: 'POST', url: 'http://demo.twilio.com/docs/voice.xml'})

Now do the same thing, but with code that tells Twilio directly which TwiML to use:

const client = require('twilio')();

client.calls('CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  .update({twiml: '<Response><Say>Ahoy there</Say></Response>'});

There's no music this time, but you should hear a robot voice when the call updates. Now let's try simply ending a phone call in progress:

const client = require('twilio')();

client.calls('CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  .update({status: 'completed'});

What can I use this for?

Now that you know how to update calls in real time, you can create waiting room functionality, or have asynchronous tasks change what is happening on phone calls as other parts of your app work on heavier computation without leaving the phone call hanging.

I’m looking forward to seeing what you build. Feel free to reach out and share your experiences or ask any questions.

  • Email: sagnew@twilio.com
  • Twitter: @Sagnewshreds
  • Github: Sagnew
  • Twitch (streaming live code): Sagnewshreds