---
"@context": https://schema.org
"@type": TechArticle
"@id": https://www.twilio.com/docs/video/node-getting-started#article
headline: Video Media SDK for Node.js quickstart
description: Connect to a Twilio Video Room from Node.js, publish a video track by pushing raw frames, and receive decoded frames from remote Participants.
url: https://www.twilio.com/docs/video/node-getting-started
inLanguage: en
dateModified: 2026-10-05T15:56:06.000Z
author:
  "@type": Organization
  name: Twilio Developer Education Team
publisher:
  "@type": Organization
  name: Twilio
---

# Video Media SDK for Node.js quickstart

> \[!IMPORTANT]
>
> The Video Media SDK for Node.js is currently available as a Public Beta product and the information contained in this document is subject to change. This means that some features are not yet implemented and others may be changed before the product is declared as Generally Available. Public Beta products are not covered by the Twilio Support Terms or [Twilio Service Level Agreement][sla].
>
> The Video Media SDK for Node.js is not a US [*Health Insurance Portability and Accountability Act* (HIPAA)][hipaa] Eligible Service or [*Payment Card Industry Data Security Standard* (PCI DSS)][pci] compliant and should not be enabled in workflows that are subject to HIPAA or PCI.

[hipaa]: https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act

[pci]: https://en.wikipedia.org/wiki/Payment_Card_Industry_Data_Security_Standard

[sla]: https://help.twilio.com/articles/115002413087-Twilio-Beta-product-support

This quickstart shows how to connect to a Video Room from a Node.js server, publish a video track by pushing raw frames, and receive decoded frames from remote Participants. To learn what the SDK is and how it differs from the client-side SDKs, see the [Overview][].

## Prerequisites

To use the Video Media SDK, you need the following prerequisites:

* [Create a Twilio account][].
* Install Node.js version 24.0.0 or later on Linux x86-64, or on macOS x86-64 for local development. On an Apple Silicon Mac, you need an x64 build of Node.js. To learn more, see [system requirements][].
* Create an API key SID and secret.

  #### View how to create an API Key

  ## Twilio Console

  1. Go to the [Twilio Console][1c]. The **Let's get building** page appears.
  2. Click **API keys and Auth tokens**. The **API keys & auth tokens** page appears with the **Auth Tokens** tab selected.
  3. Scroll to your **Account SID**.
  4. Click the copy button next to your **Account SID**.
  5. Run the following command, replacing `YOUR_ACCOUNT_SID` with *your* Account SID.

     ## macOS Terminal

     ```bash
     export TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
     ```

     ## Windows command line

     ```bash
     setx TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
     ```

     ## PowerShell

     ```bash
     [System.Environment]::SetEnvironmentVariable("TWILIO_ACCOUNT_SID", "YOUR_ACCOUNT_SID", "User")
     ```

     This command creates an environment variable on your development system for your account SID.
  6. To display the Auth Token, click the eye button in the **Primary auth token** box.
  7. Highlight and copy the Auth Token.
  8. Run the following command, replacing `YOUR_AUTH_TOKEN` with *your* Authentication Token.

     ## macOS Terminal

     ```bash
     export TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN
     ```

     ## Windows command line

     ```bash
     setx TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN
     ```

     ## PowerShell

     ```bash
     [System.Environment]::SetEnvironmentVariable("TWILIO_AUTH_TOKEN", "YOUR_AUTH_TOKEN", "User")
     ```

     This command creates an environment variable on your development system for your auth token.

  ## macOS Terminal

  ```bash
  export TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
  ```

  ## Windows command line

  ```bash
  setx TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
  ```

  ## PowerShell

  ```bash
  [System.Environment]::SetEnvironmentVariable("TWILIO_ACCOUNT_SID", "YOUR_ACCOUNT_SID", "User")
  ```

  ## macOS Terminal

  ```bash
  export TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN
  ```

  ## Windows command line

  ```bash
  setx TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN
  ```

  ## PowerShell

  ```bash
  [System.Environment]::SetEnvironmentVariable("TWILIO_AUTH_TOKEN", "YOUR_AUTH_TOKEN", "User")
  ```

  ## Legacy Console

  1. Go to the [Twilio Console][lc]. The **Get Started with Twilio** page appears.
  2. Scroll to the **Account Info** block.
  3. Click the copy button next to your **Account SID**.
  4. Run the following command, replacing `YOUR_ACCOUNT_SID` with *your* Account SID.

     ## macOS Terminal

     ```bash
     export TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
     ```

     ## Windows command line

     ```bash
     set TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
     ```

     ## PowerShell

     ```bash
     $Env:TWILIO_ACCOUNT_SID="YOUR_ACCOUNT_SID"
     ```
  5. Click the copy button next to your **Auth Token**.
  6. Run the following command, replacing `YOUR_AUTH_TOKEN` with *your* Authentication Token.

     ## macOS Terminal

     ```bash
     export TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN
     ```

     ## Windows command line

     ```bash
     set TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN
     ```

     ## PowerShell

     ```bash
     $Env:TWILIO_AUTH_TOKEN="YOUR_AUTH_TOKEN"
     ```

     This command creates an environment variable on your development system for your Authentication Token.

  ## macOS Terminal

  ```bash
  export TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
  ```

  ## Windows command line

  ```bash
  set TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
  ```

  ## PowerShell

  ```bash
  $Env:TWILIO_ACCOUNT_SID="YOUR_ACCOUNT_SID"
  ```

  ## macOS Terminal

  ```bash
  export TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN
  ```

  ## Windows command line

  ```bash
  set TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN
  ```

  ## PowerShell

  ```bash
  $Env:TWILIO_AUTH_TOKEN="YOUR_AUTH_TOKEN"
  ```

  [1c]: https://1console.twilio.com/go?to=/account/__account__

  [lc]: https://console.twilio.com
