Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Get Started with Twilio Video Part 1: Creating a server with Node/Express


(warning)

Warning

This documentation is for reference only. We are no longer onboarding new customers to Programmable Video. Existing customers can continue to use the product until December 5, 2026(link takes you to an external page).

We recommend migrating your application to the API provided by our preferred video partner, Zoom. We've prepared this migration guide(link takes you to an external page) to assist you in minimizing any service disruption.

This is the first part of a two-part tutorial for creating a video web application with a Node/Express backend and a JavaScript frontend. In this section, you'll set up a backend server that creates free Twilio WebRTC Go video rooms and generates Access Tokens for video room participants. In part two, you'll create the frontend side of the application, where participants can join a video room and share their video and audio with other participants.

At the end of this full tutorial, you'll have a web application that allows you to join a two-person video room and video chat with another person.

If you have already completed the backend section of this tutorial, jump over to Part Two. Otherwise, let's get going!


Setup

setup page anchor

Requirements

requirements page anchor

Create the project directory

create-the-project-directory page anchor

Open a new terminal window and navigate to the directory where you want your project to live. Then, create a project folder and change into this directory:


_10
mkdir video_tutorial && cd video_tutorial

Collect account values and store them in a .env file

collect-account-values-and-store-them-in-a-env-file page anchor

To start, you'll need to collect a few values from the Twilio Console(link takes you to an external page) so that you can connect your application to Twilio. You will store these values in a .env file, and your server will read in these values.

Within the new project folder you created above, create a file called .env and open it in your preferred text editor.

The first value you'll need is your Account SID, which you can find in the Twilio Console(link takes you to an external page). Once you've gotten that value, store it in the .env file:


_10
TWILIO_ACCOUNT_SID=<your account sid>

Create an API Key

create-an-api-key page anchor

Next, you'll need to create an API key. This is what you'll use to authenticate with Twilio when making API calls.

You can create an API key using the Twilio CLI, the REST API, or the Twilio Console(link takes you to an external page). This tutorial will show how to generate it via the Console.

To generate the API Key from the Twilio Console:

When you've created the key, you'll see the friendly name, type, key SID, and API key secret.

(warning)

Warning

Make sure to copy the secret now, because you'll only be able to see it once. When you leave this page, you won't be able to see the secret again.

Copy the API Key ID and the API Key Secret and store both values in the .env file.


_10
TWILIO_ACCOUNT_SID=<your account sid>
_10
TWILIO_API_KEY_SID=<key sid>
_10
TWILIO_API_KEY_SECRET=<secret>

If you're using git for version control, make sure these credentials remain secure and out of version control. To do this, create a .gitignore file at the root of your project directory. In this file, you can list the files and directories that you want git to ignore from being tracked or committed.

Open the new .gitignore file in your code editor and add the .env file. While you're here, you can also add node_modules/, for the dependencies folder you'll install in the next step.


_10
.env
_10
node_modules/

Great! Now that you've stored those credentials and added the .env to .gitignore, you can move on to creating the Express server.

Install the dependencies

install-the-dependencies page anchor

First, set up a new Node.js project with a default package.json file by running the following command:


_10
npm init --yes

Once you have your package.json file, you're ready to install the needed dependencies.

For this project, you will need the following packages:

Run the following command to install the dependencies:


_10
npm install express twilio dotenv node-dev uuid

If you check your package.json file now, you'll notice that the packages above have been installed as dependencies.


You will need a server to generate Access Tokens (to grant participants permission to access a video room) and serve the frontend code that you'll build in Part Two of this tutorial. There are several options for creating web servers with Node.js, but this tutorial uses Express(link takes you to an external page).

This section walks through the general setup for a basic Express server. In the next section, you'll add the Twilio-specific code for creating video rooms.

First, create a new file called server.js at the root of the project directory. This will be the server file where you put all the core logic for your web server. Open that file in your text editor and copy and paste the following code into the file:


_23
require("dotenv").config();
_23
const { v4: uuidv4 } = require("uuid");
_23
const AccessToken = require("twilio").jwt.AccessToken;
_23
const VideoGrant = AccessToken.VideoGrant;
_23
const express = require("express");
_23
const app = express();
_23
const port = 5000;
_23
_23
// use the Express JSON middleware
_23
app.use(express.json());
_23
_23
_23
// create the twilioClient
_23
const twilioClient = require("twilio")(
_23
process.env.TWILIO_API_KEY_SID,
_23
process.env.TWILIO_API_KEY_SECRET,
_23
{ accountSid: process.env.TWILIO_ACCOUNT_SID }
_23
);
_23
_23
// Start the Express server
_23
app.listen(port, () => {
_23
console.log(`Express server running on port ${port}`);
_23
});

This code pulls in the required dependencies for the server, loads the environment variables from your .env file, starts a new Express application, and sets the application to run on port 5000. It also creates a Twilio client with the Twilio Node helper library. You'll use this client to communicate with Twilio.

At the bottom of the code, you start the Express server on port 5000.

Now, open package.json in your code editor. Inside the scripts section, add a start script as shown below. You can replace the test script that was automatically generated by npm init --yes earlier:


_10
"scripts": {
_10
"start": "node-dev server.js"
_10
},

To run the start script, return to your terminal window and run the following command:


_10
npm start

Once you have done this, you should see the following log statement in your terminal window, letting you know that the Express server is running:


_10
Express server running on port 5000


You'll use the twilioClient you created earlier in server.js, and write a function to create new video rooms.

In server.js, underneath where you created the twilioClient variable, paste in the following function:


_18
const findOrCreateRoom = async (roomName) => {
_18
try {
_18
// see if the room exists already. If it doesn't, this will throw
_18
// error 20404.
_18
await twilioClient.video.rooms(roomName).fetch();
_18
} catch (error) {
_18
// the room was not found, so create it
_18
if (error.code == 20404) {
_18
await twilioClient.video.rooms.create({
_18
uniqueName: roomName,
_18
type: "go",
_18
});
_18
} else {
_18
// let other errors bubble up
_18
throw error;
_18
}
_18
}
_18
};

In the code above, you create a function called findOrCreateRoom, which takes in a room name and checks if an in-progress video room with that name already exists for your account. If that room doesn't exist, you'll get Error 20404, which will indicate that you should create the room.

This function will create the room as a WebRTC Go room (type: "go"), which is a free room that can have up to two participants.

Eventually, you'll use this function to allow a participant to specify a room to either create or join. In the next section, you'll write a function to create an Access Token for a participant.

Here's the full server.js code with the new find_or_create_room function:


_41
require("dotenv").config();
_41
const { v4: uuidv4 } = require("uuid");
_41
const AccessToken = require("twilio").jwt.AccessToken;
_41
const VideoGrant = AccessToken.VideoGrant;
_41
const express = require("express");
_41
const app = express();
_41
const port = 5000;
_41
_41
// use the Express JSON middleware
_41
app.use(express.json());
_41
_41
// create the twilioClient
_41
const twilioClient = require("twilio")(
_41
process.env.TWILIO_API_KEY_SID,
_41
process.env.TWILIO_API_KEY_SECRET,
_41
{ accountSid: process.env.TWILIO_ACCOUNT_SID }
_41
);
_41
_41
const findOrCreateRoom = async (roomName) => {
_41
try {
_41
// see if the room exists already. If it doesn't, this will throw
_41
// error 20404.
_41
await twilioClient.video.rooms(roomName).fetch();
_41
} catch (error) {
_41
// the room was not found, so create it
_41
if (error.code == 20404) {
_41
await twilioClient.video.rooms.create({
_41
uniqueName: roomName,
_41
type: "go",
_41
});
_41
} else {
_41
// let other errors bubble up
_41
throw error;
_41
}
_41
}
_41
};
_41
_41
// Start the Express server
_41
app.listen(port, () => {
_41
console.log(`Express server running on port ${port}`);
_41
});


Generate an Access Token for a Participant

generate-an-access-token-for-a-participant page anchor

Now, you'll create a function that returns an Access Token for a participant. An Access Token gives a participant permission to join video rooms.

The Access Token will be in the JSON Web Token (JWT)(link takes you to an external page) standard. The Node Twilio helper library contains functions for creating and decoding these tokens in the JWT format.

Copy and paste the following getAccessToken function in server.js, under the findOrCreateRoom function:


