livqenoDocs

ChatPresence

Presence

Show who's online, away, or offline. Presence is never saved.

Presence shows whether a user is online, away, or offline right now. Use it for the green "online" dot next to a name, or "Agent is away" in a support chat.

Where this fits: your app is connected to a conversation (see the Chat quickstart). Presence works automatically: being connected makes you online. You only call setPresence to show away.

Presence is different from membership. Members are who may chat in a conversation. Presence is who is here right now.

Use it

In your app:

chat.on('presence', (event) => {
  console.log(`${event.userId} is ${event.status}`);
});
 
await chat.setPresence('away');
const present = await chat.getPresence();
// [{ userId: 'bob', status: 'online' }]

A typical pattern:

  1. When the chat opens, call getPresence() to draw the initial dots.
  2. Listen for presence events to update them.
  3. When the user switches to another tab or app, call setPresence('away'). When they come back, call setPresence('online').

How presence works

FactValue
Saved to the database?No. It's short-lived on purpose.
How long it lasts45 seconds, unless refreshed
How often it's refreshedEvery 20 seconds, while connected

Presence changes all the time, like when a user switches tabs. Saving every change would cost a lot and be useless seconds later.

How a user goes offline

  • Clean disconnect (user leaves normally): they go offline right away.
  • Crash, closed laptop, lost network: nothing tells the server. Their presence simply expires, so they go offline within 45 seconds.

This means users never get stuck as "online" forever.

Only changes are sent

The 20-second refresh does not send an event. You only get a presence event when a status actually changes. This keeps busy rooms quiet.

Multiple tabs

Presence is per user, not per tab. Three open tabs show as one online. Closing one tab doesn't make the user offline.

Large rooms

In a room with more than 200 people online (the default threshold, such as a live stream's chat), sending a presence event for every arrival would flood everyone. Instead:

  • per-user presence events stop;
  • every client gets a presenceCount event, { roomId, online }, at most every 5 seconds and only when the number changed (plus one last count when the room drops back under the threshold);
  • the full list is paged with listPresence() (at most 200 per page).
chat.on('presenceCount', ({ roomId, online }) => setViewerCount(online));
 
let page = await chat.listPresence({ limit: 200 });
while (page.nextCursor) {
  page = await chat.listPresence({ cursor: page.nextCursor, limit: 200 });
}

getPresence() still works, but in a large room it returns only the first page.

Live-stream audience viewers

Viewers of a live stream's chat join with an audience token: the token names the one conversation they may join (the SDK joins it by itself if you don't pass room), and they can read and post without being members. chat.isAudienceViewer is true for these clients. Member-only features — the inbox, read receipts and push — don't apply to viewers, and their calls reject with NOT_A_MEMBER without reaching the server. Slow mode, mutes, bans and the moderation hook still apply.

Common mistakes

MistakeWhat you'll seeFix
Expecting offline instantly after a crashThe user shows online for up to 45 seconds.This is expected. See above.
Using presence to decide who can readOffline members still get messages later from history.Use Members for access. Presence is display only.

Next steps