Navbar
Logo icon Name

Relay SDK for JavaScript

Getting Started

The Relay JavaScript SDK transforms your standard browser into a realtime media engine, enabling developers to directly make audio and video calls to phone numbers, SIP endpoints, and other browsers. Using the JavaScript SDK you can add immersive, scalable communication - from video conferences and softphones to click-to-call and mobile gaming - all available right in your own web pages and applications.

SignalWire's simple and powerful authentication system, using JWT, allows you to set granular permissions, enabling some of your users to only join conference calls, while others could list on-going calls and jump in to assist from a support dashboard... the possibilities are endless.

Latest Version:

Source Code: signalwire/signalwire-js

Support: SignalWire Community Slack Channel

Installation

The Relay SDK for JavaScript is easy to use and only takes a few minute to setup and get running.

CDN

You can directly include the bundle file from our CDN:

<script src="https://cdn.signalwire.com/libs/js/relay/1.2.3/relay.min.js"></script>

Then, use the global Relay variable in your application.

NPM/Yarn

NPM combined with a web application bundler like Webpack or Parcel:

npm install @signalwire/js

Then, import Relay into your application:

import { Relay } from '@signalwire/js'

Using the SDK

First step to using the SDK is to setup authentication. The JavaScript SDK is unique in that everything runs within the browser on the client side, which means you cannot safely use your Project Token for authentication as you do in the other, server-side SDKs.

To get around this, the JavaScript SDK uses JSON Web Tokens (JWT) to authenticate with SignalWire and apply fine grained permissions to the end-user.

Your server uses your Project ID and Project Token to make a request to generate a JWT with your specific requirements, such as expiration time, scopes and permissions, resource name, and give the resulting JWT Token to the browser. The JWT is safe to expose in the browser and to the end user, it is signed and cannot be edited. The browser can then safely log into SignalWire using the Project ID and the JWT.

To learn more about generating and using JWT, including all the options available to you, visit Authentication for JavaScript SDK Documentation.

Generate a JWT

To generate a JWT, make a server-side POST request to the JWT endpoint on the Relay REST API.

curl https://your-space.signalwire.com/api/relay/rest/jwt \
  -X POST \
  -u 'YourProjectID:YourProjectToken' \
  -H 'Content-Type: application/json'

Will result in a JSON response like:

{
    "jwt_token": "a_long_jwt_token",
    "refresh_token": "a_long_jwt_refresh_token"
}

For more information and examples on generating JSON Web Tokens, visit Authentication for JavaScript SDK Documentation

Connect using JWT

Using the JWT you received in the previous step, you can connect to Relay using your Project ID and the JWT.

const client = new Relay({
  project: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
  token: 'a_long_jwt_token'
})

You can then use client to make Relay requests.

Refresh JWT Token

All tokens have an expiration, so that a user cannot stay logged in forever. You can use the refresh token you received in Generate a JWT to refresh a token you already generated.

To refresh a JWT, make a server-side PUT request to the JWT endpoint with the refresh token:

curl https://your-space.signalwire.com/api/relay/rest/jwt \
  -X PUT \
  -u 'YourProjectID:YourProjectToken' \
  -H 'Content-Type: application/json' \
  -d '{
        "refresh_token": "a_long_jwt_token"
      }'

Will result in a JSON response like:

{
    "jwt_token": "a_new_jwt_token",
    "refresh_token": "a_new_jwt_refresh_token"
}

For more information about automatically refreshing JWT as they're about to expire, see refreshToken Event Documentation

API Reference

Relay

Relay client is the basic connection to Relay, allowing you send commands to Relay and setup handlers for inbound events.

Constructor

Constructs a client object to interact with Relay.

Parameters

project string required Project ID from your SignalWire Space
token string required Json Web Token retrieved using Rest API. See Generate a JWT for more information.

Examples

Create a Client to interact with the Relay API.

const client = new Relay({
  project: 'my-project-id',
  token: 'my-jwt',
})

client.on('signalwire.ready', (client) => {
  // You are connected with Relay!
})

client.connect()

Properties

connected boolean true if the client has connected to Relay.
expired boolean true if the JWT has expired.

Devices and Media Constraints

You can configure the devices your client will use by default with these properties and methods:

devices
getter
object All devices recognized by the client keyed by kind: videoinput, audioinput and audiooutput.
videoDevices
getter
object DEPRECATED: Video devices recognized by the client.
audioInDevices
getter
object DEPRECATED: Audio input devices recognized by the client.
audioOutDevices
getter
object DEPRECATED: Audio output devices recognized by the client.
mediaConstraints
getter
object Current audio/video constraints used by the client.
speaker
getter
string Audio output device used by the client.
speaker
setter
string Set the audio output device to use for the subsequent calls.

Examples

If present, use the first audio output device as default speaker.

const speakerList = client.audioOutDevices.toArray()
if (speakerList.length) {
  client.speaker = speakerList[0].deviceId
}

Local and Remote Elements

It is usual, in a WebRTC application, to display the local and remote videos in a video-call. In the case of an audio-only call you will need at least the audio element to play the media.

localElement getter HTMLMediaElement Current element used by the client to display the local stream.
localElement setter HTMLMediaElement, String or Function It accepts an HTMLMediaElement, the ID of the element as a string or a Function that returns an HTMLMediaElement.
remoteElement getter HTMLMediaElement Current element used by the client to display the remote stream.
remoteElement setter HTMLMediaElement, String or Function It accepts an HTMLMediaElement, the ID of the element as a string or a Function that returns an HTMLMediaElement.

Note: the client will attach the streams to the proper element but will not change the style attribute. You can decide if you would like to display or hide the HTMLMediaElement following the application logic.
Use the callUpdate notification to detect call state changes and update the UI accordingly.

STUN/TURN Servers

Through the iceServers you can set/retrieve the default ICE server configuration for all subsequent calls.

iceServers getter RTCIceServers Current ICE servers used by the client.
iceServers setter RTCIceServers[] or Boolean array of ICE servers, true to use the default ones or false to not use STUN/TURN at all.

Examples

Use both STUN and TURN for the client.

client.iceServers = [
  {
    urls: 'stun:stun.example.domain.com'
  },
  {
    urls: 'turn:turn.example.domain.com',
    username: '<turn-username>',
    credential: '<turn-password>'
  }
]

Methods

checkPermissions

The first time a user visits your page, before access his microphone or webcam, the browser display a notification to the user. Use this method if you want to check you already have the permission to access them.

Available In:

Parameters

audio boolean optional Whether to check permissions for the microphone.
Default to true
video boolean optional Whether to check permissions for the webcam.
Default to true

Returns

Promise<boolean> - A Promise object resolved with a boolean value.

Examples

Check both audio and video permissions.

// within an async function ..
const success = await client.checkPermissions()
if (success) {
  // User gave the permission..
} else {
  // User didn't gave the permission..
}

connect

Activates the connection to Relay. Make sure you have attached the listeners you need before connecting the client, or you might miss some events.

Available In:

Returns

Promise<void>

Examples

await client.connect()

disconnect

Disconnect the client from Relay.

Available In:

Returns

void

Examples

client.disconnect()

disableMicrophone

Disable the use of the microphone for the subsequent calls.

Available In:

disableWebcam

Disable the use of the webcam for the subsequent calls.

Available In:

enableMicrophone

Enable the use of the microphone for the subsequent calls.

Available In:

enableWebcam

Enable the use of the webcam for the subsequent calls.

Available In:

getAudioInDevices

Return all audioinput devices supported by the browser.

Available In:

Parameters

None

Returns

Promise<MediaDeviceInfo[]> - A Promise object resolved with a list of MediaDeviceInfo.

Examples

List microphones.

// within an async function ..
const devices = await client.getAudioInDevices()
devices.forEach(device => {
  console.log(device.kind + ': ' + device.label + ' id: ' + device.deviceId);
})

getAudioOutDevices

Return all audiooutput devices supported by the browser.

Available In:

Parameters

None

Returns

Promise<MediaDeviceInfo[]> - A Promise object resolved with a list of MediaDeviceInfo.

Examples

List speakers.

// within an async function ..
const devices = await client.getAudioOutDevices()
devices.forEach(device => {
  console.log(device.kind + ': ' + device.label + ' id: ' + device.deviceId);
})

getDeviceResolutions

Return a list of supported resolutions for the given webcam (deviceId).

Available In:

Parameters

