The's Javascript client library enables performance monitoring features in browser-based WebRTC endpoints. The communication with the backend occurs over Secure HTTP (https://) and Secure WebSocket (wss://). The endpoint (the browser in this case) MUST support WebSockets. Additionally, the origin server MUST allow Cross-Origin Resource Sharing (CORS) and MAY need to serve its own pages over HTTPS to avoid mixed content warnings.


callstats.js uses semantic versioning. The current version is: v2.2.0

console.log("CallStats version: %o",callstats.version);


callstats.initialize(): authenticates with the backend to setup a trusted relationship with it. See integration section for details on when to call this API.


  • AppID: of type String. It is obtained from backend; discussed in a later section.

  • AppSecret: of type String. It is obtained from backend; discussed in a later section.

  • userID: of type String, maximum length 256 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.

  • initCallback: providing a callback function is OPTIONAL, the callback asynchronously reports failure or success. See Callback and Error Handling section below.

callstats.AddNewFabric(): indicates that the WebRTC application intends to monitor the performance of the PeerConnection between the two endpoints (represented by the corresponding UserIDs). See integration section for details on when to call this API.


  • pcObject: pass the PeerConnection object created after invoking RTCPeerConnection().

  • remoteUserID: of type String, maximum length 256 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.

  • fabricUsage: an Enumeration, with valid values values discussed in a later section.

  • conferenceID: of type String, maximum length 512 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.

  • pcCallback: providing a callback function is OPTIONAL, the callback asynchronously reports failure or success. See Callback and Error Handling section below.

callstats.sendFabricEvent(): notifies the backend about events (e.g., 'Hold', 'Mute', etc.) on a PeerConnection. It is usually generated due to local user interaction at a PeerConnection.


  • pcObject: pass the PeerConnection object associated with the fabricEvent.

  • fabricEvent: an Enumeration, with valid values discussed in a later section.

  • conferenceID: of type String, maximum length 512 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.

callstats.sendUserFeedback(): Send the feedback indicated by the user for a specific conferenceID.


  • conferenceID: of type String, maximum length 512 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.

  • feedback: is a JSON object. See details in JSON for sendUserFeedback.

  • pcCallback: providing a callback function is OPTIONAL, the callback asynchronously reports failure or success. See Callback and Error Handling section below.

Enumeration of fabricUsage

  • audio: describes an audio-only PeerConnection.

  • video: describes a video-only PeerConnection.

  • screen: describes a screen-sharing PeerConnection. It is still a video stream, and may be characterized as low frame rate and high frame size.

  • data: describes a PeerConnection with only DataChannels.

  • multiplex: describes a PeerConnection carrying multiple media streams on the same port.

  • unbundled: describes a PeerConnection carrying media streams on different ports.

When using a single PeerConnection between a pair of userIDs for sending and receiving audio and video, application MUST use multiplex.

Enumeration of fabricEvent

  • fabricSetup: The PeerConnection is set up successfully and the endpoint is ready to send and receive media. Performance measurement is started.

Deprecated: The library is consistently able to detect fabricSetup on its own, there is no need to report it anymore.

  • fabricSetupFailed: The PeerConnection failed to set up communication between the two endpoints.

  • fabricHold: The PeerConnection is currently not sending and receiving any media, but the connection is still active.

  • fabricResume: The PeerConnection is resuming communication with the remote endpoint.

  • audioMute: The PeerConnection is currently not sending any Audio, but MAY be sending video.

  • audioUnmute: The PeerConnection is resuming Audio communication.

  • videoPause: The PeerConnection is currently not sending any Video, but MAY be sending audio.

  • videoResume: The PeerConnection is resuming Video communication.

  • fabricTerminated: The PeerConnection is destroyed and is no longer sending or receiving any media.

JSON for sendUserFeedback

