Best Practice Guide

This best practice guide is designed to help you make the most out of Ably’s Realtime platform. These recommendations include some important considerations that may otherwise be missed when reading through our documentation.

This guide consists of the following two sections:

  • Ably 101 – Key concepts that you must understand before moving on to the best practice recommendations.
  • For experienced developers – Ably’s recommendations for experienced developers, to help avoid common issues.

Ably Realtime is a cloud-based platform that enables you to integrate realtime functionality into your applications.

Ably supports two methods of authentication:

  1. Basic authentication
  2. Token authentication

When using basic authentication, you use the Ably API key to authenticate with Ably. In production systems you should always avoid using basic authentication on the client-side (such as in a browser), where the API key might be exposed. Instead, use token authentication with either an authUrl or authCallback.

With token authentication, your auth server uses your Ably API key to authenticate with Ably and then provides a TokenRequest object to your client, which your client then uses to authenticate with Ably. These short-lived tokens ensure that the Ably API key is never exposed to your client-side applications. However, the auth server can use the API key directly to authenticate with Ably using basic authentication, as on the secure server the API key will not be accessible to anyone other than authenticated personnel, such as systems administrators.

Important: Do not use basic authentication on the client-side, as it exposes your Ably API key. API keys don’t have an expiry, so once compromised, they could be used indefinitely by an attacker. Tokens have an expiry, and so there is only a small period of time during which the compromised token can be used.

Important: Never use token authentication to authenticate your server with Ably, as this results in unnecessary overhead – the server will periodically need to reauthenticate with Ably. Instead, use basic authentication to authenticate your server with Ably.

If you prefer to use a single auth strategy across all third-party services, you can use JWTs to authenticate with Ably.

Basic authentication is the simplest method to authenticate your clients on the Ably platform, but this exposes your API key in the source code. Therefore, Ably recommends that you create an auth server and use token authentication to authenticate your clients. Using this approach, only your auth server has access to your API key, protecting it from being misused. Read more about selecting an authentication mechanism.

Tokens are short-lived, that is, they expire after a given time. You must ensure that the client can request a new token when it needs one. The Ably Client Library SDKs provide two different mechanisms to obtain tokens automatically: authUrl or authCallback. You specify which one to use in the ClientOptions object.

Ably Client Library SDKs may implement two interfaces: realtime and REST. The Realtime interface maintains a persistent connection to Ably and can be considered stateful. The REST interface issues HTTP requests to the Ably platform and is stateless. The REST interface is therefore lighter weight because it does not need to maintain state.

Depending on your use case, you may only need to use the REST interface on your server. For example, the server may only need to authenticate with Ably, and then act as an auth server for clients. You might then use the realtime interface on your client, so it can both subscribe to and publish messages.

The PHP and Python SDKs only have a REST interface. While the Ruby SDK implements both realtime and REST interfaces, there is also a Ruby SDK available that implements only the REST interface. The full list of available SDKs, and their supported interfaces, can be found on the SDK download page.

An important difference between the REST and realtime interface is that with REST you can only publish realtime messages and not subscribe to them. With the realtime interface you can both publish and subscribe. If you have a use case where you only need to authenticate, or publish messages, then the REST interface is recommended.

The main factors are summarized here:

  • If you want to maintain a persistent connection with Ably’s Realtime platform in order to subscribe to messages sent on a channel, or be notified whenever the presence set changes, you need to use the realtime library.
  • If you just want to publish data to the platform and don’t need to subscribe or manage channel attachment, you can the REST library.
  • If you want to publish at very high rates or with the lowest possible realtime latencies, Ably’s realtime library would be best as it can publish at higher rates and lower latencies than is possible with the REST library due to message pipelining.
  • If you want to primarily issue tokens for clients or publish messages to channels, you can use the REST library.
  • If you want to get one-time info about the presence set of a channel, you can use the REST library.
  • If you want to set up realtime communication with IoT devices on platforms for which there isn’t an Ably Client Library SDK available, you can use the MQTT protocol adapter.
  • If you wish to migrate from PubNub or Pusher to Ably, you can use the relevant protocol adapter to switch to Ably, and then gradually move over to using the Ably Client Library SDKs.

All Ably Client Library SDKs use TLS by default. This ensures that data is transmitted to and from Ably securely. However, messages are not encrypted within the Ably system. Using the encryption feature of our SDKs, you can ensure that message payloads are opaque: they can never be decrypted by Ably but only by other clients that share your secret key.

