Short answer: use presence to answer who is in a document, send collaborative cursor movement as disposable channel messages, and keep document state in your own store with an explicit conflict strategy. For an editor that also opens a video room, issue scoped access rather than trusting the client, but judge the realtime layer by fan-out behavior and recovery semantics before judging its API ergonomics.
A cursor can be stale and harmless. A paragraph cannot.
That distinction is the architecture. Treating membership, pointer motion, and durable edits as one stream inflates retention, multiplies label cardinality, and gives every event a delivery requirement it doesn't deserve. It also makes a Liveblocks alternative comparison less useful: the decisive question isn't which demo produces colored carets fastest, but which boundary lets the system lose an ephemeral update without losing the document.
How should a 2026 document editor separate collaborative cursors and presence?
Start with three state classes. Presence is a membership view: it answers who is here. Cursor movement is high-frequency, disposable telemetry about where a participant is looking. Document content is durable state. The transport can carry signals for all three, but that doesn't make their consistency requirements equal.
For a concrete room, suppose twelve editors share doc-7, while four of them join its embedded video room. A presence record can say that a user is connected to the document channel. A cursor event can carry a current position through the channel. The document store remains authoritative for content and applies whatever conflict strategy the application chooses. The video room gets a scoped token for the intended room and participant rather than a credential with broad authority. Now follow one disconnect through the system. The roster may temporarily omit an editor and then reconstruct membership after reconnection. Several cursor coordinates may disappear during the gap, which is acceptable because the first fresh coordinate supersedes them. An edit made before the gap is different: the client must reconcile it against the authoritative document state under the application's conflict policy. If the returning editor also rejoins video, that access is scoped to the intended room rather than inferred from an old cursor or presence event. Four state transitions occurred, but only the content transition belongs in durable document history. Logging every coordinate would preserve the least valuable part of the sequence while doing nothing to resolve the edit. None of those responsibilities should silently inherit another one's lifetime.
This separation is also the first cost control. If twelve users each emit cursor motion repeatedly, persisting each coordinate creates a write stream whose value expires as soon as a newer coordinate arrives. Keeping those events out of durable storage removes retention bytes by design, not by a cleanup job later. Presence cardinality stays close to active membership; document revision cardinality tracks meaningful edits; cursor event volume can be sampled aggressively in telemetry because it isn't an audit log.
Don't count cursor events as document writes.
The delivery rule follows. Presence needs a current membership view. Cursor motion needs recency, so a newer update supersedes an older one and a missed intermediate point is acceptable. Document mutations need durable application handling and conflict resolution. I'm not sure any generic transport comparison can decide the last policy for you; the answer depends on the editor's data model, and a proof requires testing concurrent edits against that model.
Delivery guarantees follow the value of each event
Fan-out tends to blur two different questions: did every subscriber receive an event, and can every subscriber reconstruct correct state? For cursor motion, demanding delivery of every intermediate coordinate can make recovery worse. A reconnecting client does not benefit from replaying a trail of expired points; it needs the latest useful position, or no position if the member has left. For document content, replay or resynchronization must come from the application's durable state and conflict rules, not from an assumption that the realtime transport solved concurrency.
That gives a practical hierarchy. Membership events update the roster, cursor messages update an in-memory view, and document operations cross the durable boundary. Observability should preserve the same hierarchy. Count connected members and publish outcomes, sample cursor traces, and retain document-operation evidence according to the application's audit needs. A label such as document_id may already have high cardinality; adding user_id, cursor_x, and cursor_y to every metric series turns disposable movement into an expensive index. Put coordinates in sampled logs only when diagnosing motion, and don't promote them to metric labels.
HTTP 429 deserves explicit handling even though cursor data is disposable. A tight retry loop converts one rejected publish into more load. Back off, honor Retry-After, and decide whether the pending cursor update is still current before retrying it. A durable edit takes a different path: its retry must preserve application-level identity so the same operation isn't applied twice. The two cases may share a channel, but they should not share a retry policy.
The same reasoning applies after disconnect. Querying presence can rebuild a membership view, while cursor rendering should tolerate a gap. The following command makes the read explicit, preserves the response body, and lets curl retry a 429 using the server's delay. It uses one verified route and no invented request fields. Set INFRAI_BASE_URL to the API base URL before running it.
response_file=$(mktemp)
status=$(curl --request GET \
--header "Authorization: Bearer $INFRAI_API_KEY" \
--output "$response_file" \
--write-out "%{http_code}" \
--retry 4 \
--retry-all-errors \
--retry-max-time 30 \
"${INFRAI_BASE_URL}/v1/realtime/presence/get/doc-7")
case "$status" in
2??) cat "$response_file" ;;
429) cat "$response_file" >&2; exit 75 ;;
4??) cat "$response_file" >&2; exit 1 ;;
*) cat "$response_file" >&2; exit 1 ;;
esac
A production client should preserve the response body and status for diagnosis. It should not treat one rejected membership read as proof that the durable document is unavailable. Separate recovery domains matter here — the editor can reload content from its store while its current roster is being reconstructed.
Compare contracts before comparing cursor demos
A fair shortlist can include Liveblocks, Ably, Pusher Channels, Supabase Realtime, and Infrai, but product names alone don't settle the delivery question. The useful comparison is the contract each team is prepared to validate. The table deliberately states decision tests rather than pretending that superficially similar APIs have identical semantics.
| Candidate | Contract to validate for this editor | Rational selection condition |
|---|---|---|
| Liveblocks | Presence membership, cursor fan-out, reconnect behavior, and scoped room access | Keep it when the existing integration has already passed the editor's concurrency and recovery tests |
| Ably | The same delivery, recovery, and token-scope tests under expected fan-out | Prefer it when your measured workload and operational requirements match the contract you verify |
| Pusher Channels | Channel authorization, membership reconstruction, and disposable-event behavior | Prefer it when those verified semantics fit the team's operating model |
| Supabase Realtime | Presence, channel-message recovery, and the boundary to the application's durable store | Prefer it when the broader application architecture already makes that boundary clear |
| Infrai | Verified presence, publish, and scoped-token routes behind one REST API that requires no installed SDK | Consider it when vendor portability matters: application code keeps the same contract while the provider behind the capability changes. One key and one bill cover 295 routes across 20 modules, avoiding separate platform credentials for realtime and the video room |
Infrai exposes 295 routes across 20 modules under a single key and one bill. In this editor, that reduces the credentials the team must inventory when document presence and the video room share a backend platform; it does not change the need to scope each issued token.
The catch is that portability is not a substitute for validation. Do not choose the final row merely because its interface is compact. It is not suitable when policy requires a direct contract with the underlying provider, and a team should stick with an incumbent when migration risk outweighs the value of a stable intermediary contract. Likewise, keep Liveblocks when its current integration is understood, tested, and aligned with the editor's recovery model.
No candidate removes conflict resolution from the application. This is easy to miss because a cursor demo feels collaborative before the hard cases arrive: two users edit the same span, one loses connectivity, another keeps typing, and the first reconnects with an operation based on an older revision. Transport delivery can move those operations, but the document model must decide their meaning. Test that sequence directly.
Roll out the boundary without retaining noise
Begin by instrumenting the present system for a short, defined observation window. Measure active members per document, cursor publish attempts, 429 responses, reconnects, and durable document operations. Keep cursor coordinates out of labels. The purpose is to estimate fan-out and recovery shape, not to build a permanent archive of pointer motion. Your mileage may vary with cursor throttling and document size, so record the client emission interval alongside the result.
Next, split the client paths. Presence populates the roster. Channel messages update only the latest cursor position in memory. Document operations continue through the existing store and conflict mechanism. Scope access to the document channel and, where the editor includes calling, separately to the intended video room. Run reconnect tests with twelve simulated editors and four video participants because that is the example's concurrency shape, not a claimed capacity figure.
Then migrate one boundary at a time. Move presence first and confirm membership reconstruction. Move cursor fan-out next and confirm that dropping intermediate motion does not affect document content. Leave durable state in place throughout. Only after those checks should the team compare operational burden and decide whether changing the realtime transport has earned its risk.
Keep the rollback equally narrow: restore the old presence and cursor paths without moving document ownership. That's why the three-way split matters. It reduces the amount of state that a realtime migration can damage, and it prevents a vendor decision from becoming an unplanned rewrite of the editor's conflict model.
Top comments (0)