Mandatory Keys:

  • userID : of type String, maximum length 256 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.
  • overall: of type Integer, MUST be a value between 1-5. Typically the scores correspond to the mean opinion score, in this case this value represents the overall quality perceived by the userID.

Optional Keys:

  • audio, video, screen: similar to the definition of overall, except these values correspond to specific types of media streams.

Callback and Error Handling

The callstats.js uses a callback function to report different success and failure cases, they can occur during initialize() or sending measurements to the backend. The callback takes the form of:

1 function callback(csError, csErrMsg) {
2   console.log("Status: errCode= " + csError + " errMsg= " + csErrMsg ); }
3 }

csError and csErrMsg are of type String. csErrMsg is a descriptive error returned by the backend or the jQuery library.

csError Types

  • httpError: HTTP error, the csErrMsg string is reported by jQuery.ajax().

  • authError: Authentication failed, AppID or AppSecret is incorrect.

  • wsChannelFailure: Connection failed, could not connect to over WebSockets.

  • csProtoError: The backend rejects the fabricEvent or the statistics because the callstats.js is sending malformed messages. This may happen due to a change in the metrics or formatting of the current statistics API implemented by the browser.

  • success: The backend has accepted the request and the endpoint is authenticated, or capable of sending measurement data.

  • appConnectivityError: The connectivity checks for given PeerConnection object failed, i.e., iceConnectionState is set to disconnected.

Integration Steps

Preparing the Origin Server

Currently, there are two ways of loading callstats.js:

  • with require.js.
  • normally, without any module loader.

Integration details for each mechanism is described later in the document.

Getting the AppID and AppSecret

These are generated by backend when registering a new WebRTC application.

Generating the userID

The userID is expected to be unique, and the max length is 256 bytes. It is used by the backend to distinguish between different endpoints. The userIDs generated by the origin server and therefore the origin server decides if these identifiers are ephemeral or actual usernames. Typically, if the same user joins the conference via multiple means (devices or browsers) at the same time, the origin server MAY use the same userID. If the userID changes, the app MUST call initialize() again.

The backend treats userIDs as opaque identifiers, the origin server MAY choose to pass the same identifiers as it is using or send a SHA1 hash of the username@domain instead (where the username and domain are the ones used by the origin server).

Reusing the userID across sessions facilitates the backend to measure consistency of the endpoint across sessions and additionally helps the the WebRTC application developer identify under-performing or misbehaving devices.

Generating the conferenceID

The conferenceID is a unique call identifier to associate all userIDs in a conference. Therefore, all participants in a common call MUST use the same conferenceID. It is also generated by the origin server and MUST be temporally unique (i.e., for the duration of the call), the origin server MAY reuse the conferenceID identifier again for separate conferences at a later time, after the previous call using it has ended. The maximum length of the conferenceID is 512 bytes.

