Presence
Presence stores the current live state for a room member. Use it for online state, cursors, selections, typing indicators, active tools, viewport ranges, and other short-lived UI state.
Join with initial presence
Section titled “Join with initial presence”app.post("/rooms/:roomId/join", async (request) => { const pathSegments = new URL(request.url).pathname.split("/") const roomId = pathSegments[2] return await live.room(roomId).join({ presence: { status: "online", typing: false, }, })})join() returns the member record:
{ room: "project_123", kind: "room", memberId: "user_123", joinedAt: "2026-05-25T00:00:00.000Z", lastSeenAt: "2026-05-25T00:00:00.000Z", metadata: {}, presence: { status: "online", typing: false }}Update presence
Section titled “Update presence”app.post("/rooms/:roomId/presence", async (request) => { const pathSegments = new URL(request.url).pathname.split("/") const roomId = pathSegments[2] const body = await request.json()
return await live.room(roomId).presence({ presence: { cursor: body.cursor, selection: body.selection, typing: body.typing, }, })})Presence values are JSON. Keep them small and focused on the live UI state a client needs to render.
Presence examples
Section titled “Presence examples”Use the same presence() method for different live UI needs:
await room.presence({ presence: { status: "online", typing: true, },})await room.presence({ presence: { cursor: 128, selection: { from: 120, to: 128 }, },})await room.presence({ presence: { tool: "pen", viewport: { x: 120, y: 80, zoom: 1.25 }, },})List active members
Section titled “List active members”app.get("/rooms/:roomId/members", async (request) => { const pathSegments = new URL(request.url).pathname.split("/") const roomId = pathSegments[2] const members = await live.room(roomId).members({ limit: 100, })
return Response.json({ members })})Each member includes metadata, presence, actor, joined time, and last seen time.
Leave a room
Section titled “Leave a room”app.post("/rooms/:roomId/leave", async (request) => { const pathSegments = new URL(request.url).pathname.split("/") const roomId = pathSegments[2] return await live.room(roomId).leave()})Use leave() when a user closes a document, leaves a lobby, or disconnects
cleanly.
Member IDs
Section titled “Member IDs”By default, Realtime derives a member ID from the resolved actor. Pass
memberId when you need a stable client or device key:
await room.join({ memberId: `device_${deviceId}`, presence: { status: "online", },})This is useful when one user can have multiple tabs or devices in the same room.
Presence and room metadata
Section titled “Presence and room metadata”Use presence for per-member live state and metadata for shared room state:
await room.metadata({ metadata: { title: "Incident response", mode: "war_room", locked: false, },})
await room.presence({ presence: { status: "online", role: "incident_commander", },})Clients can render shared room settings and member-specific state separately.