Docs

Presence

The presence API tracks who is on a channel and lets you react to joins, updates, and leaves.

Presence is a live membership set per channel. Each entry is a client id with an optional data payload, kept current by the service even when connections drop.

Watch presence

const off = channel.presence.on((event) => {
  console.log(event.action, event.clientId, event.data);
});

Registering the first listener opens a presence watcher on the channel. The listener first receives one enter per current member, so you can build the initial roster from events alone, then live transitions as they happen. Removing the last listener closes the watcher, so idle channels cost nothing.

presence.subscribe is an alias of presence.on, and both accept an action filter:

channel.presence.on('leave', (event) => {
  removeUser(event.clientId);
});

Enter, update, and leave

await channel.presence.enter({ name: 'Acorn', status: 'building' });
await channel.presence.update({ name: 'Acorn', status: 'idle' });
await channel.presence.leave();

enter announces this connection with an optional payload, update replaces the payload, and leave removes it. Closing the connection also removes the member after the service notices the drop.

Presence traffic bills as messages. Each enter, update, or leave counts one message in, and every watching client that receives the event counts one message out. That multiplies on channels where everyone watches everyone: 200 clients entering while 200 watch is about 40,000 messages. Keep presence channels reasonably sized, and see Usage and billing for the full accounting.

The presence event

Field Type Meaning
action 'enter' | 'update' | 'leave' What changed
clientId string The member’s client id
connectionId string The member’s connection, since one client id can hold several
data unknown? The payload from enter or update
timestamp number When the transition happened, ms since epoch

Reconnects

If this connection entered presence and then drops, the SDK re-enters automatically once it reconnects, with the last payload it sent. Other members see a leave only when the service gives up on the connection, so brief blips usually pass unnoticed.

Presence over REST

Fetch a point-in-time snapshot of the members without holding a WebSocket open:

import { Rest } from '@foony/realtime';

const rest = new Rest({ key: process.env.FOONY_API_KEY! });
const page = await rest.channels.get('chat:lobby').presence.get();

for (const member of page.items) {
  console.log(member.clientId, member.data);
}

Capabilities

Entering presence requires the presence operation on the channel. Watching presence events only requires subscribe. See Auth and capabilities.