NAV
Javascript

Introduction

Welcome to the callstats.io API!

The callstats.io’s Javascript client library enables performance monitoring features in browser-based WebRTC endpoints. The communication with callstats.io 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.

Versioning

callstats.js uses semantic versioning. The latest version is in the changelog. However, programmatically the version can be fetched by invoking callstats.version.

API

callstats.initialize() with app secret

callstats.initialize(AppID, AppSecret, localUserID, csInitCallback, csStatsCallback, configParams);
Params Argument Type Description
AppID Required String Application ID is obtained from callstats.io.
AppSecret Required String Application secret is obtained from callstats.io.
localUserID Required String (128 bytes) or Object it is provided by the developer and MUST NOT be null or empty.
csInitCallback Optional Callback asynchronously reports failure or success of the protocol messages.
csStatsCallback Optional Callback asynchronously reports the conference statistics.
configParams Optional JSON it is the set of parameters to enable/disable certain features in the library.

JSON for UserID (supported since v3.14)

In some cases, customers want to provide the actual username in addition to the alias to callstats.io. Since callstats.js version 3.14, it accepts userID both as a String or an object. Section on generating userID provides more guidelines on choosing a localUserID.

var userId = {};
userId.userName = "Clark Kent";
userId.aliasName = "superman";
Keys Required Description
userName Yes Strint of maximum lenth 128 characters.
aliasName Yes String of maximum length 128 characters.

JSON for configParams

var configParams = {
  disableBeforeUnloadHandler: true, // disables callstats.js's window.onbeforeunload parameter.
  applicationVersion: "app_version" // Application version specified by the developer.
};

It provides developers a method to enable or disable certain features or functions within the callstats.js library. It is a javascript object with the following OPTIONAL key-value pairs. They are:

Keys Required Description
disableBeforeUnloadHandler No by default the value is false.
applicationVersion No String of maximum length 30 characters.

callstats.initialize() with third party authentication

Params Argument Type Description
AppID Required String Application ID is obtained from callstats.io.
tokenGenerator Required callback Callback to generate token.
localUserID Required String (128 bytes) or Object it is provided by the developer and MUST NOT be null or empty.
csInitCallback Optional callback asynchronously reports failure or success of the protocol messages.
csStatsCallback Optional callback asynchronously reports the conference statistics.
configParams Optional JSON it is the set of parameters to enable/disable certain features in the library.

callstats.addNewFabric()

 callstats.addNewFabric(pcObject, remoteUserID, fabricUsage, conferenceID, pcCallback);
Params Argument Type Description
pcObject Required Object PeerConnection object.
remoteUserID Required String (128 bytes) or Object It is generated by the origin server.
fabricUsage Required Enum Valid values are discussed in a later section.
conferenceID Required String (256 bytes) It is generated by the origin server.
pcCallback Optional Callback the callback asynchronously reports failure or success for pcObject.

callstats.reportError()

callstats.reportError(pcObject, conferenceID, callstats.webRTCFunctions.createOffer);
Params Argument Type Description
pcObject Required Object PeerConnection object
conferenceID Required String (256 bytes) It is generated by the origin server.
wrtcFuncName Required Enum Name of the WebRTC function that failed.
domError Optional Object DOMError object
localSDP Optional Object Local SDP collected when errors occur.
remoteSDP Optional Object Remote SDP collected when errors occur.

callstats.associateMstWithUserID()

// Extracting SSRC from SDP
var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
var reg = /^ssrc:(\d*) ([\w_]*):(.*)/;

pc.remoteDescription.sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
        var type = l[0];
        var content = l.slice(2);
        if(type === 'a') {
          if (reg.test(content)) {
            var match = content.match(reg);
            if(($.inArray(match[1],ssrcs) === -1)) {
              ssrcs.push(match[1]);
            }
          }
        }
      });

    ssrcs.forEach(function(ssrc) {
      window.callstats.associateMstWithUserID(pcObject, userID, conferenceID, ssrc, usageLabel, associatedVideoTag);
    });
Params Argument Type Description
pcObject Required Object PeerConnection object.
userID Required String (128 bytes) or Object It is generated by the origin server.
conferenceID Required String (256 bytes) It is generated by the origin server.
SSRC Required Object Synchronization Source Identifier, as defined in RFC3550.
usageLabel Required String (20 bytes) it is generated by the origin server.
associatedVideoTag Optional String handler to the user’s video tag.

callstats.sendFabricEvent()

