Skip to Content
Server SDKPresence

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:

  1. Store userId in connection metadata
  2. Resolve metadata by connectionId on the client with client.getConnectionMetadata(connectionId)
  3. 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.

Last updated on
© 2025