How to control and record voice calls with Node.js serverless functions
Tags: javascript, serverless
Published: 2019-05-13 20:15:07

---
title: How to control and record voice calls with Node.js serverless functions
published: true
tags: javascript, serverless
canonical_url: https://www.twilio.com/blog/control-and-record-voice-messages-with-node-js-serverless-functions
---

There are many ways to communicate with your friends and family. You might use good old SMS, Whatsapp, emails and of course phone calls. Recently, I came across a surprising new way of communication. It all started with [my friend Michaela asking a question on Twitter.](https://mobile.twitter.com/FischaelaMeer/status/1117718863095922689)

> Would it be possible to generate an RSS feed out of Twilio voice calls?

What she was looking for was a way to transform phone calls into an RSS feed referencing the recorded phone call. Why? Because she listens to many podcasts and sends very long voice messages to one of her friends via Whatsapp. As these messages usually don’t need a timely response, they both would prefer all the voice messages appear in their podcatchers rather than Whatsapp.

Let me introduce you to the idea of [“PodBot - the surprise podcast from your friends”](https://podbot.netlify.com).

![Podbot preview in a browser window](https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/68he8yLdDsMp_AXDMeAZiQMsLe0wPJ5rK7Ov575PhY6PtT.width-800.jpg)

The idea is a follows: All you have to do to publish a new podcast episode is to make a phone call. There is no need for a microphone setup, and you wouldn’t need to record, store or upload audio files to a podcast platform.

## Requirements for a voice call driven podcast site

To create a phone call driven podcast site you need several things.

You need a phone number that you can control programmatically. Luckily, [Twilio Voice](https://www.twilio.com/voice) provides this exact functionality.

Additionally, you need a way to store the information and transcriptions of the incoming phone calls. [Google sheets](https://www.youtube.com/watch?v=UGN6EUi4Yio) or cloud databases can be used with Node.js and thus can provide a quick data store used in [Twilio Serverless Functions](https://www.twilio.com/functions).

Moreover, you need a site hoster that can serve your podcast site and feed.

Configuring programmable voice calls, downloading audio files and building a site with all the information is a lot of work. That’s why we split building _PodBot_ and all its tasks into several tutorials.

In this first tutorial, we’ll use Twilio serverless functions to accept and manage phone calls, recordings, and voice transcriptions. In later tutorials, we’ll extend the functions to write to a data store, and we’ll use this data to build the podcast site using [Gatsby](https://www.gatsbyjs.org/), including the mandatory RSS podcast feed. Sound good? Let’s get started writing functions, then! 🎉

Here’s what you need today:

- A Twilio account to buy a phone number and accept calls
- Node.js and npm installed

## Function-driven voice calls to the rescue

To define what happens when someone calls a Twilio phone number you have to provide some configuration in an XML-based format that is called [TwiML](https://www.twilio.com/docs/glossary/what-is-twilio-markup-language-twiml). The Twilio API requests this configuration right at the moment a call comes in. You can serve TwiML via [TwiML bins](https://www.twilio.com/blog/2017/11/twiml-bins-a-serverless-and-codeless-way-to-try-twilio.html), your custom-tailored application via webhooks, or serverless functions.

Before we implement this functionality, let’s recap and think about what we need to build. When someone calls _PodBot_ we need to gather the following episode information:

- the title
- the recording URL
- the episode transcription

Luckily, Twilio provides ways to retrieve all this call information. Below you see the TwiML configuration to ask for the episode title, record it and get a transcript of the recording.

![Graphic showing the call flow with serverless functions](https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/sSm5imNV5rilVnwDdcchaXZnin3BhwF3rsVziYxcMhv_Cg.width-800.jpg)

Let’s go into detail; when someone calls your Twilio number (step 1), Twilio asks your defined serverless functions for some TwiML configuration (step 2). The responded TwiML defines to ask for the title of the episode and to record the answer (step 3). Information about the complete recording should be sent to a `/call-exit/` endpoint. The response of `/call-exit/` will control what happens next by responding with more TwiML. The initial TwiML also specifies that the generated transcript should be sent to `/transcribe-title/`.

After Twilio receives this initial TwiML configuration, PodBot speaks to the caller saying “Tell me the title of your episode.” (step 4). Then it waits and records the answer until five seconds of silence has passed. Magic? Magic!

TwiML configurations like the one above can be chained together. This option makes it possible to ask for the episode title and record it followed by another action to end the phone call or to record more data like the episode itself.

Let’s set up the call handling in a new project. 🎉

**To keep this tutorial crisp and short we’ll only record and transcribe the episode title. You can find a solution at the end of the article that you can tweak to your needs and run locally quickly.**

### The creation of serverless functions

Create a new directory for this project and also create three JavaScript files in the `functions` directory: `call-enter.js`, `transcribe-title.js` and `call-exit.js`.

```bash
$ mkdir podbot-functions
$ cd podbot-functions
$ mkdir functions
$ touch functions/call-enter.js functions/transcribe-title.js functions/call-exit.js
```

Each of these JavaScript files represents one HTTP endpoint. These endpoints have to respond with TwiML when the Twilio API asks for the configuration. To build a TwiML response you can use the [Twilio JS client](https://www.npmjs.com/package/twilio-js) which is available globally in Twilio functions.

### The serverless entry point of your phone calls

`call-enter.js` is the first endpoint Twilio requests when someone calls your number.

```javascript
// File: /functions/call-enter.js
'use strict';

exports.handler = function(context, event, callback) {
  let response = new Twilio.twiml.VoiceResponse();

  // documentation for say
  // -> https://www.twilio.com/docs/voice/twiml/say 
  response.say(
    { voice: 'woman', language: 'en-US' },
    'Welcome to PodBot. Tell me the title of your episode.'
  ); 

  // documentation for record
  // -> https://www.twilio.com/docs/voice/twiml/record   
  response.record({
    action: '/call-exit',
    timeout: '5',
    transcribe: 'true',
    transcribeCallback: '/transcribe-title'
  }); 
  
  callback(null, response);
};
```

The above defined serverless function will be called [with `context`, `event` and a `callback`](https://www.twilio.com/docs/runtime/functions/invocation#handler-arguments). The `context` object provides information about the current execution environment, `event` contains the request parameters passed into your function, and you can use the `callback` to respond to the request.

By calling the `callback` with `null` as the first argument, you signal that there were no errors. The second argument is a `VoiceResponse` which you can create by using the global `Twilio` object.

By defining the `Record` verb and its included `action` attribute, the second endpoint will be called after the caller is silent for five seconds.

Additionally, `transcribeCallback` defines the endpoint to retrieve the transcription when it’s ready.

### Log the recording and say goodbye

After the caller gives the name of the episode and remains silent for 5 seconds, the next endpoint (`/call-exit/`) is called to request additional configuration and continue the phone call.

```javascript
// File: /functions/call-exit.js
'use strict';

exports.handler = function(context, event, callback) { 
  // do something with the data here 
  console.log(event.CallSid, event.RecordingUrl); 
  // CallSid: ‘CA3ac5f19...’
  // RecordingUrl: ‘https://api.twilio.com/2010-04-01/Accounts/ACa3.../Recordings/RE92...’ 
  
  const response = new Twilio.twiml.VoiceResponse();
  
  // documentation for say 
  // -> https://www.twilio.com/docs/voice/twiml/say 
  response.say({ voice: 'woman', language: 'en-US' }, 'Thanks');
  callback(null, response);
};
```

Above you see the first important part of logging phone calls in serverless functions. Using the `event` object, you can access the data Twilio included in the request. The `CallSid` is a unique identifier for the phone call. This identifier stays the same for a phone call across the three functions.

The recording URL is also accessible. To request the recording in MP3 format, append `.mp3` to the `RecordingUrl` property of the `event` object.

Right now this function only logs the information, but with `CallSid` and `RecordingUrl` available you can store this data in a database or other stores.

To finish the phone call, configure the `VoiceResponse` to say “Thanks”.

### The transcript logging

The last function you need is `transcribe-title.js`. The `/transcribe-title/` endpoint’s only job is to log the transcript of the episode title. It doesn’t have to provide any additional configuration. Call `callback` with `null` to signal that there were no errors and you’re good to go.

```javascript
// File: /functions/transcribe-title.js
'use strict';

exports.handler = function(context, event, callback) {
  // do something with the data here
  console.log(event.CallSid, event.TranscriptionText);
  // CallSid: ‘CA3ac5f19...’
  // RecordingUrl: “Hello everybody I hope...”
  callback(null);
};
```

At this point, you have three endpoints in place that can accept and control Twilio voice messages and log the recording URL and a transcript. With this setup, it’s time to test these with your first phone call.

## Run Twilio functions locally

To run Twilio functions locally, you can use [twilio-run](https://www.npmjs.com/package/twilio-run). You can install the tool into your project but thanks to [npx](https://www.npmjs.com/package/npx), which comes with recent npm version, all you have to do is to run a single command in the root of your project directory.

```bash
$ npx twilio-run --live
```

This command downloads `npm-run` if it’s not available in your environment and runs it. `twilio-run` looks for a `functions` directory which you have already prepared. The `--live` flag makes sure that the functions won’t be cached when a local server is started. This flag allows you to write functions without the need for a command restart.

![Terminal showing the local functions endpoints](https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/RHC243fddMbVU_UtU0crMb8sQyXm1yl3RrB8WYgkENpPJf.width-800.jpg)

After running the command, the local server is started to debug and test your functions. Unfortunately, your localhost is not accessible on the internet. That’s the reason why `twilio-run` comes with another nifty configuration. If you run it with the `--ngrok` flag, it automatically spins up a publicly available URL which tunnels all requests to your local machine.

```bash
$ npx twilio-run --live --ngrok
```

![Terminal showing the live endpoints of Twilio run](https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/v5d1UZF7vPtFh8QC_6o3oXoD33MMnq3EEgYu9B2jQR9x9c.width-800.jpg)

The provided URLs are what you need finally set up your call handling.

## Connect your Twilio number with serverless functions

[After you buy a number](https://support.twilio.com/hc/en-us/articles/223135247-How-to-Search-for-and-Buy-a-Twilio-Phone-Number-from-Console), you can set it up to use your local functions when a call comes in. On the configuration page for a particular number, you’ll find the setting for incoming calls. Select the webhook option for incoming calls and copy/paste the public URL for `/call-enter/`. Hit

“save” and call your number.

![Number configuration to call local function when I call comes in](https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/4dNh107dx4IMF69hk-8XwCFg8zyflUGZ7ZKI0hv2ZE1NWn.width-800.jpg)

When you call your number and tell PodBot the title of the podcast episode you should see the `CallSid`, `RecordingUrl`, and `TranscriptionText` logged to your terminal.

![Terminal showing the call logs including sid and transcript](https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/jwO03-JbTJzDz3jr3bVyP0fS4eDqrsxp3IUwlEsUAR39-1.width-800.jpg)

Using `twilio-run` you can develop functions in your local environment right from the command line. If you’re happy with the functionality of your local functions, you can then move them to [the functions area in your Twilio console](https://www.twilio.com/console/runtime/functions/manage) and adjust your number to use your functions instead of webhooks.

![Overview of pasted functions in Twilio console and set call handling in number configuration](https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/ucLO49bM_aJpSEOgGZwPHPbGRZMe0vAhFBS8OuXUdoPYqi.width-800.jpg)

After you move the functions to Twilio and adjust the incoming call handling, you have a voice bot running in the cloud that is ready to log information for further usage. At that point, you'll no longer require a local setup.

This tutorial was the first step of building PodBot. With these three functions, you’re able to manage and log phone calls using Twilio. If you want to play around with it, you can check out my [podbot-functions](https://github.com/stefanjudis/podbot-functions) repo on GitHub or have a look at [the function docs](https://www.twilio.com/docs/runtime/functions).

If you want to start your own podcast business or just want to say “Hi” you can reach me under the social channels below.