Presence
Mesh tracks which connections are currently present in each room (if presence tracking is enabled for the room), and notifies subscribed clients when others join or leave.
Presence—and presence state—is tracked per connection, not per user.
When a user opens your app in multiple tabs or devices, each creates its own WebSocket connection. These connections are treated independently in Mesh, each with its own:
- Connection ID
- Room membership
- Per-room presence status
- Optional presence state
Even if those connections share the same userId
, Mesh does not deduplicate them. This is intentional—Mesh gives you flexible primitives without enforcing identity rules or session merging.
To implement user-level presence (e.g. “only show one typing indicator per user”):
- Store a
userId
in connection metadata - On the client, call
getConnectionMetadata(connectionId)
- Deduplicate by
userId
in your UI
For a ready-made solution, use the Unified Presence utility which handles this pattern elegantly.
See Server SDK → Presence for details.
Basic usage
Server: enable presence tracking
// Enable tracking for a single room
server.trackPresence("lobby");
// Or for all matching rooms
server.trackPresence(/^.+$/);
Client: subscribe to presence
const { success, present } = await client.subscribePresence(
"lobby",
(update) => {
if (update.type === "join") {
console.log("Joined:", update.connectionId);
} else if (update.type === "leave") {
console.log("Left:", update.connectionId);
}
}
);
You’ll get a list of currently present connections and live updates as others join or leave.
Unsubscribe when no longer needed:
await client.unsubscribePresence("lobby");
Presence states
Clients can publish transient status info like "typing"
, "away"
, or anything your app defines.
await client.publishPresenceState("lobby", {
state: { status: "typing" },
expireAfter: 8000, // optional (ms)
});
These states:
- Are scoped to a specific room + connection
- Automatically expire (if
expireAfter
is set) - Are cleared when the connection leaves the room or disconnects
Clients subscribed to presence in that room will receive a "state"
update:
{
type: "state",
connectionId: "abc123",
state: { status: "typing" } // or null if cleared/expired
}
Summary
Presence is ideal for:
- Who’s online indicators
- Live room rosters
- Typing/activity signals
- Lightweight awareness in collaborative apps
See Server SDK → Presence and Client SDK → Presence for full APIs and advanced behavior.