You can publish data to named channels within Ably’s platform and the platform will make sure that all clients subscribed to those channels will receive the data in realtime.

Ably offers the Push Notifications feature which enables you to send notifications to your clients even when they are not currently using your application and are therefore not connected to Ably. This can be implemented on both mobile devices and browsers.

With Ably’s Presence feature, your clients can attach to a presence channel and announce to other channel users that they are present on a channel. This is very useful, for example, in chat apps to indicate a member is online, or with IoT devices to indicate a device is online and connected. Clients can subscribe to realtime presence changes on channels, such as members entering or leaving, and respond to these events accordingly.

In order to make the best use of Ably, you need to be aware of the following information:

It is important to understand the difference between attaching and subscribing to a channel, and that messages are sent to clients as soon as they attach to a channel.

The attach method attaches a client to the channel. Published messages are immediately sent to clients if they have subscribe capabilities to that channel, regardless of whether or not the client has subscribed to the channel.

The subscribe method registers a subscribe listener for messages received on the channel. subscribe is a client-side operation, meaning Ably is unaware of whether or not a client is subscribed to the channel. attach is called implicitly by the subscribe method.

By default, all data published to a channel is pushed by Ably to every subscriber attached to that channel. Only on the client side can subscribers filter messages by their message name and so ‘avoid’ receiving all published messages. But, if you have messages that don’t need to be sent to some clients at all, you’re often better off using a separate channel for them rather than implementing a filter. Because this way, you won’t be sending unnecessary messages that count towards your monthly message quota. This may be economical, but it isn’t always the best solution as in some cases you may wish to trigger different listeners for different events and so setting up a single channel and filtering the messages client side would be more sensible. An example is shown below:

JavaScript v1.2
const sportsChannel = realtime.channels.get("sport"); //publish sportsChannel.publish("update", { "team": "Man United" }); sportsChannel.publish("add", { "team": "Chelsea" }); //subscribe filters sportsChannel.subscribe("update", () => { //do one thing }); sportsChannel.subscribe("add", () => { //do another thing });

Ably’s Realtime SDKs automatically handle disruptions such as network disconnections, so you don’t need to manually handle reconnection. The library emits:

  • Connection state change events such as initialized, connecting, etc.You can set up listeners for these state change events to handle connections failures like those cause by failed authentication. An example of handling connection state-change event is shown below:
JavaScript v1.2
realtime.connection.on((stateChange) => { console.log('New connection state is ' + stateChange.current); });
  • Channel state change events for various channel states such as initialized, attaching, etc. Similar to connection state changes, you can set up listeners for channel state changes in case you’d like to be informed about what’s happening. For example, if you want to know whenever the library has lost message continuity on a channel due to being disconnected for more than two minutes. An example of handling channel state-change events is shown below:
JavaScript v1.2
const myListener = (stateChange) => { console.log('channel state is ' + stateChange.current); console.log('previous state was ' + stateChange.previous); }); channel.on(myListener);

However, while registering listeners for both connection and channel state change events, bear in mind that certain repeating states might add new listeners each time. For instance, registering a listener for on(connected) adds a new listener every time the client becomes connected, even if this is a reconnection after being offline for a while, which is often an unintentional result.

It is important to understand the difference between unsubscribing from a channel and closing a connection, compared to calling the off() method for a channel or connection.

The unsubscribe() method removes message listeners for a channel.

The close() method closes a realtime connection.

The off() method for a channel or connection removes ChannelEvent or ConnectionEvent listeners that are listening for state changes on a channel or for a connection.

You should be aware that subscribing to events on the server side, using the standard Pub/Sub pattern can be disadvantageous because it can increase latency or duplicate events among multiple servers, as explained in this blog article. With Message Queues, you can have multiple worker servers and allow Ably to distribute the load of the messages received from publishers, so that each message is only processed once by any one of your worker servers.

Webhooks work well for low or medium message rates of approximately 20/s, but Message Queues scale better to high message rates of around 200/s. For even higher rates, Ably recommends using Firehose.

Always strive to instantiate a single Ably Client Library SDK instance per device, web page or server. Don’t forget that the SDK can multiplex many channels over a single connection. This maximizes throughput, minimizes bandwidth consumption, and reduces power usage.