_19
const getAccessToken = (roomName) => {
_19
// create an access token
_19
const token = new AccessToken(
_19
process.env.TWILIO_ACCOUNT_SID,
_19
process.env.TWILIO_API_KEY_SID,
_19
process.env.TWILIO_API_KEY_SECRET,
_19
// generate a random unique identity for this participant
_19
{ identity: uuidv4() }
_19
);
_19
// create a video grant for this specific room
_19
const videoGrant = new VideoGrant({
_19
room: roomName,
_19
});
_19
_19
// add the video grant
_19
token.addGrant(videoGrant);
_19
// serialize the token and return it
_19
return token.toJwt();
_19
};

The function does the following:

  • Takes in a room name
  • Creates an Access Token (in JWT(link takes you to an external page) format)

    • Generates a unique string for a participant's identity (see note below about the participant identity requirement)
  • Creates a Video Grant
  • Adds it to the Access Token
  • Returns the token in serialized format
(information)

Info

The participant identity doesn't need to be a random string — it could be a value like an email, a user's name, or a user ID. However, it does need to be a unique value for the specific room. You cannot create more than one token for a given participant identity in a room.

The Video Grant is important to add to the token, because it is the piece that allows a participant to connect to video rooms. You can limit the participant's access to a particular video room (which the code above does), or you can generate a token with general access to video rooms.

If you were going to connect this application with other Twilio services, such as Twilio Sync or Twilio Conversations(link takes you to an external page), you could create additional Sync or Conversation grants and add them to this token to allow access to those services as well.

Here's the full server code with the added getAccessToken function:


_61
require("dotenv").config();
_61
const { v4: uuidv4 } = require("uuid");
_61
const AccessToken = require("twilio").jwt.AccessToken;
_61
const VideoGrant = AccessToken.VideoGrant;
_61
const express = require("express");
_61
const app = express();
_61
const port = 5000;
_61
_61
// use the Express JSON middleware
_61
app.use(express.json());
_61
_61
// create the twilioClient
_61
const twilioClient = require("twilio")(
_61
process.env.TWILIO_API_KEY_SID,
_61
process.env.TWILIO_API_KEY_SECRET,
_61
{ accountSid: process.env.TWILIO_ACCOUNT_SID }
_61
);
_61
_61
const findOrCreateRoom = async (roomName) => {
_61
try {
_61
// see if the room exists already. If it doesn't, this will throw
_61
// error 20404.
_61
await twilioClient.video.rooms(roomName).fetch();
_61
} catch (error) {
_61
// the room was not found, so create it
_61
if (error.code == 20404) {
_61
await twilioClient.video.rooms.create({
_61
uniqueName: roomName,
_61
type: "go",
_61
});
_61
} else {
_61
// let other errors bubble up
_61
throw error;
_61
}
_61
}
_61
};
_61
_61
const getAccessToken = (roomName) => {
_61
// create an access token
_61
const token = new AccessToken(
_61
process.env.TWILIO_ACCOUNT_SID,
_61
process.env.TWILIO_API_KEY_SID,
_61
process.env.TWILIO_API_KEY_SECRET,
_61
// generate a random unique identity for this participant
_61
{ identity: uuidv4() }
_61
);
_61
// create a video grant for this specific room
_61
const videoGrant = new VideoGrant({
_61
room: roomName,
_61
});
_61
_61
// add the video grant
_61
token.addGrant(videoGrant);
_61
// serialize the token and return it
_61
return token.toJwt();
_61
};
_61
_61
// Start the Express server
_61
app.listen(port, () => {
_61
console.log(`Express server running on port ${port}`);
_61
});


Put it all together in a route

put-it-all-together-in-a-route page anchor

Next, you'll create a route called /join-room. In Part Two of this Tutorial, your frontend application will make a POST request to this /join-room route with a roomName in the body of the request.

Copy and paste the following code in server.js, underneath the route that returns "In progress!":