Params Argument Type Description
pcObject Required Object PeerConnection object.
fabricEvent Required Enum with valid values discussed in a later section.
conferenceID Required String (256 bytes) It is generated by the origin server.
eventData Optional Object event related data.

callstats.reportUserIDChange()


callstats.reportUserIDChange(pcObject, conferenceID, newUserID, callstats.userIDType.local)

Params Argument Type Description
pcObject Required Object PeerConnection object.
conferenceID Required String (256 bytes) It is generated by the origin server.
newUserID Required String (128 bytes) or Object It is generated by the origin server.
userIDType Required Enum with valid values discussed in a later section.

callstats.sendUserFeedback()

Params Argument Type Description
conferenceID Required String (256 bytes) It is generated by the origin server.
feedback Required Object JSON object.
pcCallback Optional Callback the callback asynchronously reports failure or success of feedback submission.

JSON for feedback

Keys Required Type Description
userID Required String (128 bytes) It is generated by the origin server. Discussed in a later section.
overall Required Integer (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.
audio, video, screen Optional Integer (between 1-5) Similar to the definition of overall, except these values correspond to specific types of media streams.
comment Optional String Detailed user feedback.

Callbacks and Error Handling

The WebRTC application can provide two callback functions for callstats.js:

csInitCallback

function csInitCallback(csError, csErrMsg) {
  console.log("Status: errCode= " + csError + " errMsg= " + csErrMsg ); }
}

To report different success and failure cases, they can occur during initialize() or sending measurements to callstats.io. The callback takes the form of:

csError and csErrMsg are of type String. csErrMsg is a descriptive error returned by callstats.io.

csStatsCallback

var reportType = {
  inbound: 'inbound',
  outbound: 'outbound'
};

// callback function to receive the stats
var csStatsCallback = function (stats) {
  var ssrc;
  for (ssrc in stats.streams) {
    console.log("SSRC is: ", ssrc);
    var dataSsrc = stats.streams[ssrc];
    console.log("SSRC Type ", dataSsrc.reportType);
    if (dataSsrc.reportType === reportType.outbound) {
      console.log("RTT is: ", dataSsrc.rtt);
    } else if (dataSsrc.reportType === reportType.inbound) {
      console.log("Inbound loss rate is: ", dataSsrc.fractionLoss);
    }
  }
}

// initialize the callstats js API
var callstats = new callstats();
callstats.initialize(AppID, AppSecret, localUserId, csInitCallback, csStatsCallback);

The initialize() API authenticates the javascript WebRTC application with the callstats.io back-end, and sets up a trusted relationship with it. The API is extended by adding a csStatsCallback parameter. The callback parameter is OPTIONAL.

The csStatsCallback() will be called by the callstats.js for each PeerConnection independently at regular intervals. By default the interval is set as 10 seconds to make sure we do not overwhelm the app with too many messages. For more information, please check out our blog on csStatsCallback()

API Enums

Enumeration of fabricUsage

Usage Description
multiplex Describes a PeerConnection carrying multiple media streams on the same port.
audio Describes an audio-only PeerConnection.
video Describes a video-only PeerConnection.
screen Describes a screen-sharing PeerConnection.
data Describes a PeerConnection with only DataChannels.
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

Name Description
fabricSetupFailed (Deprecated) The PeerConnection failed to set up communication between the two endpoints.
fabricHold The fabric is currently not sending and receiving any media, but the connection is still active.
fabricResume The fabric is resuming communication with the remote endpoint.
audioMute The fabric is currently not sending any Audio, but MAY be sending video.
audioUnmute The fabric is resuming Audio communication.
videoPause The fabric is currently not sending any Video, but MAY be sending audio.
videoResume The fabric is resuming Video communication.
fabricTerminated The PeerConnection is destroyed and is no longer sending or receiving any media.
screenShareStart The PeerConnection started the screen sharing.
screenShareStop The PeerConnection stopped the screen sharing.
dominantSpeaker The userID reports that it is the dominant speaker and not the remote participants.
activeDeviceList The userID reports the active devices used by him during the conference.

Enumeration of wrtcFuncNames

Function Name Description
getUserMedia The failure occurred in getUserMedia function (added in callstats.js version 3.4.x).
createOffer The failure occurred in createOffer function.
createAnswer The failure occurred in createAnswer function.
setLocalDescription The failure occurred in setLocalDescription function.
setRemoteDescription The failure occurred in setRemoteDescription function.
addIceCandidate The failure occurred in addIceCandidate function.
iceConnectionFailure Ice connection failure detected by the application.
signalingError Signaling related errors in the application.
applicationLog Application related logs, this will not be considered as a failure.

