Proxy Voice Calls Anonymously with Express, the Nexmo Voice API, and a Virtual Number

Published May 22, 2018 by Aaron Bassett

We’ve all been there: you’ve gotten out of your cab and a few minutes later you realise you’ve left your umbrella behind. Alternatively, you’re starving, staring out the window whenever you hear a car drive by, wondering where the food delivery you ordered an hour ago is.

Girl waiting on a delivery

Perhaps it’s the other way around. Maybe you’re making a delivery and you need some directions to the address.

In all these situations you’re going to need to call the other person, but you don’t want to be giving your phone number out to strangers. So instead you can use a virtual number which connects the two parties but is only usable for the duration of the current transaction.

Renting a Virtual Number

In this tutorial, we’re going to use the Nexmo CLI to rent our virtual number, but you can also manage your numbers and voice applications via the Nexmo dashboard if you’d prefer to use a GUI. If you haven’t done so already, you can install the Nexmo CLI via npm/yarn. Full instructions are in the Github repository.

At the time of writing, you can rent virtual numbers in 85 different countries. I’m going to use GB (Great Britain) in my example; you can see a complete list of countries and prices on our pricing page.

Creating Our Voice Proxy Server

At the moment if you attempt to call the virtual number we just rented, nothing happens.

Man on the phone

We have to associate the virtual number with an application. You can link multiple numbers to the same voice application, allowing you to have multiple numbers—even in different countries—all powered by a single backend.

In this example, we’re going to create our backend with Node and Express and deploy it on Glitch. You can view the code on Github or remix it directly on Glitch.

Remix on Glitch

Our Express server has a single endpoint, which looks like this:

The route defined above returns an NCCO (Nexmo Call Control Object), a JSON file which is used to provide instructions to the Nexmo API when someone answers an inbound or outbound call. An NCCO can contain many different types of actions. You can view the available actions in our developer docs.

Our proxy server requires a single action connect. With this we can proxy our incoming call to a range of different endpoints: another phone number, a WebSocket, or even a SIP URI. In the example above we connect to another phone number.

One of the requirements of the connect action is that the process.env.FROM_NUMBER must be a Nexmo Virtual Number. This virtual number is what your call recipient sees. You can use the same virtual number you rented above, that way your caller and callee see the same virtual number, keeping their numbers private.

When you remix the app, you need to configure the FROM_NUMBER and TO_NUMBER in your Glitch .env file. These numbers need to be in the E.164 format. We’re not using the EVENTS_URL in this example, but if you’re interested in how you can track analytics about your voice calls, then you should watch our webinar “Inbound Voice Call Campaign Tracking with Nexmo Virtual Numbers and Mixpanel” or read the accompanying blog post.

Linking Our Virtual Number to Our Proxy Server

To link our virtual number to our proxy server on Glitch we first need to create a Nexmo Voice Application. You can create a voice application and link it to your number using the Nexmo dashboard, or via the Nexmo CLI.

The Application Overview and the Nexmo CLI README contain more information on app:create and the expected arguments.

Where to Next?

Read the “private voice communication” tutorial for a more in-depth example. For an example of the proxy server in Kotlin, watch my webinar. Alternatively, for more information on what else you can do with Nexmo Voice APIs view our example use cases or read the developer documentation.

Leave a Reply

Your email address will not be published.

Get the latest posts from Nexmo’s next-generation communications blog delivered to your inbox.

By signing up to our communications blog, you accept our privacy policy , which sets out how we use your data and the rights you have in respect of your data. You can opt out of receiving our updates by clicking the unsubscribe link in the email or by emailing us at