The new JS SDK has quite a few changes, not only in the API itself, but also internally. First I am going to explain the changes and then list a few snippets to get used to the new API.

Support for multiple client instances

Instead of using the static Circuit.logon API, the API is now exposed on a Circuit.Client object. This allows an application to run multiple instances parallel which is particularly helpful in a nodejs application. The usage is:

  // Create a client instance and logon
var client = new Circuit.Client({domain: ''}); 
client.logon(email.value, password.value).then(function (user) { 

Any API call is then exposes on this client object. Same for events, they are all expose on this client object. E.g.

  // Create a client instance and logon
client.addEventListener('itemAdded', function (item) { 


The logon API is just a shortcut to the authenticate and getLoggedOnUser APIs. In fact the logon implementation is:

      self.logon = function (email, password) {
      return self.authenticate({email: email, password: password})

The best example to get started is

No global scope pollution

The old SDK polluted the global scope with objects such as '''Utils''', '''Constants''' and many more. This can cause conflicts with application defined objects. The new API contains everything in the Circuit namespace.

No internal caching

The old SDK used to cache conversations and users internally which is really application logic and should not be part of the SDK. That caused not only unnecessary complexity, but also a large memory footprint and performance issues. Most application did not even make use of all that caching, and if they do, then most likely not the right data is cached.

The new light weight SDK leaves taht up to the application. But as explained below, the application can define injectors to still get those nice extended and related objects. One example is that conversation.participants is now simply an array of userIds instead of a complete user object. But exactly that's where injectors come in handy.


The new SDK exposes injectors that can be implemented by the application. Currently there is a '''Circuit.Injectors.conversationInjector''', '''Circuit.Injectors.itemInjector''' and a '''Circuit.Injectors.userInjector'''.

The purpose of these injectors is to extend the conversation, item and user object at the time the SDK exposes these objects. This allows the application to define a single place where that particulat object is extende, whether be it for an event or a reponse to a request.

  • For example an application can implement a conversationInjector that enhances the conversation object to include participant objects instead of just participantIDs.
  • Another example is to assign custom avatars to user objects if the user has not assigned an avatar.

Important: Injectors can be defined as regular functions that run synchronously, or promises that run asynchronously.

Examples of injectors:

  // Define a item injector to create a teaser text
Circuit.Injectors.itemInjector = function (item) {
  if (item.type === 'TEXT') {
    // Create item.teaser attribute with replacing br and hr tags with a space
    item.extTeaser = item.text.content.replace(/<(br[\/]?|\/li|hr[\/]?)>/gi, ' ');
  } else {
    item.extTeaser = item.type;

  // The conversation injector example needs to be asynchroneous since the
// user lookup is an API call.
Circuit.Injectors.conversationInjector = function (conversation) {
  return new Promise(function (resolve, reject) {
    // Get user objects for participant userIds other than mine,
    // then set the 'extOtherUsers', 'extCreator' and 'topLevelItem.extCreator'
    // attributes. Then also set the 'title' attribute.
    var userIds = conversation.participants.filter(function (p) {
      return p !== client.loggedOnUser.userId;
    client.getUsersByIds(userIds).then(function (users) {
      // Set conversation.extOtherUsers
      conversation.extOtherUsers = users;

      // Set conversation.extCreator
      if (conversation.creatorId === client.loggedOnUser.userId) {
        conversation.extCreator = client.loggedOnUser;
      } else {
        conversation.extCreator = users.find(function (u) {
          u.userId === conversation.creatorId;

      // Set conversation.topLevelItem.extCreator
      if (conversation.topLevelItem && conversation.topLevelItem.creatorId === client.loggedOnUser.userId) {
        conversation.topLevelItem.extCreator = client.loggedOnUser;
      } else {
        conversation.topLevelItem.extCreator = users.find(function (u) {
          u.userId === conversation.topLevelItem.creatorId;

      // Set conversation.extTitle
      if (conversation.type === 'DIRECT') {
        conversation.extTitle = conversation.extOtherUsers[0].displayName;
      } else {
        conversation.extTitle = conversation.topic || (u) {
          return u.displayName;
        }).join(', ');

    }, function (err) {

  // Define a user injector to add default avatars to users without and avatar.
// This injector does not need to be async, so a regular function can be used.
Circuit.Injectors.userInjector = function (user) {
  if (!user.avatar) {
    // User does not have a profile picture. Let's assign a random one.
    var color = getColor(user.userId);
    user.extAvatar = 'https://' + client.domain + DEFAULT_AVATAR + color + '.png';
    user.extAvatarLarge = 'https://' + client.domain + DEFAULT_AVATAR + color + '-XL.png';

831 0 2