Enumeration of userIDType

Name Description
local Set the localUserID
remote Set the remoteUserID

csError Types

Name Description
httpError HTTP error, the csErrMsg string is reported by the browser.
authError Authentication failed, AppID or AppSecret is incorrect.
wsChannelFailure Connection failed, could not connect to callstats.io over WebSockets.
csProtoError The client library is sending malformed messages.
success The back-end 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.
tokenGenerationError Application could not generate the JWT.

Authentication

Basic Authentication over HTTPS

The application requires an AppID and AppSecret to authenticate with callstats.io. 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, based on simple challenge-response protocol. 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 callstats.io.

callstats.io uses the “Origin” header in the HTTP request to fetch the request’s origin. RFC6454 explains the algorithm used by user-agents to compute the “Origin” header.

callstats.io compares the Origin URL sent by the HTTP user-agent in the authentication message with the stored Origin URL for that particular AppID. If the origins match, callstats.io returns a new token and associates the token to the requesting userID. Alternatively, if the origins does not match, callstats.io rejects the request, and denies access to that particular user-agent.

3rd party authentication

Instead of relying only on the endpoint for authentication, the callstats.io also implements third-party authentication, which requires the origin server to generate token for the endpoint which is then used to authenticate the endpoint. 3rd party authentication is discussed in detail in a later section.

Integrating with your App

Step 1: Include callstats.js

  <script src="https://api.callstats.io/static/callstats.min.js"></script>

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

  var callstats = new callstats();

Add the callstats.js in the HEAD tag.

Step 2: Initialize() with AppSecret

  //initialize the app with application tokens
  var AppID     = "YOUR APPLICATION ID";
  var AppSecret = "YOUR APPLICATION SECRET";

  //localUserID is generated or given by the origin server
  callstats.initialize(AppID, AppSecret, localUserID, csInitCallback, csStatsCallback, configParams);

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, callstats.js will receive a valid authentication token to make subsequent API calls.

For more information on callbacks, please refer to csInitCallback and csStatsCallback. Also have a look at step 8 for csStatsCallback data handling.

ALTERNATIVE: If you are interested in using the third-party authentication, see the details described in a later section.

Step 3: addNewFabric()

  //adding Fabrics
  var pc_config = {"iceServers": [{url: "stun:stun.example.org:3478"}]};
  var pcObject = new RTCPeerConnection(pc_config);

  function pcCallback (err, msg) {
    console.log("Monitoring status: "+ err + " msg: " + msg);
  };

  // pcObject is created, tell callstats about it
  // pick a fabricUsage enumeration, if pc is sending both media and data: use multiplex.

  var usage = callstats.fabricUsage.multiplex;

  //remoteUserID is the recipient's userID
  //conferenceID is generated or provided by the origin server (webrtc service)
  callstats.addNewFabric(pcObject, remoteUserID, usage, conferenceID, pcCallback);

When creating a PeerConnection, call 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” or NULL because callstats.js uses getStats() to query the metrics from the browser internals. The application SHOULD call addNewFabric() immediately after the PeerConnection object is created.

Time stamp of addNewFabric() is used as a reference point to calculate fabric failure delay or fabric setup delay:

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: reportError()

  //adding Fabrics
  var pc_config = {"iceServers": [{url: "stun:stun.example.org:3478"}]};
  var pcObject = new RTCPeerConnection(pc_config);

  function pcCallback (err, msg) {
    console.log("Monitoring status: "+ err + " msg: " + msg);
  };

  function createOfferError(err) {
    callstats.reportError(pcObject, conferenceID, callstats.webRTCFunctions.createOffer, err);
  }

  // remoteUserID is the recipient's userID
  // conferenceID is generated or provided by the origin server (webrtc service)
  // pcObject is created, tell callstats about it
  // pick a fabricUsage enumeration, if pc is sending both media and data: use multiplex.

  var usage = callstats.fabricUsage.multiplex;
  callstats.addNewFabric(pcObject, remoteUserID, usage, conferenceID, pcCallback);

  // let the "negotiationneeded" event trigger offer generation
  pcObject.onnegotiationneeded = function () {
    // create offer
    pcObject.createOffer().then(
      localDescriptionCreatedCallback,
      createOfferErrorCallback
    );
  }