deviceId string required Device ID to be checked.

Returns

Promise<Array> - A Promise object resolved with a list of supported resolutions.

Examples

Check both audio and video permissions.

// within an async function ..
const resolutions = await client.getDeviceResolutions('d346d0f78627e3b808cdf0c2bc0b25b4539848ecf852ff03df5ac7545f4f5398')

[
  {
    "resolution": "320x240",
    "width": 320,
    "height": 240
  },
  {
    "resolution": "640x360",
    "width": 640,
    "height": 360
  },
  {
    "resolution": "640x480",
    "width": 640,
    "height": 480
  },
  {
    "resolution": "1280x720",
    "width": 1280,
    "height": 720
  }
]

getDevices

Return all devices supported by the browser.

Available In:

Parameters

None

Returns

Promise<MediaDeviceInfo[]> - A Promise object resolved with a list of MediaDeviceInfo.

Examples

List all devices.

// within an async function ..
const devices = await client.getDevices()
devices.forEach(device => {
  console.log(device.kind + ': ' + device.label + ' id: ' + device.deviceId);
})

getVideoDevices

Return all videoinput devices supported by the browser.

Available In:

Parameters

None

Returns

Promise<MediaDeviceInfo[]> - A Promise object resolved with a list of MediaDeviceInfo.

Examples

List webcams.

// within an async function ..
const devices = await client.getVideoDevices()
devices.forEach(device => {
  console.log(device.kind + ': ' + device.label + ' id: ' + device.deviceId);
})

newCall

Make a new outbound call.

Parameters

options object required Object with the following properties:
destinationNumber string required Extension to dial.
callerNumber string optional Number to use as the caller ID when dialling out to a phone number.
Must be a SignalWire number that you own.
id string optional The identifier of the Call.
localStream string optional If set, the Call will use this stream instead of retrieving a new one. Useful if you already have a MediaStream from a canvas.captureStream() or a screen share extension.
localElement string optional Overrides client's default localElement.
remoteElement string optional Overrides client's default remoteElement.
iceServers RTCIceServers[] optional Overrides client's default iceServers.
audio MediaStreamConstraints optional Overrides client's default audio constraints.
video MediaStreamConstraints optional Overrides client's default video constraints.
useStereo boolean optional Use stereo audio instead of mono.
micId string optional deviceId to use as microphone.
Overrides the client's default one.
camId string optional deviceId to use as webcam.
Overrides the client's default one.
speakerId string optional deviceId to use as speaker.
Overrides the client's default one.
onNotification string optional Overrides client's default signalwire.notification handler for this Call.

Returns

Promise<Call> - A Promise fulfilled with the new outbound Call object or rejected with the error.

Examples

Make an outbound call to +1 202-555-0122 using default values from the Client.

// within an async function ..
const options = { destinationNumber: '+12025550122' }
const call = await client.newCall(options).catch(console.error)

on

Attach an event handler for a specific type of event.

Available In:

Parameters

event string required Event name. Full list of events Relay Events
handler function required Function to call when the event comes.

Returns

Relay - The client object itself.

Examples

Subscribe to the signalwire.ready and signalwire.error events.

client.on('signalwire.ready', (client) => {
  // Your client is ready!
}).on('signalwire.error', (error) => {
  // Got an error...
})

off

Remove an event handler that were attached with .on(). If no handler parameter is passed, all listeners for that event will be removed.

Parameters

event string required Event name. Full list of events Relay Events
handler function optional Function to remove.
Note: handler will be removed from the stack by reference so make sure to use the same reference in both .on() and .off() methods.

Returns

Relay - The client object itself.

Examples

Subscribe to the signalwire.error and then, remove the event handler.

const errorHandler = (error) => {
  // Log the error..
}

client.on('signalwire.error', errorHandler)

// .. later
client.off('signalwire.error', errorHandler)

refreshDevices

DEPRECATED: Use getDevices instead.

Refresh the devices and return a Promise fulfilled with the new devices.

Available In:

Parameters

None

Returns

Promise<devices> - New devices object.

Examples

Refresh client's devices with async/await syntax.

// within an async function
const devices = await client.refreshDevices()

refreshToken

When the JWT is going to expire, the Client dispatch a notification with type refreshToken that allows you to refresh the token and keep your session alive.

