Server: Presence
Enable real-time tracking of who’s in a room. Mesh uses Redis TTLs and keyspace notifications to automatically clean up stale entries and notify subscribed clients.
Enable presence tracking
Track individual rooms or patterns:
.("lobby");
.(/^.+$/);
With options
Customize TTL or restrict visibility per connection:
.("admin-room", {
: 60_000, // Presence entry expires after 60s of inactivity (default is 0, meaning no expiration)
: async (, ) => {
const = await ..();
return ?.isAdmin === true;
},
});
How it works
- Presence entries are stored in Redis with optional TTL (if configured)
- TTL is refreshed via ping/pong heartbeat while connection is active
- Server pings client -> client pongs -> server refreshes presence TTL
- On disconnect or TTL expiration, presence is cleaned up
- Mesh emits
"leave"
events for both scenarios
Presence expiration uses Redis keyspace notifications. You can disable this via enablePresenceExpirationEvents: false
in your MeshServer
config.
This might be desirable if you want to implement a custom cleanup strategy, or if your Redis setup is very high traffic to the point of the overhead of processing keyspace notifications could impact performance. In most cases though, you should leave this enabled.
Get current presence
const = await ..("lobby");
// ["conn123", "conn456"]
Optional: Disable auto-cleanup
import { } from "@mesh-kit/server";
const = new ({
: false,
});
With this setting, you are responsible for manually cleaning up expired presence entries.
Per-connection model
Presence is tracked per connection, not per user.
If a user opens multiple tabs or devices, each one gets a unique connection ID and separate presence state, even if all share the same userId
in metadata.
This gives you precise control and avoids assumptions about identity or sessions.
To group presence by user:
- Store
userId
in connection metadata - Resolve metadata by
connectionId
on the client withclient.getConnectionMetadata(connectionId)
- Deduplicate by
userId
in your UI
This enables user-level presence like “only one typing indicator per user” even with multiple sessions.
Presence state
Clients can publish ephemeral presence states (e.g. "typing"
, "away"
).
On the server:
- State is stored at
"mesh:presence:state:<room>:<connectionId>"
- It’s removed on disconnect, leave, or expiration
- States can have TTLs via
expireAfter
- When cleared, Mesh emits
{ type: "state", state: null }
to subscribers
Enrich presence with metadata
.(async () => {
await ..(, {
: "user123",
: "Alice",
: "https://example.com/avatar.png",
});
});
See Client SDK → Presence for subscribing and handling updates.