Sometimes WebRTC endpoints fail to establish connectivity, this may occur when user-agents and/or bridges implement differing flavors of the Session Description Protocol (SDP) or may not support some features that others implement.

The WebRTC APIs either have a callback or a Promise associated to them. Since callstats.js ver. 3.2.x, WebRTC applications can use reportError() to capture at which stage the negotiation fails and pass on the DomError returned by the callback or Promise to callstats.io. The failure reason will appear both in the conference time-line and aggregate on the main dashboard. See Section enumerating WebRTC functions for details. The example below reports error when creating an SDP offer:

Step 5: (OPTIONAL) sendFabricEvent()

// send fabricEvent: videoPause
callstats.sendFabricEvent(pcObject, callstats.fabricEvent.videoPause, conferenceID);

// devices are returned by the
/*
var devices = navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true
});
//a typical device looks like:
//device= {  "deviceId":"default","kind":"videoinput","label":"FaceTime HD Camera","groupId":"2004946474"}
*/

var eventData = {
  deviceList: devices // array of active device
};

// send fabricEvent: activeDeviceList
callstats.sendFabricEvent(pcObject, callstats.fabricEvent.activeDeviceList, conferenceID, eventData);

During the conference, users might perform several actions impacting the measurements and conference analysis. The user might mute the audio or switch off the camera or do screen sharing during a conference. These events can directly impact the measurement data (For example, you can see a significant drop in throughput when camera is switched off). For the list of all possible conference events, please refer here

Send the appropriate fabricEvent via sendFabricEvent().

Step 6: (OPTIONAL) associateMstWithUserID()

  // After O/A is complete, i.e., onAddStream is fired
  var localUserID  = "Alice";
  var remoteUserID = "Bob";
  var conferenceID = "AliceAndBobAndCharlie";
  var mstLabel = "front-camera";
  // SSRC1 is the SSRCs of the local video stream
  // SSRC2 is the SSRC of the remote video stream, usually received in the remote SDP
  // mstLabel is a developer provided string that lets them identify
  // various tracks (e.g., front-camera, back-camera, without looking at the
  // configurations of the individual MSTs). In this example, we assume it is the
  // front-camera.
  callstats.associateMstWithUserID(pc, localUserID, conferenceID, ssrc1, mstLabel);
  callstats.associateMstWithUserID(pc, remoteUserID, conferenceID, ssrc2, mstLabel);

When interacting with the conference server, the developer is most likely going to use the name or identifier associated with the conference server as the remoteUserID. A typical conference bridge (for example, Jitsi Videobridge) transmits multiple media stream tracks within a peer connection. In which case, using a remote participant’s userID is impractical as there maybe several participants.

Since callstats.js ver. 3.3.x, we allow mapping Synchronization Source Identifier (SSRC) for a mediastreamtrack to a userID (both local and remote). By default the local and remote MediaStreamTracks are automatically mapped to the localUserID and remoteUserID. With associateMstWithUserID(), you can override the actual local and remote userIDs to the correct association. If the DOM identifiers of the video tags associated to each participant, callstats.js will calculate better quality scores for each participant. The code example shows how the API can be integrated:

Associationg userID with MST

More discussion related to the motivation of associateMstWithUserID() is covered in the following blog post.

Step 7: (OPTIONAL) sendUserFeedback()

  var overallRating = 4; // 1-5 rating, typically according to MOS scale.
  var feedback = {
    "userID": localUserID, //mandatory
    "overall": overallRating, //mandatory
  };
  callstats.sendUserFeedback(conferenceID, feedback, pcCallback);

The developers are expected to design an appropriate UI to get user input on 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.

Step 8: (OPTIONAL) Handling stats from statsCallback()

The developers can handle the stats received from statsCallback function in a way suitable to their application. It can be used for displaying bitrate or based on the conference quality indicators applications can change their settings etc. For more details check this blog post.

Step 9: (OPTIONAL) Submitting application logs

The developers can send application error logs using reportError() API and track them on callstats.io dashboard. The logs will help in debugging the corresponding conferences. The error can be an object or a string.

var error1 = {
    message: "Error message",
    error: "Error 1",
    stack: "stack trace for the error"
};

callstats.reportError(pc, confID, callstats.webRTCFunctions.applicationLog, error1);
error2 = "application error ";

callstats.reportError(pc, confID, callstats.webRTCFunctions.applicationLog, error2);

