by opentok



Tokbox is now known as Vonage

Build Status codecov

OpenTokRTC is your private web-based video conferencing solution. It is based on the TokBox OpenTok platform and uses the OpenTok SDKs and API. You can deploy OpenTokRTC on your servers to get your own Google Hangouts alternative running on WebRTC.

This repository contains a Node.js server and a web client application.

Table of Contents


If you want to install OpenTokRTC on your own server, read on. If you want to deploy OpenTokRTC to Heroku, see


You will need these dependencies installed on your machine:

  • NodeJS v8+: This version of OpenTokRTC is tested with NodeJS v8 LTS.
  • Redis: A redis server running on localhost.
  • Grunt: Used for bundling assets and running tests. You can install the Grunt CLI globally by running:
    # npm i -g grunt-cli.

You will also need these API subscriptions:

  • OpenTok: An OpenTok API key and secret. You can obtain these by signing up with Opentok/Vonage.
  • Firebase (Optional): A Firebase app and secret. Firebase is used for storing archive data of video conferences. You will need this only if you want to enable Archive Management (In-app playback and download of recordings) of conference rooms.

Setting up

Once all the dependencies are in place, you will need to set some configuration options and install the applications dependencies.

First, change directory to where you have downloaded OpenTokRTC. Then create create the file config.json in the config folder. You can copy config/example.json to config/config.json

$ cd <path-to-opentok-rtc>
$ cp config/example.json config/config.json

Edit configuration file