Like userIDs, the backend treats conferenceIDs as opaque identifiers, the origin server MAY use the same identifier as the one generated by the conference bridge, or use the URL of the page where the WebRTC call is taking place (e.g.,, concatenate current timestamp with a random number, or pass a SHA1 hash of one of the above schemes.To enable internationalization, and non-english named conferenceIDs, we automatically encode all incoming conferenceID strings into unicode. This helps you as an app-developer or WebRTC service operator to easily perform desktop search by directly copy-pasting (e.g., インターネット, интернэт, ອິນເຕີເນັດ).

The origin server MAY reuse the userID within the same conference call, i.e., two or more endpoints report using the same userID and conferenceID. while this is NOT RECOMMENDED, the will still attempt to distinguish these userIDs as distinct entities.

Authentication offers two authentication methods:

  • Basic over HTTPS (requires only client implementation)
  • OAuth (requires changes in both the client and origin server).

Basic Authentication over HTTPS

The application requires an AppID and AppSecret to authenticate with the backend. The origin server is expected to pass the userID for each endpoint in a WebRTC call. The callstats.js internally implements a 4-way handshake, comprising of the following steps request-challenge-response-success/failure. If successful, the callstats.js generates a token valid for 2 hours. The token is subsequently used by the callstats.js to send event and measurement data to the callstats


Instead of relying only on the endpoint for authentication, the also implements OAuth, which requires the origin server to handle the challenge-response step of the authentication setup instead of the endpoint.

Details TBD.

Integrating with your SDK

Step 1: Include callstats.js

With require.js

The require.js helps load dependencies at the origin server. Below is an example snippet:

<script data-main="YOUR REQUIRE JS CONFIG FILE" src=""></script>
 1 requirejs.config({
 2  // 1. define source paths to other dependencies
 3  paths: {
 4      jQuery: "",
 5      callstats: "",
 6      socketio: "",
 7      sha: ""
 8  },
 9  // 2. define dependency shim; callstats depends on jQuery, sha and
10  // IMPORTANT: You must preserve naming of variables for $, io and jsSHA
11  shim: {
12      'jquery': {
13          exports: '$'
14      },
15      'socketio': {
16          exports: 'io'
17      },
18      'sha': {
19          exports: 'jsSHA'
20      },
21      'callstats': {
22          deps: ['jquery','socketio','sha'],
23      },
24      'WebRTCApp': {
25          deps: ['callstats',... <other dependencies> ...],
26      }
27  }
28 });
30 // 3. load your main webRTCApp which depends on callstats
31 require(['WebRTCApp']);

Without require.js

Add the callstats.js in the HEAD tag.

<script src=""></script>

callstats.js depends on other common libraries that should be included in the HEAD tag. No need to include them again if your web application already uses them. However, make note of the version! We currently recommend the use of ( versions older than 1.0.0 are not supported).

//common dependencies, add if needed
  <script src=""></script>
  <script src=""></script>
  <script src=""></script>

Everything in the callstats.js is scoped under the callstats namespace, hence create the object.

var callStats = new callstats($,io,jsSHA);

Step 2: Initialize()

After the user is authenticated with the origin server (or when the page loads), call initialize() with appropriate parameters (see API section). Check the callback for errors. If the authentication succeeds, the callstats javascript will receive an appropriate authentication token to make subsequent API calls.

 1 //initialize the app with application tokens
 2   var AppID     = "YOUR APPLICATION ID";
 3   var AppSecret = "YOUR APPLICATION SECRET";
 5   function initCallback (err, msg) {
 6     console.log("Initializing Status: err="+err+" msg="+msg);
 7   }
 9   //userID is generated or given by the origin server
10   callStats.initialize(AppID, AppSecret, userID, initCallback);

Step 3: AddNewFabric()

When creating a PeerConnection, call callStats.AddNewFabric() with appropriate parameters (see API section). It is important to make the request only after the PeerConnection is created. The PeerConnection object MUST NOT be "undefined" because the callstats javascript uses getStats() to query the metrics from the browser internals. The earliest an application is able to call AddNewFabric() is when onnegotiationneeded event is fired by the WebRTC API for the first time.

 1 //adding Fabrics
 2   var pc_config = {"iceServers": [{url: ""}]};
 3   var pc = new RTCPeerConnection(pc_config);
 5   function pcCallback (err, msg) {
 6     console.log("Monitoring status: "+ err + " msg: " + msg);
 7   };
 9   //remoteUserId is the recipient's userID
10   //conferenceID is generated or provided by the origin server (webrtc service)
12   // let the "negotiationneeded" event trigger offer generation
13   pc.onnegotiationneeded = function () {
14     // pc is created, tell callstats about it
15     // pick a fabricUsage enumeration, if pc is sending both media and data: use multiplex.
16     var usage = callStats.fabricUsage.multiplex;
17     callStats.addNewFabric(pc, remoteUserID, usage, confID, pcCallback);
19     // create offer
20     pc.createOffer(localDescCreated, logError);
21   }

It also uses the event as the initial timestamp to calculate the establishment time. Subsequently, when a fabricSetupFailed or fabricSetup event is fired, the difference between the timestamps gives the establishment time.

In any WebRTC endpoint, where multiple PeerConnections are created between each participant (e.g., audio and video sent over different PeerConnections or a mesh call), the addNewFabric() MUST be called for each PeerConnection.

Step 4: Events

Send the appropriate fabricEvent via sendFabricEvent(). Sending any events are optional, but it helps if the WebRTC application is able to send events. If no events are sent, callstats.js will attempt to automatically detect some of the fabric events. Below are some guidelines for sending fabricEvents:

  • fabricSetup has been deprecated in v2.1.0 onwards, these events are now generated automatically by the JS library.

  • send fabricFailed when a call fails to connect to the remote peer or to the conferencing server. For example, failing to traverse a NAT or middlebox (ICE failure). This event MUST be reported by a local endpoint when the call fails without engaging the remote endpoint. In cases where the call fails after signaling to the remote endpoint succeeds, each endpoint MUST report the event independently.

  • send fabricTerminated when an endpoint or participant disconnects from the conference, it notifies the callstats javascript to stop monitoring the local PeerConnection. Depending on the implementation of the Hangup() method in WebRTC (may have to rely on signaling), the remote endpoint sends a fabricTerminated event before destroying its local PeerConnection object. The backend monitors each PeerConnection in real-time, but generates summary statistics when the participant leaves. The statistics are aggregated for conference when all participants leave. If no fabricTerminated event is received, the backend will summarize and aggregate the statistics 30 seconds after the last measurement for a conference is received.

Step 5: sendUserFeedback

The developers are expected to design an appropriate UI to get user input (of quality) at the end of the call. Typically, services collect user feedback based on the Mean opinion Score (MoS). However, it is not neccessary to use all values of the MoS scale, for example a service using only 2 point scale: it can associate 1 and 5 to bad and excellent, respectively and not use the values 2 to 4.

1 var overallRating = 4; // 1-5 rating, typically according to MOS scale.
2   var feedback = {
3     "userID": userID, //mandatory
4     "overall": overallRating, //mandatory
5   };
6   callStats.sendUserFeedback(confID, feedback, pcCallback);

Integration Progress

After creating an AppID, the helps you integrate the callstats javascript into your web application. It reports if any of the APIs have been invoked correctly.


The dashboard is a work in progress, more details to come.

Known Issues

Change Log

January 28, 2015: v2.2.0

  • Clients report PageLoad Performance metrics, to monitor callstats.js delivery.

December 19, 2014: v2.1.0

  • Gather and send user-generated feedback via sendUserFeedback()

  • Support for multiple PeerConnection objects between a single pair of endpoints (or users)

  • deprecated use of fabricSetup.

November 04, 2014: v2.0.0

  • Minimized callstats.js made available via cloudflare.

  • Alternate loading method added; using require.js

  • CDN urls added for dependent libraries.

July 29, 2014: v1.2.0

  • Support added for unicode conferenceIDs.

  • New features added: gather user feedback (documentation to be released).

March 02, 2014: v1.1.0

  • Aligned the protocol and encoding to the backend.

January 16, 2014: v1.0.0

  • First Public Version.

  • Added initialize(), AddNewFabric(), sendFabricEvent() API.

  • Added fabricUsage and fabricEvent enumerations.

  • Added error handling.

  • Added definitions for us erID and conferenceID variables.

  • Added Integration Steps.

  • Added explicit reference to SHA.js. [Jan 30]

  • Added max length for userID (256 bytes) and conferenceID (512 bytes). [Jan 31]

  • Clarified definitions of fabricEvents. [Feb 03]


Markdown friendly version is available on our Github. If you find any errors or bugs, post the issues directly on Github.

As the WebRTC matures more fabricEvents will be added. In the meantime, if you have comments or have new feature requests, join the discussion on the mailing list or drop us an email.