Using the available authentication methods in Ably, you can choose the permissions or capabilities to be given to a client. You can do this by restricting the permissions on the API key as well as restricting the permissions that your auth server grants to this API key whilst sending a token request. You can restrict the channels that a client can access (using wildcards), as well as the operations the client can perform within those channels, using capabilities.

Always make sure to limit the capabilities given to a client to only what’s required by the client to do their job. This prevents any unexpected behaviour by a client and increases the security of your application. This is called the principle of least privilege.

Although Ably recommends that you use channels to distribute work more evenly across the cluster, there is an associated cost for a high number of channels. Here are some considerations that might help you plan your channel usage:

  • Don’t use different channels just to indicate different types of data or different events, if they’re all going to the same set of clients. Use one channel, and distinguish between the different events using the message name.
  • Channels are the unit of security and scalability. If you are sending some data that must not be shared with certain clients, make sure it’s on a channel that those clients don’t have the capabilities to attach to.
  • Be aware that each channel can support a maximum of 100 messages per second.

A client ID serves as an identification for your clients when they are present on a channel. Your clients can set their own ID using the clientId attribute, but in that case, there’s a possibility that some of your clients can pretend to be someone else. To prevent this, you can embed a clientId in the token issued to your clients from your auth server. Doing so ensures that the clientId is set by your auth server, thus eliminating the chance of the end clients emulating as others.

It is important when using the presence feature to understand the number of messages it can produce. If you have subscribers and presence members present on a channel then the number of messages used can increase rapidly. As an example, consider 200 clients subscribed to presence events on a channel and all of them join and leave the presence set within a few minutes. This would result in the following messages:

  • 200 presence messages published for the enter event.
  • 200 × 200 (40,000) messages subscribed to for the enter events.
  • 200 presence messages published for the leave event.
  • 200 × 200 (40,000) presence messages subscribed to for the leave event.

This highlights the potential for 80,400 messages to be sent in a very short space of time on a single channel. As additional clients subscribe and enter the presence set, the number of messages quickly multiplies.

In some instances this is the behavior required of your application. In other scenarios you may prefer to only have a server subscribed to presence events and the clients are only present on the channel.

It is possible to have clients be present on a channel without them receiving presence change events. Efficient use of capabilities can prevent all clients from receiving presence notifications while still allowing them to enter the presence set. This is a common scenario when only a server is required to monitor the presence set and saves clients from subscribing to a potentially high volume of unnecessary messages.

An example of achieving this would be to use one channel for generic communications and another for the presence set. The following capabilities demonstrate this for clients and for servers:

For clients:

{ "chatPresence": ["presence"], "chat": ["publish", "history", "subscribe"], }

For servers:

{ "chatPresence": ["presence", "subscribe"], "chat": ["publish", "history", "subscribe"], }

A common need is to keep an updated list of currently-present members in your user interface.

To achieve this, many developers try to build the initial list using Presence.get() and then mutate that list whenever a new presence event arrives, from that event. However, we recommend against doing this, because it’s easy to get wrong and end up with a list that’s out of sync with the real presence set.

One common error is to fail to take into account that a single clientId may be present multiple times on the same channel via different client connections; as far as Ably is concerned, these are different members of the presence set for the channel as they have different connectionIds. For example, if a client with ID “Sarah” is connected to a chat channel on both a desktop and a mobile device simultaneously, or maybe via multiple tabs in a browser, “Sarah” will be present twice in the presence member set with the same clientID. So if she leaves the channel on her mobile, and your app sees the leave event and removes her entry from that list, you will get an incorrect list.

Instead, our recommended best practice is to just get the presence set afresh from the client library whenever you see a presence event, and rebuild the list in your user interface from that.

With a realtime SDK, the get operation is free and local, it just gives you the presence set that the client has already synced with the server (and which is kept updated by the server), so there is no cost to this.

For example:

JavaScript v1.2
channel.presence.on((presenceMessage) => { // Ignore the presence message, just rebuild your state from the get() method // (including uniquifying by clientId if you only want one entry per clientId) channel.presence.get((err, members) => { console.log('There are ' + members.length + ' members on this channel'); }); });

Ably apps are entirely isolated from one another, so each app can be treated as its own environment. Ably recommends using separate apps within your account for testing purposes and to name apps logically to easily differentiate between development, test and production environments.

The Ably sandbox environment is strictly for use by Client Library SDK developers and should not be used for testing.

Ably 101