Available In:

Parameters

token string required New JWT to keep your session alive.

Returns

Promise<void>

Examples

Listen for all notifications and, on refreshToken, fetch a new JWT from your backend and update the token on the client.

client.on('signalwire.notification', function(notification) {
  switch (notification.type) {

    case 'refreshToken':
      // Take a new token from your server...
      xhrRequestToRefreshYourJWT().then(async (newToken) => {
        await client.refreshToken(newToken).catch(console.error)
      })
    break

  }
})

setAudioSettings

You can set the default audio constraints for your client. See here for further details.

Note: It's a common behaviour, in WebRTC applications, to persist devices user's selection to then reuse them across visits.
Due to a Webkit’s security protocols, Safari generates random deviceId on each page load.
To avoid this issue you can specify two additional properties (micId and micLabel) in the constraints input parameter.
The client will use these values to assure the microphone you want to use is available by matching both id and label with the device list retrieved from the browser.


Available In:

Parameters

constraints MediaTrackConstraints required MediaTrackConstraints object with the addition of micId and micLabel.

Returns

Promise<MediaTrackConstraints> - Audio constraints applied to the client.

Examples

Set microphone by id and label with the echoCancellation flag turned off.

// within an async function
const constraints = await client.setAudioSettings({
  micId: '229d4c8838a2781e3668eb173fea2622b34fbf6a9deec19ee5caeb0916839520',
  micLabel: 'Internal Microphone (Built-in)',
  echoCancellation: false
})

setVideoSettings

You can set the default video constraints for your client. See here for further details.

Note: It's a common behaviour, in WebRTC applications, to persist devices user's selection to then reuse them across visits.
Due to a Webkit’s security protocols, Safari generates random deviceId on each page load.
To avoid this issue you can specify two additional properties (camId and camLabel) in the constraints input parameter.
The client will use these values to assure the webcam you want to use is available by matching both id and label with the device list retrieved from the browser.


Available In:

Parameters

constraints MediaTrackConstraints required MediaTrackConstraints object with the addition of camId and camLabel.

Returns

Promise<MediaTrackConstraints> - Video constraints applied to the client.

Examples

Set webcam by id and label with 720p resolution.

// within an async function
const constraints = await client.setAudioSettings({
  micId: '229d4c8838a2781e3668eb173fea2622b34fbf6a9deec19ee5caeb0916839520',
  micLabel: 'Internal Microphone (Built-in)',
  width: 1080,
  height: 720
})

Events

All available events you can attach a listener on.

signalwire.ready The session has been established and all other methods can now be used.
signalwire.error There is an error dispatch at the session level.
signalwire.notification A notification from SignalWire. Notifications can refer to calls or session updates.
signalwire.socket.open The websocket is open. However, you have not yet been authenticated.
signalwire.socket.error The websocket gave an error.
signalwire.socket.message The client has received a message from the websocket.
signalwire.socket.close The websocket is closing.

Call

A Call represents a one-to-one call with another browser, a SIP endpoint, or even a phone number. The Call object supports both audio and video.

Properties

id string The identifier of the call.
direction string The direction of the call. Can be either inbound or outbound.
state string The state of the call. See below for all the possible call states.
prevState string The previous state of the call. See below for all the possible call states.
localStream MediaStream The local stream of the call. This can be used in a video/audio element to play the local media.
remoteStream MediaStream The remote stream of the call. This can be used in a video/audio element to play the remote media.

State

The state and prevState properties of a Call have the following values:

Value Description
new New Call has been created in the client.
trying You are attempting to call someone.
requesting Your outbound call is being sent to the server.
recovering Your previous call is recovering after the page refresh. If you refresh the page during a call, you will automatically be joined with the latest call.
ringing Someone is attempting to call you.
answering You are attempting to answer the inbound Call.
early You received the media before the Call has been answered.
active Call has become active.
held Call has been held.
hangup Call has ended.
destroy Call has been destroyed.
purge Call has been purged.

Methods

answer

Start the process to answer the incoming Call.

Available In:

Parameters

None

Returns

None

Example

call.answer()

deaf

Turn off the audio input track.

Available In:

Example

call.deaf()

dtmf

Send a Dual Tone Multi Frequency (DTMF) string to Relay.