Loading with require.js

Script loading with require.js


<script data-main="YOUR REQUIRE JS CONFIG FILE" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.js"></script>

requirejs.config({
  // 1. define source paths to other dependencies
  paths: {
    //jQuery usage is deprecated from the version 3.10.0 onwards and socket.io is deprecated from 3.16.0
    callstats: "https://api.callstats.io/static/callstats.min"
  },
  shim: {
    'callstats': {
      deps: [],
    },
    'WebRTCApp': {
      deps: ['callstats',... <other dependencies> ...],
    }
  }
});

// 3. load your main webRTCApp which depends on callstats
require(['WebRTCApp']);

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

Generating userID, conferenceID, and JWT

userID

The userID is expected to be unique, and the max length is 256 bytes. It is used by callstats.io 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.

callstats.io 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 instead (where the username and domain are the ones used by the origin server). If you are not going to search by userID, we prefer that you use ephemeral userIDs. Alternatively, we support internationalization, and non-English named usernames, we automatically encode all incoming userID strings into UTF-8, and they are case-sensitive.

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.

  1. Using multiple PeerConnections between a local userID and conference server: The number of PeerConnections perhaps uniquely match 1:1 with the number of participants in the session. That is, there may be one PeerConnection which just sends media to the conference server and multiple PeerConnections carrying MediaStreamTracks (MSTs) associated with different participants. In this case, it may be advisable to use the conferenceServerID as the remoteUserID for the outbound media, and the actual remoteUserIDs for the inbound media.

  2. Multiple MSTs in a PeerConnection: There is only one PeerConnection between the localUserID and the conference bridge and the PeerConnection carries all the MediaStreamTracks (MSTs) received at the bridge from the various participants. In this case, the remoteUserID is the name of the conference bridge (e.g., conferenceServerID). More discussion about this is covered in the following blog post.

WebRTC conference star topology

UserID objects

In some cases, customers want to provide the actual username in addition to the alias to callstats.io. For example, the actual username can be accessed by the customer support, while the alias is shown to engineering team. The customer service representative needs to know the real names of the users to perform their work, while the engineering team does not. This functionality helps callstats.io separate the userID information and show the correct end-user information based on the user role.

Since callstats.js version 3.14, it accepts userID both as a String or an object.

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 256 bytes.

Like userIDs, callstats.io 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., www.example.com/conferenceID), concatenate current time-stamp 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 UTF-8, and these strings are case-sensitive. This helps you as an app-developer or WebRTC service operator to easily perform dashboard 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 callstats.io will still attempt to distinguish these userIDs as distinct entities.

Third-party authentication

Token format used by callstats.io’s third party authentication system is JWT. Currently the only supported algorithm is ES256.

API

The API is defined above.

Token claims

 {
  "userID":"4358",
  "appID":"545619706",
  "keyID":"0123456789abcedf00",
  "iat":1465221382,
  "nbf":1465221682,
  "exp":1465221682,
  "jti":"25b30fb33a7764d2971534507718f35274bb"
}

Token supports following claims:

Claim Required/optional Type Description
appID Required String This is your AppID.
userID Required String This is endpoint’s local user identifier.
keyID Required String ID of the key that was used to generate this token. This can be obtained from secrets configuration page
exp Optional NumericDate  Token expiration time. It’s recommended that this is set 5-10 minutes into the future.
nbf  Optional NumericDate Token not valid before. It’s recommended that this is set 5-10 minutes into the past.
jti  Optional  String JWT ID. This is used for audit logging.

Alternative Step 2: Initialize() with JWT (Client example)

  //initialize the app with application tokens
  var AppID     = "YOUR APPLICATION ID";

  function exampleTokenGenerator(initialToken) {
    var cached = null;
    if (initalToken)
     var cached = initialToken;
    // forcenew = set to true if application should generate new token and false if
    // it's okay to use cached token
    // callback(error, token). error should be set to non-null if there was an
    // non-recoverable error. Token should be the JWT. Please see section
    // "Third-party Authentication" for more complete documentation
    return function(forcenew, callback) {
      if (!forcenew && cached !== null)
        return callback(null, cached);
      // 1. get new token
      var xhr = new XMLHttpRequest();
      xhr.open('POST', '/getToken');
      xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
      xhr.onload = function() {
        // Did we get 200 OK response?
        if (xhr.status == 200) {
          // Get token and send it to callback
          var resp = JSON.parse(req.responseText);
          // the token should contain the claims defined in third party authentication
          return callback(null, resp.token);
        }
        console.log("Couldn't get the token");
        console.log(req.responseText);
        // if uncorrectable error happens, inform callstats.io
        return callback('Unknown error');
      };
      xhr.send(data);
    };
  }

  function initCallback (err, msg) {
    console.log("Initializing Status: err="+err+" msg="+msg);
  }

  //userID is generated or given by the origin server
  callstats.initialize(AppID, exampleTokenGenerator(initialToken), userID, initCallback, statsCallback, configParams);

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, callstats.js will receive an appropriate authentication token to make subsequent API calls.

