Best Practice Guide

This best practice guide is designed to help you make the most out of Ably’s Realtime platform for your applications. These recommendations include some important considerations that may otherwise be easily 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.
  • Using Ably like a pro – Recommendations that we’ve compiled as per our experience with developers to help you avoid common mistakes or misunderstandings.

Ably 101

Ably Realtime is a cloud-based platform that allows you to easily integrate realtime functionality into your applications. Just plug and play!

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 these channels will receive the data in realtime.

Notifications

Ably offers the Push Notifications feature which allows you to send notifications to your clients even when they are not using your application at the time, or in other words, not connected to Ably. This can be implemented on both mobile devices and browsers. Ably also offers a smart variation known as Smart Notifications using which you can make the notifications most effective based on your user’s connection state, their active device or even their current context within your application.

Presence

With Ably’s Presence feature, your clients can attach to a presence channel and announce to the rest of the 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.

Realtime vs REST

Ably provides two types of client libraries. Realtime libraries maintain a persistent connection to Ably and can be considered stateful, whereas REST libraries issue HTTP requests to the Ably platform and are stateless.

Authentication and Encryption

Ably supports two main means of authentication: Basic Authentication and Token Authentication. Basic Authentication is very easy to set up and requires the API key to be used by your clients. Token Authentication allows you to connect your auth server to Ably, using the API key, which allows your clients to handle authentication via the short lived tokens. These tokens provide a secure way to pass information over the internet and make sure that the actual API key is never exposed to your end clients but remains safely with your auth server. If you prefer to use a single auth strategy across all third party services, you can use JWT Authentication as part of Token Authentication.

Ably supports TLS being enabled by default. This ensures that data is securely sent to and received from Ably. However, messages are not encrypted within the Ably system. Using the encryption feature of our client libraries, you can make sure that message payloads are opaque, can never be decrypted by Ably but only by other clients that share your secret key.

Using Ably like a pro

In order to make the best use of Ably, you need to know the following gotchas:

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:

var sportsChannel = realtime.channels.get("sport");
//publish
sportsChannel.publish("update", { "team": "Man United" });
sportsChannel.publish("add", { "team": "Chelsea" });

//subscribe filters
sportsChannel.subscribe("update", function(){
  //do one thing
});
sportsChannel.subscribe("add", function(){
  //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(function(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:
var myListener = function(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.

Using the API key on the client side

Ably’s Basic Authentication method is the easiest way to authenticate your clients on the Ably platform, but, this will directly expose the API key in the source code. Hence, when using it on the client side, any entity that interacts with the client could view your API key and potentially misuse it. So, if you can run an auth server, we recommend using Token Authentication instead. With this method, your auth server is expected to use the API key to raise a token request from Ably, and the token can then be used by your end clients in the authentication step, eliminating the chance of misusing an exposed API key. Read more about selecting an authentication mechanism.

Ensuring tokens are auto-renewable

Tokens are short-lived i.e. they expire after a given time. It is almost never correct to provide a token to a client library without ensuring the client library has a means to get a new token automatically when it needs one. The Ably client library SDKs provide two mechanisms in the ClientOptions so that they can obtain tokens automatically using either authUrl or the authCallback.

Using the correct client library SDK – Choosing between Realtime, REST, MQTT and others

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.

WebHooks/Reactor Functions vs. Message Queues when to use which?

WebHooks and Reactor Functions work well for low or medium message volumes i.e ~20/s, but Reactor Queues will scale better to high message volumes i.e ~200/s. For volumes higher than that, we recommend using Reactor Firehose.

Multiplexing channels

You should almost always instantiate a single Ably client library instance per device, web page or server. Don’t forget that the Client Library SDK can multiplex many channels over a single connection. This maximizes throughput, minimizes bandwidth consumption and reduces power & battery drain.

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

Whilst we recommend 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 may help you with your channel usage design:

  • 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

Building a mechanism that keeps a tab on presence events can be quite complex. Hence, 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(function(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. Hence, 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

Get started now with our free plan

It includes 3m messages per month, 100 peak connections, 100 peak channels, and loads of features.

Create your free account