Presence
Presence enables clients to be aware of other clients that are currently “present” on a channel. Each member present on a channel has a unique self-assigned client identifier and system-assigned connection identifier, along with an optional payload that can be used to describe the member’s status or attributes. Presence allows you to quickly build apps such as chat rooms and multiplayer games by automatically keeping track of who is present in real time across any device.
Getting started
The Presence
object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as “present” on a channel. Here is a simple presence example using the presence
property of the Channel
object to enter a channel and subscribe to presence events.
var realtime = new Ably.Realtime({
key: '<loading API key, please wait>',
clientId: 'bob' }
);
var channel = realtime.channels.get('sax-pan-boo');
channel.presence.subscribe('enter', function(member) {
alert('Member ' + member.clientId + ' entered');
});
channel.presence.enter();
Demo OnlyCopyCopied!
Note that all examples on this page assume you are running them within an EventMachine reactor. Find out more in our Realtime usage documentation
If you would prefer to just dive into code and see some examples of how to use presence via the Realtime API, then we recommend you take a look at our Realtime tutorials.
Presence
In order to be present on a channel, a client must be identified by having a client ID, have permission to be present, and be attached to the channel. For simplicity, the library will implicitly attach to a channel when entering or subscribing to presence events. Clients are assigned a clientId
when using token authentication, find out more about token authentication.
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, “Sarah ” will be present twice in the presence member set with the same client ID, yet will have two unique connection IDs. A member of the presence set is therefore unique by the combination of the clientId
and connectionId
strings.
Presence states and events
Whenever a member enters or leaves a channel, or updates their member data, a presence event is emitted to all presence subscribers on that channel. Subscribing to presence events makes it incredibly easy to build an app that shows, in real time, any changes to clients connected to Ably and present on a channel.
The following presence events are emitted:
- enter
- A new member has entered the channel
- leave
- A member who was present has now left the channel. This may be a result of an explicit request to leave or implicitly when detaching from the channel. Alternatively, if a member’s connection is abruptly disconnected and they do not resume their connection within a minute, Ably treats this as a leave event as the client is no longer present
- update
- An already present member has updated their member data. Being notified of member data updates can be very useful, for example, it can be used to update the status of a user when they are typing a message
- present
- When subscribing to presence events on a channel that already has members present, this event is emitted for every member already present on the channel before the subscribe listener was registered
Member data
In addition to the clientId
for members on a channel, it is also possible to include data when entering a channel. Clients can update their data at any point which will be broadcasted to all presence subscribers as an update
event.
/* Subscribe to presence enter events */
channel.presence.subscribe('enter', function(member) {
console.log(member.data); // => not moving
});
/* Subscribe to presence update events */
channel.presence.subscribe('update', function(member) {
console.log(member.data); // => travelling North
});
/* Enter this client with data and update once entered */
channel.presence.enter('not moving', function(err) {
channel.presence.update('travelling North');
});
CopyCopied!
Presence member list
The Presence
object 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 the presence 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.
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);
});
CopyCopied!
Presence History
The Presence
object exposes a history
method allowing a client to retrieve historical presence events on the channel.
History provides access to instantaneous “live” history as well as the longer term persisted history for presence channels. If persisted history is enabled for the channel, then presence events will typically be stored for 24 – 72 hours. If persisted history is not enabled, Ably retains the last two minutes of presence event history in memory.
The following example retrieves the first two pages of historical presence events.
channel.attach(function() {
var presence = channel.presence;
presence.history({}, function(err, resultPage) {
if(err) {
console.log('Unable to get presence history; err = ' + err.message);
} else {
console.log(resultPage.items.length + ' presence events received in first page');
if(resultPage.hasNext()) {
resultPage.next(function(err, nextPage) { ... });
}
});
});
CopyCopied!
See the presence history documentation for further details of the supported query parameters.
Managing multiple client IDs
Each unique clientId
may only be present once when entering on behalf of another client as the unique identifier for each member in a presence set is the combined clientId
and shared connectionId
>
An Ably client instance might, if on an application server for example, publish messages and be present on channels on behalf of multiple distinct client IDs. The channel’s Presence
object therefore also supports methods that enable presence messages to be emitted for a clientId
specified at the time of the call, rather than implicitly based on the clientId
specified when the library is instantiated or authenticated.
In order to be able to publish presence changes for arbitrary client IDs, the client library must have been instantiated either with an API key, or with a token bound to a wildcard client ID.
var rest = new Ably.Rest({ key: '<loading API key, please wait>' });
/* request a wildcard token */
rest.auth.requestToken({ clientId: '*' }, function(err, token) {
var realtime = new Ably.Realtime({ token: token });
var channel = realtime.channels.get('realtime-chat');
channel.presence.subscribe('enter', function(member) {
console.log(member.client_id + 'entered realtime-chat');
});
channel.presence.enterClient('Bob'); // => Bob entered realtime-chat
channel.presence.enterClient('Mary'); // => Mary entered realtime-chat
});
Demo OnlyCopyCopied!
Handling transient channel/connection failures
Any time a channel is re-attached and the presence set is re-synced, e.g. after a short disconnection, the client will check whether any members it has entered into the presence set are there. If not, it will automatically re-enter them. This means that if a channel loses continuity (for example, because a client was disconnected from Ably for more than two minutes before reconnecting), then after the channel automatically re-attaches, any presence members it had previously entered will be restored.
The exception is if you use the recover feature to resume a previous connection with a fresh client library instance (for example, to have continuity over a page refresh). In that case you will need to explicitly re-enter presence after you re-attach to the channel, due to the loss of client library internal state.
Presence with unstable connections
Clients that are part of a presence set remain present for 15 seconds after they are abruptly disconnected, for example where the internet connection suddenly drops or the client is changing networks. This delay is to avoid repeated leave
and enter
events being sent when a client is experiencing an unstable connection.
The Ably client library will attempt to reconnect after a disconnect. If the connection is reestablished before 15 seconds have passed, a leave
event will not be sent. If the connection is reestablished after 15 seconds, a leave
event will be sent and the presence set will need to be rejoined.
Note that the 15 second delay from being removed from the presence set is only for abrupt or unplanned disconnects. If a client calls leave()
or close()
they immediately send a leave
event.
The time taken before a leave
event is sent in the case of an abrupt disconnect can be reduced to a minimum of 1 second by setting a value for remainPresentFor
, in milliseconds. This property is set within the transportParams
property of the clientOptions
object.
It is important to note that it can initially take up to 30 seconds to identify that a client has been abruptly disconnected. Shorten the amount of time taken to identify abrupt disconnects using the heartbeatInterval
property if your app needs to quickly identify presence set members being abruptly disconnected.
The following example code demonstrates establishing a connection to Ably with remainPresentFor
set to 1 second:
const ably = new Ably.Realtime(
{
key: '<loading API key, please wait>',
transportParams: { remainPresentFor: 1000 }
}
);
Demo OnlyCopyCopied!
API Reference
View the Presence API Reference.