Generating a JSON Web Token (JWT)

  var express = require('express');
  var jwt = require('jsonwebtoken');
  var app = express();
  var fs = require('fs');

  var crypto = require('crypto');

  // Your ECDSA private key for which the public key is submitted to
  // callstats.io dashboard
  var key = fs.readFileSync('ecprivate.key');
  var keyid = '0102030405060709';
  var appid = 12345678;
  // Dummy audit log
  var audit = {log: console.log};

  // Dummy session middleware
  app.use(function (req, res, next) {
    req.user = {id: 300};
    next();
  });

  // Dummy JWT ID generator
  var randomIdGenerator = function () {
    return 42;
  };

  app.post('/getToken', function (req, res) {
    if (!req.user) {
      res.status(403);
      return res.send(JSON.stringify({error: "User not logged in"}));
    }
    var randomid = randomIdGenerator().toString();
    var token = null;
    try {
      token = jwt.sign(
        {
          userID: req.user.id.toString(),
          appID: appid,
          keyID: keyid
        }, key,
        {
          algorithm: "ES256",
          jwtid: randomid,
          expiresIn: 300, //5 minutes
          notBefore: -300 //-5 minutes
        });
    } catch (err) {
      console.log(err);
      res.status(500);
      return res.send(JSON.stringify({error: "Token creation failed"}));
    }
    audit.log({action: "GrantToken", user: req.user.id, tokenid: randomid});
    res.status(200);
    res.send(JSON.stringify({token: token}));
  });

  app.listen(3000, function () {
    console.log('Example app listening on port 3000!');
  });

You can use following code as an example to generate JWT for authenticating the endpoint.

Support

If you have comments or have new feature requests, join the discussion on the mailing list or drop us an email.

Webhook Notifications

{
"reason":"dissatisfactoryUserFeedback","timestamp":1471354044616,"appId":"xxxxx","triggerType":"interval",
"actualValue":5,"threshold":0.2,"fractionalValue":0.3333333333333333,
"period":{"start":1458125913802,"end":1458129519080},
"url":"https:\/\/dashboard.callstats.io\/search?feedback12=1",
"text":"33% of the conferences had dissatisfactory feedback in the last hour i.e., 5 of 15 total conferences with appID xxxxx. The current trigger threshold is 20%."
}
{
"reason":"failedConferences","timestamp":1471354046133,"appId":"xxxxx","triggerType":"interval",
"actualValue":7,"threshold":0.1,"fractionalValue":0.11290322580645161,
"period":{"start":1458125913802,"end":1458129519080},
"url":"https:\/\/dashboard.callstats.io\/search?failureGroup=totalFailure",
"text":"11% of the conferences failed in the last hour i.e., 7 of 62 total conferences with appID xxxxx. The current trigger threshold is 10%."
}

JSON encoding

callstats.io sends periodic notifications (JSON encoded messages) to webhook URLs. The notification messages are sent when either a single event occurs (individual notification) or a metric exceeds a threshold value in a defined interval (interval notification), in the message these are identified by the triggerType. Details of the notification message structure are below:

Keys Description
reason camelCase string identifying the notification.
timestamp Unix timestamp in seconds when the message was sent.
appId The application identifier corresponding to the message.
triggerType One of interval or individual.
actualValue The actual measured value of the metric when the message was triggered.
threshold The threshold over which the notification is triggered. For individual metrics, this value is 1.
fractionalValue The ratio of the actualValue of a certain metric and the total measurement points of that metric. e.g., failed/total conferences.
period Object containing start and end timestamps.
url The search URL that will find the conference on callstats.io dashboard.
text Notification in english text.

Keys for the Notification reason

Keys Description
failedConferences ratio of failed conferences exceeded threshold
dissatisfactoryUserFeedback ratio of user feedback with dissatisfactory rating exceeded threshold