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 101

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

Authentication

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.

Using the API key on the client side

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.

Renewing tokens

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.

Realtime vs REST

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:

Encryption

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.

Publish and Subscribe (Pub/Sub)

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.

Notifications

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.

Presence

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.

For experienced developers

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

Channels that you attach to, automatically receive messages from Ably even without a subscribe listener

Once a channel is attached, assuming the client has permission to subscribe to messages, Ably will immediately start sending published messages to that client irrespective of whether there are any subscribe listeners registered on that client or not. A common misunderstanding is that only after a client has subscribed to a channel will Ably start sending messages to that client. This is not the case as registering a listener with a channel subscribe operation is a client-side operation only and is not communicated to Ably.

Use separate channels to filter messages for different sets of subscribers

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:

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
});

Being present without subscribing to presence events

If you want lots of people to be present, but without necessarily listening for presence change events, tokens can be used to prevent all users from receiving presence notifications while still allowing them to enter the presence set. This is a common scenario when you just want to know how many people are present on a channel at any point in time. An example of such a differential token capability is shown below:

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

Handling connection and channel state-change events

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:
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:
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.

Subscribing to events on the server-side

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.

Choosing between events, message queues, and Firehose

Events 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.

Multiplexing channels

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.

Limiting the effect of a security compromise using the principle of least privilege

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.

Efficient use of channels

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.

Embedding client ID in the token to ensure trust

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.

Using the synced presence set provided by the realtime library

Monitoring presence events can be quite complex. For this reason, the Presence object in the realtime library exposes a get method allowing a client to retrieve an array of all members present on the channel. The Ably client is responsible for keeping track of the presence set from the time that the channel is attached. An up-to-date presence set is pushed to the client following attach and this set is updated on each subsequent presence event. Thus get returns the already-known presence set retained in memory and does not trigger a new request to the Ably service. You can simply use this method as shown below, instead of venturing into the complexity of building one of your own.

channel.presence.get((err, members) => {
  console.log('There are ' + members.length + ' members on this channel');
  console.log('The first member has client ID: ' + members[0].clientId);
});

Using the presence set as a single source of truth to see which clients are present

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, however they will be differentiated by their unique connectionId. 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, yet will have two unique connection IDs. This means that if “Sarah” leaves the channel on her mobile, it doesn’t necessarily mean she’s gone as she might still be connected via desktop. For this reason, you should always use the presence set, which you can retrieve using the get method, as the single source of truth to see which clients are connected.


API reference
Documentation

Need help?

If you need any help with your implementation or if you have encountered any problems, do get in touch. You can also quickly find answers from our knowledge base, and blog.