Skip to Content
Client SDKPresence

Client: Presence

Track who’s online in a room, listen for join/leave events, and share ephemeral presence state (like "typing" or "away").

Need user-level presence across tabs or devices? Use the createPresence utility to group connections by user ID or any other logic.

Subscribing

Subscribe to presence in a room:

const { , } = await .( "lobby", () => { if (. === "join") { .("User joined:", .); } else if (. === "leave") { .("User left:", .); } else if (. === "state") { .("State update:", ., .); } } );

You’ll receive:

  • A list of currently present members with metadata via present
  • Real-time "join", "leave", and "state" events

The present array includes both connection IDs and their metadata:

// present structure: [ { id: "conn_123", metadata: { username: "alice", avatar: "..." } }, { id: "conn_456", metadata: { username: "bob", avatar: "..." } } ]

Unsubscribe when done:

await .("lobby");

Join + subscribe in one step

Use joinRoom() with a callback to automatically subscribe to presence:

const { , } = await .("lobby", () => { .(); });

Both subscribePresence() and joinRoom() return the same present format with metadata included.

If you omit the callback from joinRoom(), you still get the current occupants with metadata - but you won’t be subscribed to real-time updates.

Leaving rooms

When you leave a room, any active presence subscription for that room is automatically cleaned up:

await .("lobby"); // unsubscribes from presence

You don’t need to manually call unsubscribePresence() after leaving a room.

Publishing presence state

Send ephemeral presence state to others in the room:

await .("lobby", { : { : "typing" }, : 8000, // optional (ms) });

Clear it manually:

await .("lobby");

Automatic presence refresh

When the server sends a ping and the client responds with a pong, the server refreshes the presence TTL for all rooms that the client connection has joined.

You don’t need to manually track rooms or re-send updates for each room your client has joined.

Receiving presence states

Presence updates include state events:

const { , , } = await .( "lobby", () => { if (. === "state") { .(`${.} state:`, .); } } );

You’ll also get a states object with current values at the time of subscription:

{ "abc123": { status: "typing" }, "def456": { status: "away" } }

Working with member metadata

Both methods return member information including metadata:

const { , } = await .("lobby", callback); // or const { , } = await .("lobby"); // Display current members .( => { .(`${.?.username || .} is online`); });

For real-time updates in your presence callback, resolve metadata for new connections:

await .("lobby", async () => { if (. === "join") { const = await .(.); .(`${?.username || .} joined`); } });

Use cases

  • Online indicators with user names and avatars
  • Room occupancy lists
  • Typing indicators
  • Game states like “ready”, “spectating”, etc.

Tips

  • Both joinRoom() and subscribePresence() include member metadata automatically
  • Unsubscribe when no longer needed to reduce overhead
  • Resubscribe after reconnecting (or use createPresence, which handles this for you)
  • Use expireAfter for short-lived states like "typing"
  • Debounce frequent updates to avoid spamming the network
Last updated on
© 2025