Edit config/config.json and replace <key> and <secret> with your OpenTok API key and the corresponding API secret:

    "OpenTok": {
        "apiKey": "<key>"
        "apiSecret": "<secret>"

If you want to use archive management, set up Firebase configuration. To do these, edit the configuration sections for "Firebase" and "Archiving". Replace <firebase_url> with a Firebase database URL and <firebase_secret> with a corresponding database secret. Also mark Archiving and archivingManager as enabled. For more information on how to obtain Firebase credentials, see Firebase configuration section below:

    "Firebase": {
        "dataUrl": "<firebase_url>",
        "authSecret": "<firebase_secret>"
    "Archiving": {
        "enabled": true,
        "archiveManager": {
            "enabled": true

For more configuration options, see detailed configuration options below:

Next, set up the dependencies for the server:

$ npm install

Note: You will need to run these commands as a non-root user, else bower will refuse to execute.


Ensure that Redis server is running on localhost (run redis-server). Start the application in foreground by running:

$ node server

This will start the application on port 8123 by default.

To specify a custom port number, use the -p flag when calling node server, e.g., to run the application on port 8080:

$ node server -p 8080

Additionally, you can start the application as a daemon by passing -d flag, which starts the application and keeps it running in the background so that your terminal is not blocked, e.g.:

$ node server -d

To start the server with HTTPS enabled, pass -S flag to launch a secure server along with -C <dir> flag to specify a directory that holds SSL certificate files. To quickly start a secure server, run:

$ node server -S -C sampleCerts

The server expects SSL certificate file to be named serverCert.pem and SSL private key file to be named serverKey.pem. There is a pre-generated, self-signed SSL certificate pair in the ./sampleCerts directory.

For detailed information on available options, run $ node server -h.

Configuration options

Configuration can be done using the config JSON file, or environment variables which overwrite any JSON value read. The default JSON file is config/config.json. This path can be overwritten using the Environment Variable DEFAULT_JSON_CONFIG_PATH. These are the detailed configuration options:

OpenTok configuration

Environment Variable Names and Description:

  • TB_API_KEY (Required): Your OpenTok API key.
  • TB_API_SECRET (Required): Your OpenTok API Secret.
  • TB_JS_URL (Optional): The OpenTok.js URL to be loaded by the app. The default value is "". Enterprise partners should set this to the URL for the enterprise version of OpenTok.js ("").
  • TB_MAX_SESSION_AGE (Optional, default value 2): Sessions should not live forever. So we'll store the last time a session was used and if when we fetch it from Redis we determine it's older than this max age (in days). This is the key where that value (in days) should be stored. By default, sessions live two days.

JSON example:

"OpenTok": {
  "apiKey": "<key>",
  "apiSecret": "<secret>",
  "jsUrl": "",
  "maxSessionAge": 2

Firebase configuration

This application needs you to specify a Firebase database URL and a database secret. Here is how you can obtain both.

Go to Firebase console, create a new project or choose an existing project. Once there, follow these steps:

  • Firebase database URL: Click on Database link on the left. Copy the URL you see under the Data tab. The URL is in the format where xxxx is the unique ID of your Firebase project.

    Note: For the security rule mentioned in the Firebase security measure section to work, you will need to set the Firebase database URL in this application configuration as

  • Firebase database secret: Click on the Settings (cog) icon and go to Project Settings > Service Accounts > Database Secrets. Click on the Show button for the secret and copy it.

Then set the following values in config/config.json, replacing <firebase_url> with the Firebase database URL and <firebase_secret> with the Firebase database secret:

"Firebase": {
    "dataUrl": "<firebase_url>",
    "authSecret": "<firebase_secret>"

You can also set the values using these environment variables:

  • FB_DATA_URL: Firebase database URL.
  • FB_AUTH_SECRET: Firebase database secret.

Firebase security measure

If you want to ensure that the archive list is kept secure (as in only the actual people using a room can see it, and nobody can see the list of archives of other rooms) then you will need to configure additional security parameters to your Firebase application. To do this, log in to Firebase console, go to your project, then in Database > Rules set these rules and hit Publish:

    "rules": {
        ".read": "auth != null && auth.role == 'server'",
        ".write": "auth != null && auth.role == 'server'",
        "$sessionId": {
            ".read": "auth != null && (auth.role == 'server' || auth.sessionId == $sessionId)",
            ".write": "auth != null && auth.role == 'server'",
            "archives": {},
            "connections": {
                ".read": "auth != null && auth.role == 'server'",
                ".write": "auth != null && (auth.role == 'server' || auth.sessionId == $sessionId)",
                "$connectionId": {}

Phone dial-out

The app can dial out and add a phone-based end user to the OpenTok session, using the OpenTok SIP API. This app uses Nexmo as the SIP application that connects to OpenTok. (You can also use the OpenTok SIP API to connect to other SIP endpoints.)

To enable this feature:

  1. Sign up for a Nexmo/Vonage account.

  2. Edit config/config.json file in this application, and add the following properties:

  • SIP.enabled -- Set this to true.

  • SIP.username -- Set this to the apiKey for the Nexmo account you created.

  • SIP.password -- Set this to the apiSecret for the Nexmo account you created.

  • SIP.requireGoogleAuth -- See Google Authentication for Phone dial-out for instructions on how to limit this functionality to users authenticated by their google account.

For example, the new lines in the config.json file should look like this:

       "SIP": {
         "sipUri" : "",
         "sipUsername" : "nexmoApiKey",
         "sipPassword" : "nexmoApiSecret",
         "requireGoogleAuth": false

You can also add these settings as SIP_ENABLED, SIP_URL, SIP_USERNAME, SIP_PASSWORD and SIP_REQUIRE_GOOGLE_AUTH environment variables (instead of config.json settings).

Google Authentication for Phone dial-out

You can limit the ability to place outgoing calls to those authenticated by google. To enable this feature:

  1. Create a Google API Console Project and client ID following the steps detailed here:

  2. Edit the config/config.json file in this application, and add the following properties:

  • Google.clientId -- Set this to your client ID.
  • Google.hostedDomain -- If you wish to limit sign in to accounts associated with a hosted domain, set the domain here.
  • Sip.requireGoogleAuth -- true to require auth for SIP dial-out as detailed in Phone dial-out.

For example, the new lines in the config.json file should look like this:

  "Google": {
    "clientId": ">",
    "hostedDomain": ""

You can also add these as GOOGLE_CLIENT_ID and GOOGLE_HOSTED_DOMAIN environment variables instead of config.json setings.

Web client configuration

Web client allows to be configured in some of its features. You can enable or disable using their enabled field in JSON or ENABLE_<FEATURE> environment variable.


  • ENABLE_ARCHIVING:(Optional, default value: true) Enable Archiving (Recording)
  • ARCHIVE_ALWAYS:(Optional, default value: false) Record all sessions.
  • ARCHIVE_TIMEOUT: (Optional, default value: 5000): The initial polling timeout (in milliseconds) for archive status change updates. Set this to 0 to disable polling.
  • TIMEOUT_MULTIPLIER (Optional, default value: 1.5) : Timeout multiplier. If the first archive status update polling fails, subsequent polling intervals will apply this multiplier successively. Set to a lower number to poll more often.
Archive Manager
  • ENABLE_ARCHIVE_MANAGER: (Optional, default value: false) Enable Archive Manager. Only meaningful if archiving is not disabled (Manage Recordings, requires firebase to be configured)
  • EMPTY_ROOM_LIFETIME: (Optional, default value 3): Maximum time, in minutes, an empty room
"Archiving": {
    "enabled": true,
    "archiveAlways": false,
    "pollingInitialTimeout": 5000,
    "pollingTimeoutMultiplier": 1.5,
    "archiveManager": {
        "enabled": false,
        "emptyRoomMaxLifetime": 3

Screen sharing configuration

  • ENABLE_SCREENSHARING:(Optional, default value: false) Whether to enable screen sharing.
  • CHROME_EXTENSION_ID :(Optional, LEGACY, default value: 'null'): The Chrome AddOn extension ID for screen sharing. Note: the Chrome extension is no longer required for screensharing.
  • ENABLE_ANNOTATIONS: (Optional, default value: true) Whether to enable annotations in screen sharing. This is only meaningful if screen sharing is not disabled.
"Screensharing": {
    "enabled": false,
    "chromeExtensionId": null,
    "annotations": {
        "enabled": true

To know more about how screen sharing works in OpenTok, see the guide on screen sharing.


The app lets the developer POST feedback data to an endpoint on your HTTP server:

FEEDBACK_URL: The URL to send a POST request with feedback data. Leave this as an empty string or undefined to disable issue reporting.

REPORT_ISSUE_LEVEL: The audio and video scores in the feedback form are between 1 (awful) and 5 (excellent). When the feedback form is submitted, if an audio or video score is less than or equal to the report issue level, the app calls OT.reportIssue(). This reports an issue, which you can view in OpenTok Inspector. (For more information, see Reporting an issue in the OpenTok developer Guides.) The default value is 3, set to 0 to disable issue reporting.

"Feedback": {
    "url": "",
    "reportIssueLevel": 0

SIP connection

See the Phone dial-out section.

Additional configuration options

  • SHOW_TOS (Optional, default value: false): Whether the app will display the terms of service dialog box and require the user to agree to the terms before joining a room.

  • ALLOW_IFRAMING (Optional, default value: 'never'): Controls the server-side restriction on allowing content to load inside an iframe. The allowed values are:

    • 'always': Allow iframing unconditionally (note that rtcApp.js should also be changed to reflect this, this option only changes what the server allows)

    • 'never': Set X-Frame-Options to 'DENY' (Deny loading content in any iframe)

    • 'sameorigin': Set X-Frame-Options to 'SAMEORIGIN' (Only allow iframe content to be loaded from pages in the same origin)

    We don't allow restricting iframe loading to specific URIs because it doesn't work on Chrome.

  • USE_GOOGLE_FONTS (Optional, default value: true): Whether the client app will load the Open Sans font (the main font used in the user interface) from the Google font library ( or not.

  • JQUERY_URL (Optional, default value: ''): Route of the CDN that will be used to load JQuery scripts.

  • MEDIA_MODE (Optional, default value: 'routed'): Whether the OpenTok sessions should be relayed or routed.

Customizing the UI

For information on how to customize OpenTokRTC's UI, see


"ServerPersistence: Timeout while connecting to the Persistence Provider! Is Redis running?

Ensure Redis server is running on localhost (run redis-server in the command line) and restart OpenTokRTC.

OpenTokRTC does not work on when served over HTTP.

Browser security policies require HTTPS for WebRTC video communications. You will need to set up the app to be served over HTTPS. You can set up a secure reverse-proxy to your OpenTokRTC port using nginx. For details, read this post.

UI looks broken

UI assets are compiled as part of the build process when installing application dependencies using npm install. If the web application UI still looks broken, run the following commands in the root directory of the application:

$ bower install
$ grunt clientBuild

We recommend that you run the application as a non-root user. However, if you are running the application as the root user, you will additionally need to tell bower to allow root user to install dependencies, else bower will refuse to work:

$ bower install --allow-root

Health status check

There is a health status check endpoint at /server/health. You can load this URL to check whether the app is able to connect to all required external services. On success, this health check endpoint sends a response with the HTTP status code set to 200 and the JSON like the following:

  "name": "opentok-rtc",
  "version": "4.1.1",
  "gitHash": "312903cd043d5267bc11639718c47a9b313c1663",
  "opentok": true,
  "firebase": true,
  "googleAuth": true,
  "status": "pass"

The JSON includes the following properties:

  • name -- "ot-embed"

  • version -- The version number deployed (from package.json)

  • git_hash -- The git commit deployed

  • opentok -- Whether the OpenTok API check passed. The app uses the OpenTok Node.js SDK, which connects to the OpenTok API server to create OpenTok sessions.

  • firebase -- Whether the Firebase check passed. The app uses Firebase to store embed data.

  • googleAuth -- Whether the Google Authentication check passed. This check is only run if the app uses Google Authentication for making outbound SIP calls. (See Google Authentication for Phone dial-out.)

  • status -- "pass" (if all checks pass) or "fail" (if any check fails)

On failure, the health status check endpoint returns a response with the HTTP status code set 400 and JSON like the following:

  "name": "opentok-rtc",
  "version": "4.1.1",
  "git_hash": "312903cd043d5267bc11639718c47a9b313c1663",
  "opentok": true,
  "firebase": false,
  "error": "10-second Firebase timeout reached.",
  "status": "fail"

Note that upon failure, the status property is set to "fail" and the error property is set to an error message. Also, the property for the failing test, such as firebase, will be set to false. If a test fails, the health check will not run subsequent tests.

Development and Contributing

Interested in contributing? We ❤️ pull requests! See the Contribution guidelines.

Getting Help

We love to hear from you so if you have questions, comments or find a bug in the project, let us know! You can either:

Further Reading