* To run the [`virtual_camera.js`][] example, install [FFmpeg][] and make sure `ffmpeg` is on your `PATH`. On macOS, run `brew install ffmpeg`. On Debian or Ubuntu, run `sudo apt install ffmpeg`.

## Install the SDK

1. Install the SDK and the Twilio helper library:
   ```bash
   npm install twilio
   npm install @twilio/video-node-sdk
   ```
   You use the `twilio` helper library to create Access Tokens.
2. In your app, add the import statement for the SDK:
   ```javascript
   const { connect, createLocalVideoTrack } = require('@twilio/video-node-sdk');
   ```

## Create an Access Token

The `connect()` function takes a standard Twilio Video Access Token with a `VideoGrant`, the same token format the JavaScript SDK uses. [Generate an Access Token][] on your server with the [`twilio` helper library][].

```javascript title="Create an access token example"
const twilio = require('twilio');

function generateToken(identity, roomName) {
  const token = new twilio.jwt.AccessToken(
    process.env.TWILIO_ACCOUNT_SID,
    process.env.TWILIO_API_KEY,
    process.env.TWILIO_API_SECRET,
    { identity, ttl: 3600 },
  );
  token.addGrant(new twilio.jwt.AccessToken.VideoGrant({ room: roomName }));
  return token.toJwt();
}
```

> \[!WARNING]
>
> Keep your API key secret on the server. Never ship Twilio credentials in client-side code or commit the controls to source control.

## Connect to a Room

Create a local video track, and then pass it to `connect()`. The returned promise resolves after the Room connects. Because `connect()` returns a promise, call it from an `async` function. The code in the following sections runs inside that function.

```javascript title="Connect to a Room example"
// !focus(4,6:9)
const { connect, createLocalVideoTrack } = require('@twilio/video-node-sdk');

async function main() {
  const videoTrack = createLocalVideoTrack('virtual-camera');

  const room = await connect(generateToken('node-participant', 'my-room'), {
    name: 'my-room',
    videoTracks: [videoTrack],
  });

  console.log('Connected to Room:', room.name, room.sid);

  // Add the code from the following sections here.
}

main().catch(err => {
  console.error('Error:', err);
  process.exit(1);
});
```

## Send video frames

