Skip to content

CRDT rooms

CRDT rooms are Realtime rooms with document update and awareness helpers. Use them for collaborative editors, whiteboards, shared forms, kanban boards, canvas tools, and any feature where multiple clients edit the same state.

Terminal window
const document = live.crdtRoom("document_123")

CRDT rooms also support the normal room methods such as join, presence, members, history, snapshot, and restore.

Send each document update with a client ID and optional clock:

Terminal window
app.post("/documents/:documentId/updates", async (request) => {
const pathSegments = new URL(request.url).pathname.split("/")
const documentId = pathSegments[2]
const body = await request.json()
const document = live.crdtRoom(documentId)
return await document.applyUpdate({
update: body.update,
clientId: body.clientId,
clock: body.clock,
})
})

update is JSON so you can store a compact operation, a patch envelope, or an encoded update payload your client library understands.

When your client uses Yjs, send the binary update as base64:

Terminal window
await live.crdtRoom("document_123").applyYjsUpdate({
updateBase64,
clientId: "client_1",
clock: 42,
})

Read missing updates with a state vector:

Terminal window
await live.crdtRoom("document_123").syncYjs({
stateVectorBase64,
})

See Yjs for the full flow.

Awareness is live client state associated with a collaborative document:

Terminal window
app.post("/documents/:documentId/awareness", async (request) => {
const pathSegments = new URL(request.url).pathname.split("/")
const documentId = pathSegments[2]
const body = await request.json()
return await live.crdtRoom(documentId).awareness({
clientId: body.clientId,
state: {
cursor: body.cursor,
selection: body.selection,
color: body.color,
},
})
})

Use awareness for cursors, selections, active tools, viewport ranges, and user display details.

Terminal window
app.get("/documents/:documentId/state", async (request) => {
const pathSegments = new URL(request.url).pathname.split("/")
const documentId = pathSegments[2]
const sinceClock = Number(new URL(request.url).searchParams.get("sinceClock") ?? 0)
return await live.crdtRoom(documentId).document({
sinceClock,
limit: 200,
})
})

The result contains ordered updates and current awareness state:

Terminal window
{
room: "document_123",
kind: "room",
updates: [
{
updateId: "upd_123",
update: { ops: [{ insert: "hello" }] },
clientId: "client_1",
clock: 1,
appliedAt: "2026-05-25T00:00:00.000Z"
}
],
awareness: [
{
clientId: "client_1",
state: { cursor: 5 },
updatedAt: "2026-05-25T00:00:00.000Z"
}
]
}

Use snapshots to create checkpoints:

Terminal window
const snapshot = await live.crdtRoom("document_123").snapshot()

Snapshots include metadata, members, and recent messages. Store the returned snapshotId when users need named versions or restore points.

Terminal window
await live.crdtRoom("document_123").restore(snapshot.snapshotId)