Available In:

Parameters

string string required DTMF to send.

Returns

None

Examples

call.dtmf('0')

hangup

Hangs up the call.

Available In:

Parameters

None

Returns

None

Examples

call.hangup()

hold

Holds the call.

Available In:

Parameters

None

Returns

None

Examples

call.hold()

muteAudio

Turn off the audio output track.

Available In:

Example

call.muteAudio()

muteVideo

Turn off the video output track.

Available In:

Example

call.muteAudio()

setAudioInDevice

Change the audio input device used for the Call.

Available In:

Example

// within an async function ..
const success = await call.setAudioInDevice('d346d0f78627e3b808cdf0c2bc0b25b4539848ecf852ff03df5ac7545f4f5398')
if (success) {
  // The Call audio input has been set to the device 'd346d0f78627e3b808cdf0c2bc0b25b4539848ecf852ff03df5ac7545f4f5398'
} else {
  // The browser does not support the .setSinkId() API..
}

setAudioOutDevice

Change the audio output device used for the Call.

Available In:

Example

// within an async function ..
const success = await call.setAudioOutDevice('d346d0f78627e3b808cdf0c2bc0b25b4539848ecf852ff03df5ac7545f4f5398')
if (success) {
  // The Call audio has been redirect to the device 'd346d0f78627e3b808cdf0c2bc0b25b4539848ecf852ff03df5ac7545f4f5398'
} else {
  // The browser does not support the .setSinkId() API..
}

setVideoDevice

Change the video output device used for the Call.

Available In:

Example

// within an async function ..
const success = await call.setVideoDevice('d346d0f78627e3b808cdf0c2bc0b25b4539848ecf852ff03df5ac7545f4f5398')
if (success) {
  // The Call video has been redirect to the device 'd346d0f78627e3b808cdf0c2bc0b25b4539848ecf852ff03df5ac7545f4f5398'
} else {
  // The browser does not support the .setSinkId() API..
}

toggleAudioMute

Toggle the audio output track.

Available In:

Example

call.toggleAudioMute()

toggleHold

Toggles the hold state of the call.

Available In:

Parameters

None

Returns

None

Examples

call.toggleHold()

toggleVideoMute

Toggle the video output track.

Available In:

Example

call.toggleVideoMute()

undeaf

Turn on the audio input track.

Available In:

Example

call.undeaf()

unhold

Un-holds the call.

Available In:

Parameters

None

Returns

None

Examples

call.unhold()

unmuteAudio

Turn on the audio output track.

Available In:

Example

call.unmuteAudio()

unmuteVideo

Turn on the video output track.

Available In:

Example

call.unmuteVideo()

Notification

A notification is an event that SignalWire dispatches to notify the Client about different cases. A notification can refer to the JWT expiration, Call changes or Conference updates.

Types

Every notification has a property type that identify the case and the structure of the data.
The available type are:

Value Description
refreshToken The JWT is going to expire. Refresh it or your session will be disconnected.
callUpdate A Call's state has been changed. Update the UI accordingly.
participantData New participant’s data (i.e. name, number) to update the UI.
userMediaError The browser does not have permission to access media devices. Check the audio and video constraints you are using.

refreshToken

Your JWT is going to expire. Refresh it or your session will be disconnected.

Anatomy of a refreshToken notification.

{
  type: 'refreshToken',
  session: RelayInstance
}

callUpdate

A Call's state has been changed. It is useful to update the UI of your application.s

Anatomy of a callUpdate notification.

{
  type: 'callUpdate',
  call: CallObject
}

participantData

This notification contains the participant data for the current Call. This is useful when updating the UI.

Anatomy of a participantData notification.

{
  type: 'participantData',
  call: CallObject,
  displayName: 'David Roe',
  displayNumber: '1777888800'
  displayDirection: 'inbound'
}

userMediaError

The browser lacks of permissions to access microphone or webcam. You should check which audio/video constraints you are using and make sure they are supported by the browser.

Anatomy of a userMediaError notification.

{
  type: 'userMediaError',
  error: error
}

Examples

Checkout our examples in Github to help you get started quickly.

Visit https://github.com/signalwire/signalwire-node/tree/master/packages/js/examples for our latest list of example implementations using the JavaScript SDK.