Unlike the client-side SDKs, a local track lacks a camera. To supply raw [I420][] video frames, call the `write()` method on the track. Each call takes the frame dimensions and the `y`, `u`, and `v` planes. Each plane object contains its `data` as a `Buffer`, its `stride`, and its own `width` and `height`.

```javascript title="Send video example"
videoTrack.write({
  format: 'I420',
  width: 1280,
  height: 720,
  y: { data: yPlane, stride: 1280, width: 1280, height: 720 },
  u: { data: uPlane, stride: 640, width: 640, height: 360 },
  v: { data: vPlane, stride: 640, width: 640, height: 360 },
});
```

> \[!NOTE]
>
> Wait for `connect()` to resolve, and then send frames. The SDK drops any video frames that you write before then. Start your send loop after the `await` returns.

To learn about I420 video planes and strides and PCM audio, see [Work with media frames][].

## Receive media from remote Participants

Remote media arrives as raw decoded frames. Listen for `trackSubscribed`, then read frames from each video or audio track with the `frames()` async iterator.

```javascript title="Receive media example"
async function trackSubscribed(track) {
  if (track.kind !== 'video') return;
  try {
    // Frames that arrive while you process one are queued, and the SDK drops
    // them if the queue fills. The loop ends by itself when the track is
    // unsubscribed or the Room disconnects.
    for await (const frame of track.frames()) {
      console.log(`${frame.width}x${frame.height} @ ${frame.timestamp}us`);
      frame.close?.();
    }
  } catch (err) {
    // Nothing awaits this function, so an error that escapes here becomes an
    // unhandled rejection and stops the process.
    console.error('Frame loop failed:', err);
  }
}

function participantConnected(participant) {
  participant.on('trackSubscribed', trackSubscribed);

  participant.tracks.forEach(publication => {
    if (publication.isSubscribed) {
      trackSubscribed(publication.track);
    }
  });
}

// participantConnected doesn't fire for Participants already in the Room, and a
// track can finish subscribing before the trackSubscribed listener is attached.
// Call participantConnected for each Participant in room.participants, and check
// isSubscribed on each publication.
room.participants.forEach(participantConnected);
room.on('participantConnected', participantConnected);

room.on('disconnected', () => {
  room.dispose();
});
```

When you finish with a Room, call `room.dispose()`. Until you do, the Node.js process doesn't exit. Call it with the `disconnected` event, as in the preceding example.

## Run a working example

The [SDK repository][] includes runnable examples. The [`virtual_camera.js`][] example decodes an MP4 with `ffmpeg` and sends its frames into a Room.

```bash
git clone https://github.com/twilio/twilio-video-node.git
cd twilio-video-node
npm install --prefix examples
cp .env.example .env
# Edit .env and set TWILIO_ACCOUNT_SID, TWILIO_API_KEY, and TWILIO_API_SECRET.
node examples/virtual_camera.js my-room
```

To review every example, see the [`examples` directory][].

## Next steps

* [Work with media frames][]: Learn the I420 video and PCM audio frame formats in depth.
* [Differences from the JavaScript SDK][]: Map what you know from the browser SDK to the server.
* [Best practices][]: Pace frames, manage resources, and troubleshoot common issues.

[`examples` directory]: https://github.com/twilio/twilio-video-node/tree/main/examples

[`twilio` helper library]: https://www.npmjs.com/package/twilio

[`virtual_camera.js`]: https://github.com/twilio/twilio-video-node/blob/main/examples/virtual_camera.js

[Best practices]: /docs/video/node-best-practices

[Create a Twilio account]: https://www.twilio.com/try-twilio

[Differences from the JavaScript SDK]: /docs/video/node-differences-from-javascript-sdk

[FFmpeg]: https://ffmpeg.org/download.html

[Generate an Access Token]: /docs/video/tutorials/user-identity-access-tokens

[i420]: /docs/glossary/i420

[Overview]: /docs/video/node

[SDK repository]: https://github.com/twilio/twilio-video-node/tree/main/examples

[system requirements]: /docs/video/node#system-requirements

[Work with media frames]: /docs/video/node-working-with-media-frames