_14
app.post("/join-room", async (req, res) => {
_14
// return 400 if the request has an empty body or no roomName
_14
if (!req.body || !req.body.roomName) {
_14
return res.status(400).send("Must include roomName argument.");
_14
}
_14
const roomName = req.body.roomName;
_14
// find or create a room with the given roomName
_14
findOrCreateRoom(roomName);
_14
// generate an Access Token for a participant in this room
_14
const token = getAccessToken(roomName);
_14
res.send({
_14
token: token,
_14
});
_14
});

This route takes a POST request containing a JSON object with a room name, and then calls the find_or_create_room function and the get_access_token function. It returns the decoded Access Token, which is a JSON Web Token (JWT)(link takes you to an external page).

Here's the final server file with all of these pieces:


_76
require("dotenv").config();
_76
const { v4: uuidv4 } = require("uuid");
_76
const AccessToken = require("twilio").jwt.AccessToken;
_76
const VideoGrant = AccessToken.VideoGrant;
_76
const express = require("express");
_76
const app = express();
_76
const port = 5000;
_76
_76
// use the Express JSON middleware
_76
app.use(express.json());
_76
_76
// create the twilioClient
_76
const twilioClient = require("twilio")(
_76
process.env.TWILIO_API_KEY_SID,
_76
process.env.TWILIO_API_KEY_SECRET,
_76
{ accountSid: process.env.TWILIO_ACCOUNT_SID }
_76
);
_76
_76
const findOrCreateRoom = async (roomName) => {
_76
try {
_76
// see if the room exists already. If it doesn't, this will throw
_76
// error 20404.
_76
await twilioClient.video.rooms(roomName).fetch();
_76
} catch (error) {
_76
// the room was not found, so create it
_76
if (error.code == 20404) {
_76
await twilioClient.video.rooms.create({
_76
uniqueName: roomName,
_76
type: "go",
_76
});
_76
} else {
_76
// let other errors bubble up
_76
throw error;
_76
}
_76
}
_76
};
_76
_76
const getAccessToken = (roomName) => {
_76
// create an access token
_76
const token = new AccessToken(
_76
process.env.TWILIO_ACCOUNT_SID,
_76
process.env.TWILIO_API_KEY_SID,
_76
process.env.TWILIO_API_KEY_SECRET,
_76
// generate a random unique identity for this participant
_76
{ identity: uuidv4() }
_76
);
_76
// create a video grant for this specific room
_76
const videoGrant = new VideoGrant({
_76
room: roomName,
_76
});
_76
_76
// add the video grant
_76
token.addGrant(videoGrant);
_76
// serialize the token and return it
_76
return token.toJwt();
_76
};
_76
_76
app.post("/join-room", async (req, res) => {
_76
// return 400 if the request has an empty body or no roomName
_76
if (!req.body || !req.body.roomName) {
_76
return res.status(400).send("Must include roomName argument.");
_76
}
_76
const roomName = req.body.roomName;
_76
// find or create a room with the given roomName
_76
findOrCreateRoom(roomName);
_76
// generate an Access Token for a participant in this room
_76
const token = getAccessToken(roomName);
_76
res.send({
_76
token: token,
_76
});
_76
});
_76
_76
// Start the Express server
_76
app.listen(port, () => {
_76
console.log(`Express server running on port ${port}`);
_76
});

Test this new route by running the server (with the command npm start) and making a POST request to http://localhost:5000/join-room. You can use curl(link takes you to an external page), Postman(link takes you to an external page), HTTPie(link takes you to an external page), or another tool for making this request. To make the request using curl, run the following command in your terminal:


_10
curl -X POST http://localhost:5000/join-room \
_10
-H "Content-Type: application/json" \
_10
--data '{"roomName": "test room!"}'

You should receive output similar to the output below:


_10
{
_10
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImN0..."
_10
}

You can use the site jwt.io(link takes you to an external page) to inspect the token you received and see the different components that make up the Access Token. If you paste the token you received into the jwt.io debugger, it will decode the token and show you what the token includes. You should see that it contains a video grant for the specific room you created. The token will also include fields with other information you provided:

  • iss : your TWILIO_API_KEY_SID
  • sub : your TWILIO_ACCOUNT_SID
  • identity : the randomly generated uuid for the participant's identity

You now have a working backend server that will create video rooms and generate Access Tokens! You're done with this section of the tutorial and can move on to Part Two, where you'll create the frontend for this web app.


Rate this page: