Quickstart

Updated on September 21, 2021

To start receiving events from Crisp websites subscribed to your integration, the RTM API needs to be connected to over a single WebSocket channel, via the Socket.IO protocol.

The channel will be silent until you send the first authentication payload, with your authentication token. Once authenticated, events will start flowing, until you explicitly teardown the channel.

This guide walks you through setting up a connection with the RTM API, and receiving events.

Overview Schematic

Overview schematic

👉 The RTM API lets your integration receive real-time events such as messages, as they get received on the Crisp websites that your plugin has access to. Before events start flowing, you will need to authenticate yourself over the socket.


Usage Flow

This is the lifecycle of a connection with the RTM API:

  1. Import your Socket.IO client library;
  2. Open a connection with wss://app.relay.crisp.chat/;
  3. Once connected, send your tokens with the authentication payload;
  4. Optionally, filter events and rooms you want to receive events for;
  5. Start receiving real-time events;
  6. (time passes...)
  7. Not willing to receive events anymore, teardown connection (disconnect);

How To Connect

Use a library

The most convenient way to connect with the RTM API is to use a RTM API-compatible library that we provide. Read our API Libraries guide to find a library for your programming language.

Let's provide an example on how you can receive events from the RTM API in your code.

As we recommend using Golang to build integrations with Crisp, the examples that follow will use the go-crisp-api library.

1. Import and configure the library

import (
  crispAPI "github.com/crisp-im/go-crisp-api/crisp"
)

func main() {
  // Create the Crisp client (it lets you access the REST API and RTM API at once)
  client := crispAPI.New()

  // Configure your Crisp authentication tokens ('plugin' token)
  client.AuthenticateTier("plugin", "<token_identifier>", "<token_key>")
}

2. Start listening for events

import (
  // <previous imports eluded>
  "fmt"
)

func main() {
  // <previous code eluded>

  // Subscribe to realtime events
  client.Events.Listen(
    // Subscribe to target event namespaces
    []string{
      "message:send",
    },

    // This will bind all event listeners
    func(reg *crisp.EventsRegister) {
      fmt.Print("Socket is connected: now listening for events\n")

      // Listen for text messages sent from visitors
      reg.On("message:send/text", func(evt crisp.EventsReceiveTextMessage) {
        fmt.Printf("Got text message from visitor: %s\n", evt)
      })
    },

    func() {
      // Disconnected event, you'd typically want to log the error there
      fmt.Print("Socket is disconnected: will try to reconnect\n")
    },

    func() {
      // Error event, you'd typically want to log the error there
      fmt.Print("Socket error: may be broken\n")
    },
  )

  // Note: to keep your code running, you would need to add blocking code here
}

The full working code example can be found at: go-crisp-api/examples/events/main.go.


Direct usage (no library)

In case no library is available to you, it is still possible to use Socket.IO to open a connection manually, authenticate, and receive events. This is fairly easy, and holds in a few lines of code.

The WebSocket endpoint you will need to connect to is: wss://app.relay.crisp.chat/. Note that the connection must be WSS (secure WebSocket), we do not support WS (insecure WebSocket) nor legacy HTTP long-polling.

The examples that follow will use JavaScript, as this is the main language that Socket.IO targets. Note that Socket.IO client libraries are available for most programming languages.

1. Import Socket.IO

In package.json:

{
  "dependencies": {
    "socket.io-client": "2.3.0"
  }
}

In app.js:

import io from "socket.io-client";

2. Connect to the RTM API

In app.js:

// <previous code eluded>

// Create client
let _client = new io("https://app.relay.crisp.chat", {
  path       : "/",
  transports : ["websocket"]
});

// Handle events
_client.on("connect", () => {
  console.log("RTM API connected");
});

_client.on("reconnect", () => {
  console.log("RTM API reconnecting...");
});

_client.on("disconnect", () => {
  console.log("RTM API disconnected");
});

_client.on("error", (error) => {
  console.error("RTM API error", error);
});

3. Authenticate to the RTM API (and filter events)

In app.js:

// <previous code eluded>

_client.on("connect", () => {
  // <previous code eluded>

  // Authenticate to the RTM API
  this.emit("authentication", {
    // Configure your Crisp authentication tokens
    username : "<token_identifier>",
    password : "<token_key>",

    // Subscribe to target event namespaces
    events : [
      "message:send"
    ]
  });
});

// <next code eluded>

_client.on("authenticated", () => {
  console.log("RTM API authenticated");
});

4. Handle events from the RTM API

In app.js:

// <previous code eluded>

// Listen for messages sent from visitors
_client.on("message:send", (event) => {
  console.log("Got message from visitor", event);
});

How To Authenticate

Once the WebSocket connection is open with the RTM API, you have about 10 seconds to authenticate with the server.

👉 Authentication is covered in our guide on RTM API Authentication.

If you do not authenticate in a timely manner, the server will close your connection. So please send the authentication payload as soon as you open the connection with the RTM API.

Subscribing To Events

Filter by event namespaces

Most integrations only need to subscribe to a handful of events from the RTM API, skipping a lot of them.

We recommend that upon connecting to the RTM API, you request to receive only the events that you require. This can be done upon sending the authentication payload, by adding an events property with the list of events you with to receive:

{
  // <other properties eluded>

  "events" : [
    // List of events to subscribe to, eg:
    "message:send",
    "message:received",
    "message:updated"
  ]
}

All our RTM API-compatible libraries let you filter events in a programmatic way, meaning that you do not have to send this authentication payload manually.

Note that the full list of available events can be read in the RTM API Reference.

Filter by origin (websites)

In some cases, you may need to restrict the events that you wish to receive to originate from a subset of websites that are subscribed to your plugin. This is rather rare, but be aware that it is possible.

As done with event namespace filtering, append a rooms property to the authentication payload, as such:

{
  // <other properties eluded>

  "rooms" : [
    // List of website IDs to subscribe to, eg:
    "8c842203-7ed8-4e29-a608-7cf78a7d2fcc"
  ]
}
Note that all filtered websites identifiers must be subscribed to your plugin. The server will reject any attempt to filter on websites that are not subscribed to your plugin.

Re-binding filters later on

If you would like to update filtered event namespaces or website rooms after you authenticated, note that this is possible.

Simply send a socket:bind event with the following structure (this must be done when you are already authenticated):

{
  "events" : [
    // List of events to subscribe to, eg:
    // We added 'message:compose:send' there.
    "message:send",
    "message:received",
    "message:updated",
    "message:compose:send"
  ],

  "rooms" : [
    // List of website IDs to subscribe to, eg:
    // We removed '8c842203-7ed8-4e29-a608-7cf78a7d2fcc' and added '25320afc-33e9-436d-8296-6b89d2e0986b' there.
    "25320afc-33e9-436d-8296-6b89d2e0986b"
  ]
}
Note that you need to re-list all events and rooms, as omitting an event or website identifier would remove it from the events that you receive. This lets you either unsubscribe/subscribe from/to previous/new events.

Usage Considerations

Connection limits

To protect Crisp systems against abuse or human error, the RTM API will not allow too many connections to be open from the same IP address or authentication token.

If, for any new connection that you open with the RTM API, the server either disconnects you or you do not receive any event on the channel (ie. it stays silent), then you may have hit the limits.

In fact, most integrations will only require 1 single connection to be open with the RTM API, at any time. Opening more connections suggests that you may have made a mistake.

As we know human error can occur when implementing an API, those limits will actually reveal potential mistakes you made. For instance you may open a new RTM API for each single user of your integration (this is wrong) and not re-use a common RTM API connection for everyone (this is right).

Since the limits may be subject to change in the future, we chose not to reveal them there. Note that they are quite high for the intended usage, meaning that you may start being limited after opening 50+ connections.

Network errors

When implementing the RTM API, remember that you are connecting to an external server over the network, which may not be 100% reliable. Therefore, you must make sure to handle abrupt and polite disconnections accordingly, in which case you should schedule a reconnection attempt.

If you get disconnected, we advise that you implement a reconnection retry counter. The counter would be reset upon successfully reconnecting, and it would be incremented for each reconnection failure. You would attempt the first reconnection retry immediately after being disconnected, only to retry at slower and slower intervals if you still cannot reconnect. This ensures your systems behave in a polite manner with ours, and do not flood our servers with reconnection attempts.

Being polite while reconnecting is particularly important, as your reconnection attempts compete with attempts from other users. If 10k+ users tried to reconnect every second at once, the servers would be temporarily slowed down to handle all those requests, actually making it slower to reconnect for everyone. So, be gentle please.