Home Advanced features explained How to setup a WebSocket connection?

How to setup a WebSocket connection?

Last updated on Apr 17, 2023

WebSockets establish a continuous connection between the client and server, enabling bi-directional communication. Chatwoot utilizes this connection to provide real-time updates about platform events. To connect to the Chatwoot WebSocket, simply provide a token and follow the setup instructions outlined in this guide.

Note: This feature is experimental, and the documentation may change with each release. Additionally, backward compatibility cannot be guaranteed, so it is important to ensure you are using the latest version of the implementation.

Why should I use a WebSocket connection?

A WebSocket connection allows for real-time data updates, making it ideal for clients such as an Android or iOS client SDK for Chatwoot. This helps update the dashboard without the need to reload the page. Hence, it can enhance the user experience and improve an agent's productivity.

How to set up a WebSocket connection with Chatwoot?

To set up a WebSocket connection with Chatwoot, you need to initiate a connection with the authentication PubSub token provided by Chatwoot. The URL for the connection is wss://<your-installation-url>/cable. If you are using Chatwoot Cloud, you can use wss://app.chatwoot.com/cable as the URL.

A PubSub token is a token that is used to authenticate a client when connecting to a PubSub (publish-subscribe) service. The client must present this token to the service in order to establish a connection and begin publishing or subscribing to messages.

There are two types of PubSub tokens available in Chatwoot, as listed below.

  1. User PubSub Token: This token has the privileges of an agent/admin and would receive all of the events listed later on the page. You can get the PubSub token by calling the Profile API.

  2. Contact PubSub Token: Chatwoot generates a unique PubSub token for each session a contact has. This token can be used to connect to the WebSocket and receive real-time updates for the same session. When a contact is created through the public APIs, the pubsub_token is included in the response payload. This token only grants access to events related to the current session, such as conversation.created,  conversation.status_changedmessage.createdmessage.updatedconversation_typing_onconversation_typing_off and presence.update.

Please refer Client APIs to build real time customer facing integrations using Chatwoot.

Note: This token may be rotated regularly based on your installation type. Please ensure that you are using the latest token.

How to connect to Chatwoot WebSocket?

To connect to the Chatwoot WebSocket, use the command subscribe and include your pubSubToken, accountId, and userId (if using a user token) in the connection request. Here is an example of how you can connect with Chatwoot.

// Add a helper method to convert JSON to a string
const stringify = (payload = {}) => JSON.stringify(payload);

const pubSubToken = "<contact/user-pub-sub-token>";
const accountId = "<your-account-id-in-integer>";
const userId = "<user-id-in-integer-if-using-user-token>";
const connection = new WebSocket(
  "wss://app.chatwoot.com/cable"
);

connection.send(
  stringify({
    command: "subscribe",
    identifier: stringify({
      channel: "RoomChannel",
      pubsub_token: pubSubToken,
      account_id: accountId,
      user_id: userId,
    }),
  })
);

// The expected string in connection.send is of the format:
// {"command":"subscribe","identifier":"{\\"channel\\":\\"RoomChannel\\",\\"pubsub_token\\":\\"your-pubsub-token\\",\\"account_id\\": account_id_integer,\\"user_id\\":user_id_integer }"}

Publishing presence to the WebSocket server

To keep your users’ status online in Chatwoot, you can send a presence update event to Chatwoot every 30 seconds. This action would keep the status of the agent/contact online.

How to update the presence of an agent/admin?

To update the presence of an agent or admin, send the following payload to the server:

const userPayload = stringify({
  command: "message",
  identifier: stringify({
    channel: "RoomChannel",
    pubsub_token: "<user-pubsub-token>",
    account_id: accountId,
    user_id: userId,
  }),
  data: stringify({ action: "update_presence" }),
});

connection.send(userPayload);
// The expected string in connection.send is of the format:
// {"command":"message","identifier":"{\\"channel\\":\\"RoomChannel\\",\\"pubsub_token\\":\\"your-pubsub-token\\",\\"account_id\\": account_id_integer,\\"user_id\\":user_id_integer ","data":"{\\"action\\":\\"update_presence\\"}"}

How to update the presence of a contact?

To update the presence of a contact, send the following payload to the server:

const agentPayload = stringify({
  command: "message",
  identifier: stringify({
    channel: "RoomChannel",
    pubsub_token: "<user-pubsub-token>",
  }),
  data: stringify({ action: "update_presence" }),
});

connection.send(agentPayload);
// The expected string in connection.send is of the format:
// {"command":"message","identifier":"{\\"channel\\":\\"RoomChannel\\",\\"pubsub_token\\":\\"your-pubsub-token\\","data":"{\\"action\\":\\"update_presence\\"}"}

WebSocket Payload

Objects

An event can contain any of the following objects as payload. Different types of objects supported in Chatwoot are as follows.

Conversation

The following payload will be returned for a conversation.

{
  "additional_attributes": {
    "browser": {
      "device_name": "string",
      "browser_name": "string",
      "platform_name": "string",
      "browser_version": "string",
      "platform_version": "string"
    },
    "referer": "string",
    "initiated_at": {
      "timestamp": "iso-datetime"
    }
  },
  "can_reply": "boolean",
  "channel": "string",
  "id": "integer",
  "inbox_id": "integer",
  "contact_inbox": {
    "id": "integer",
    "contact_id": "integer",
    "inbox_id": "integer",
    "source_id": "string",
    "created_at": "datetime",
    "updated_at": "datetime",
    "hmac_verified": "boolean"
  },
  "messages": ["Array of message objects"],
  "meta": {
    "sender": {
      // Contact Object
    },
    "assignee": {
      // User Object
    }
  },
  "status": "string",
  "unread_count": "integer",
  "agent_last_seen_at": "unix-timestamp",
  "contact_last_seen_at": "unix-timestamp",
  "timestamp": "unix-timestamp",
  "account_id": "integer"
}

Contact

The following payload will be returned for a contact.

{
  "additional_attributes": "object",
  "custom_attributes": "object",
  "email": "string",
  "id": "integer",
  "identifier": "string or null",
  "name": "string",
  "phone_number": "string or null",
  "thumbnail": "string"
}

User

The following payload will be returned for an agent/admin.

{
  "id": "integer",
  "name": "string",
  "available_name": "string",
  "avatar_url": "string",
  "availability_status": "string",
  "thumbnail": "string"
}

Message

The following payload will be returned for a message.

{
  "id": "integer",
  "content": "string",
  "account_id": "integer",
  "inbox_id": "integer",
  "message_type": "integer",
  "created_at": "unix-timestamp",
  "updated_at": "datetime",
  "private": "boolean",
  "status": "string",
  "source_id": "string / null",
  "content_type": "string",
  "content_attributes": "object",
  "sender_type": "string",
  "sender_id": "integer",
  "external_source_ids": "object",
  "sender": {
    "type": "string - contact/user"
    // User or Contact Object
  }
}

Notification

The following payload will be returned for a notification.

{
  "id": "integer",
  "notification_type": "string",
  "primary_actor_type": "string",
  "primary_actor_id": "integer",
  "primary_actor": {
    "can_reply": "boolean",
    "channel": "string",
    "id": "integer",
    "inbox_id": "integer",
    "meta": {
      "assignee": {
        "id": "integer",
        "name": "string",
        "available_name": "string",
        "avatar_url": "string",
        "type": "user",
        "availability_status": "string",
        "thumbnail": "string"
      },
      "hmac_verified": "boolean"
    },
    "agent_last_seen_at": "unix-timestamp",
    "contact_last_seen_at": "unix-timestamp",
    "timestamp": "unix-timestamp",
  },
  "read_at": "unix-timestamp",
  "secondary_actor": "object/null",
  "created_at":"unix-timestamp",
  "account_id": "integer",
  "push_message_title": "string"
}

Identifier

Each event will have an identifier attribute in the following format.

{
  "identifier": "{\\"channel\\":\\"RoomChannel\\",\\"pubsub_token\\":\\"token\\",\\"account_id\\":id,\\"user_id\\":user_id}"
}

Message

Each event will include a message attribute which we return the event name as well as the data associated with it. To see the list of events, refer the documentation below.

Types of Events

conversation.created

This event is triggered when a new conversation is initiated. If subscribing to the contact's PubSub token, this event will only include data related to the specific session associated with the PubSub token.

Available to: agent/admin, contact

{
  "message": {
    "event": "conversation.created",
    "data": {
      // Conversation object will be available here
    }
  }
}

conversation.read

This event is triggered and sent to the agents/admins who have access to the inbox, when a contact has read a message.

Available to: agent/admin

{
  "message": {
    "event": "conversation.read",
    "data": {
      // Conversation object will be available here
    }
  }
}

message.created

This event is triggered and sent to the agents, admins, contacts when a new message is created in a conversation they have access to.

Available to: agent/admin, contact

{
  "message": {
    "event": "message.created",
    "data": {
      // Message object will be available here
    }
  }
}

message.updated

This event is triggered and sent to the agents, admins, contacts when a message is updated in a conversation they have access to.

Available to: agent/admin, contact

{
  "message": {
    "event": "message.updated",
    "data": {
      // Message object will be available here
    }
  }
}

conversation.status_changed

This event is sent to the agents, admins, contacts when a conversation status is updated.

Available to: agent/admin, contact

{
  "message": {
    "event": "conversation.status_changed",
    "data": {
      // Conversation object will be available here
    }
  }
}

conversation.typing_on

This event is sent to the agents, admins, contacts when a contact or an agent starts typing a response.

Available to: agent/admin, contact

{
  "message": {
    "event": "conversation.typing_on",
    "data": {
      "conversation": {
        // Conversation object will be available here
      },
      "user": {
        // Contact / Agent,Admin User object will be available here.
      },
      "is_private": "boolean", // Shows whether the agent is typing a private note or not.
      "account_id": "integer"
    }
  }
}

conversation.typing_off

This event is sent to the agents, admins, contacts when a contact or an agent ends typing a response.

Available to: agent/admin, contact

{
  "message": {
    "event": "conversation.typing_off",
    "data": {
      "conversation": {
        // Conversation object will be available here
      },
      "user": {
        // Contact / User object will be available here.
      },
      "account_id": "integer"
    }
  }
}

assignee.changed

This event is sent to the agents/admins with access to an inbox when the assigned agent is changed.

Available to: agent/admin

{
  "message": {
    "event": "assignee.changed",
    "data": {
      // Conversation object will be available here
    }
  }
}

team.changed

This event is sent to the agents/admins with access to an inbox when the assigned team is changed.

Available to: agent/admin

{
  "message": {
    "event": "team.changed",
    "data": {
      // Conversation object will be available here
    }
  }
}

conversation.contact_changed

This event is sent to the agents/admins when two contacts are merged all their conversations are consolidated under one contact.

Available to: agent/admin

{
  "message": {
    "event": "conversation.contact_changed",
    "data": {
      // Conversation object will be available here
    }
  }
}

contact.created

This event is sent to the agents/admins when a contact is created.

Available to: agent/admin

{
  "message": {
    "event": "contact.created",
    "data": {
      // Contact object will be available here
    }
  }
}

contact.updated

This event is sent to the agents/admins when a contact is updated.

Available to: agent/admin

{
  "message": {
    "event": "contact.updated",
    "data": {
      // Contact object will be available here
    }
  }
}

presence.update

Available for both agent and the contact, this event provides real-time updates on the availability status of the users in the system. The event delivered to contacts will not include information about other contacts' availability status.

Available to: agent/admin

{
  "message": {
    "event": "presence.update",
    "data": {
      "account_id": "integer",
      "users": {
        "user-id": "string"
      },
      "contacts": {
        "contact-id": "string"
      }
    }
  }
}

notification_created

This event is sent to the agents/admins when a notification is created.

Available to: agent/admin