Live cursors in a mobile app: where synchronization breaks
Live cursors in an app are the interface element most sensitive to the network.
Each participant's pointer position changes dozens of times per second, and any delay in updating the position is immediately visible to the eye: someone else's cursor twitches, lags half a second behind, or gets stuck in one spot while the person is already writing somewhere else on the board.
Unlike document text, where a divergence can be reconciled later, there is no point in "catching up" to pointer movement — only the last frame matters.
The root of the problem lies in the transport. If you send every finger displacement as a separate message over a reliable channel with delivery confirmation, on a weak network the queue grows faster than it can drain, and the cursors start showing the past.
That is why the stream of coordinates is moved to a separate lightweight channel without delivery guarantees: a lost intermediate position is not needed, since the next one will supersede it within a few milliseconds.
A separate challenge is synchronizing cursors across platforms: phone, tablet, and web send events at different frequencies and in different coordinate systems, and without normalization to a shared board space the cursor "drifts" when the screen rotates or the zoom level changes.
The second source of failures is collaborative editing on a phone. The mobile network drops when switching between a cell tower and Wi-Fi, the app goes to the background and back, while the server keeps waiting for packets from a "dead" connection.
If this is not tracked, the cursors of disappeared participants remain on screen, and those who return get duplicated.
The fix is explicit presence signals: a short time-to-live for a participant's marker, automatic reconnection with list recovery, and a soft fade-out of the cursor on connection loss instead of an abrupt disappearance.
Finally, rendering. Even perfectly delivered coordinates can be ruined if the entire canvas is redrawn on every movement — on a weak device this causes stutter and a drop in the responsiveness of your own input.
Cursors are drawn on a separate layer above the content, only the changed elements are updated, and motion is interpolated between the received points so that with sparse packets the pointer glides rather than jumps.
We break down how this is handled at the level of channel architecture, message format, and presence logic — and why the right solution is almost always cheaper than it seems.
What well-tuned cursor mechanics deliver
Well-tuned cursor mechanics are first and foremost a predictable position update rate.
When engineers set it deliberately rather than "however it turns out," the cursor moves smoothly, without jerks or "sticking," and behavior does not depend on how loaded the channel is for a particular user.
It is the stability of the rate, not its maximum, that determines the feeling of smoothness: the user notices not the high pace, but the dips in it.
The second measurable effect is controlled traffic consumption. Transmitting coordinates is a stream of small messages, and without well-tuned mechanics it either balloons with every finger movement or, conversely, economizes so much that the cursor twitches.
Well-tuned mechanics maintain the balance: the volume of data per session stays within reasonable limits even during active drawing and dragging of objects, and on a weak network degradation happens gradually rather than as a cutoff.
The third effect is predictable battery load. A constantly active position update channel is one of the most unnoticed energy consumers: it prevents the device from going to sleep and keeps the radio in active mode.
When the mechanics are well-tuned, the app reduces activity when there are no cursors on screen and does not spend charge on an exchange the user cannot see.
Finally, well-tuned mechanics mean that cursor behavior is reproducible: engineers know how many messages are sent per second, how the app behaves when connectivity is lost, and how quickly cursors return to sync after reconnection.
This turns "magic" into an engineering quantity that can be measured, tested, and improved, rather than hoping that "this time it won't lag."
Approaches to Cursor Position Transmission: Comparing Options
Transmitting cursor coordinates is a trade-off between update frequency and channel load. Each option takes its own approach to how often the position is sent and how it responds to a connection loss. Below are three schemes that are realistically chosen between at the start.
| Option | When it fits | Limitations |
|---|---|---|
| Continuous stream | Real-time collaborative editing where smooth movement matters | Keeps the connection open at all times, sensitive to unstable networks and network switching on mobile |
| Batched sending | Comments, annotations, infrequent actions where a fraction-of-a-second delay is not critical | Movement looks jerky, and when a packet is lost the position "jumps" |
| Hybrid scheme | Most mobile scenarios: active movement plus pauses | Harder to implement — requires logic for switching between modes |
Continuous stream
The connection is kept open, and coordinates are sent continuously.
It delivers the smoothest picture, but on a mobile channel it is the most expensive option: when the app is minimized or the device switches between networks, the stream breaks and must be restored without losing position.
Batched sending
Positions accumulate and are sent in groups — economical in terms of traffic and resilient to short interruptions. The price for this is latency: a colleague's cursor moves discretely rather than smoothly.
Hybrid scheme
Active movement goes as a stream, while during pauses transmission switches to batches. This removes the main load but preserves smoothness where it is visible. This is the scheme we most often build on — let's look at how to configure it for your scenario.
How we implement live cursors in a mobile app
Implementing live cursors starts not with code, but with analyzing scenarios: where exactly in the app several people work simultaneously and what each of them should see.
At this stage we determine how many participants are in a session, how often the pointer moves, whether movement history is needed, and how the mechanics behave under poor connectivity.
The choice of transport and update frequency depends on the answers — there is no universal recipe here.
Then we proceed through stages, each ending with a verifiable result.
- Analyzing scenarios and constraints. We agree on which screens get live cursors, who sees other people's pointers, and how they coexist with the existing interface. The output is a scenario map with priorities.
- Designing the data model. We define the cursor event format, the binding to a session, and the rules by which a pointer disappears when connectivity is lost. This eliminates most future conflicts.
- Setting up synchronization. We choose transport for the task — a persistent channel for active sessions, state exchange on reconnection. We build in motion smoothing so the pointer doesn't jitter on an unstable network.
- Client-side implementation. We embed cursor rendering into the existing interface layer without breaking current animation and gestures. We verify that the mechanics don't interfere with scrolling and input.
- Testing on devices. We run the scenarios on real devices of different classes: parallel sessions, switching between networks, minimizing the app, prolonged connection retention.
- Load optimization. We look at how much traffic and battery the mechanics consume during an active session, and reduce update frequency where precision is not critical.
- Handover of the solution. We deliver the configured mechanics, operational guidelines for working with it, and instructions for the team that will develop the feature further.
This order makes it possible to launch live cursors without reworking existing screens and with predictable behavior during connectivity failures. Describe your scenario — we'll get back to you with an estimate and an implementation plan.
Artifacts: diagrams, configurations, and regulations
Everything that describes how live cursors work is delivered as working documentation, not verbal agreements. The customer's engineer opens the package and sees how position transmission is structured, where limits are configured, and what to do in case of a failure.
- Data flow diagram: the path of an event from a touch on the device to rendering for other participants, buffering points, and places where loss or delay is possible.
- Client configuration: parameters for the coordinate sending rate, smoothing thresholds, rules for extinguishing the cursor when the application goes to the background.
- Access policies: which participants can see others' cursors, how permissions are granted and revoked, and what happens when a session is interrupted.
- Overload behavior regulations: message priorities, limits on the number of simultaneous cursors, and the order of interface degradation.
- Instructions for connecting new event types: how to add a gesture or a label without breaking compatibility with older versions of the application.
- Cursor documentation: description of message formats, error codes, and recovery scenarios after a connection loss.
- Acceptance checklist: a set of checks by which the customer independently confirms that collaborative presence works on target devices and networks.
The package is designed so that support can be carried out without us: the engineer understands the topology from the diagrams, where to change behavior from the configuration, and who to grant access to from the policies. This removes the main maintenance risk, when knowledge lives in the head of a single developer.
Describe your task — we will come back with an estimate and a plan, including the documentation scope for your environment.
Case Study: How We Eliminated Cursor Jumps in a Collaborative Notes App
What It Was Like Before
The client is a collaborative notes service: several people edit the same document simultaneously, and cursor positions must be visible to all participants.
Initially, cursors were transmitted through a shared text synchronization channel: every mouse movement was sent as a separate message, with no batching and no consideration for network conditions.
On stable Wi-Fi, this looked acceptable, but as soon as a user stepped into an elevator or switched to a weak mobile connection, cursor jumps began: the marker would freeze, then leap across half the screen, and sometimes remain stuck at a spot where the person had long since left.
The problem wasn't the delay itself, but the fact that lost positions weren't marked in any way. Participants saw an outdated cursor and assumed it was current — this eroded trust in collaborative editing more than an honest delay would.
We investigated exactly where connection stability was being lost and rebuilt the position transmission layer.
What We Changed
We separated two data streams: text edits go through a reliable channel with delivery confirmation, while cursor positions go through a separate lightweight stream where losing a single message isn't critical because the next one supersedes the previous one.
Movements are batched into a single packet over a short interval, so instead of dozens of tiny messages, one is sent — the channel stops choking on a weak network.
We added smoothing on the receiving end: between incoming points, the position is interpolated, so the marker moves smoothly rather than jumping.
If updates from a participant don't arrive beyond a threshold, the cursor is marked as inactive and dimmed — the user immediately sees that the data is stale instead of having false confidence.
What It Became
| Metric | Before | After |
|---|---|---|
| Position update frequency | unstable, depended on load | steady, with packet batching |
| Share of lost positions on a weak network | noticeable, unmarked | close to zero, stale ones are marked |
| Interface responsiveness during editing | dips during active movement | steady, streams are separated |
Cursor jumps are gone: on a weak connection, the marker either moves smoothly or honestly shows that the participant is inactive. Collaborative editing no longer depends on the connection quality of each individual user.
How does a live cursor differ from a presence indicator?
A presence indicator answers the question "who is currently in the room": when an event about a participant joining or leaving arrives, the application shows an avatar, name, and status.
Data is updated infrequently — once every few seconds or when the roster changes — so the load on the channel is minimal, and desynchronization is almost imperceptible.
This mode covers participant lists, online counters, "typing" statuses, and collaborative editing, where what matters is the person's presence itself, not their actions at a specific point.
A live cursor is a continuous transmission of position: pointer coordinates, selection, sometimes clicks, which are broadcast to other participants at a frequency close to real time.
Here, not only delivery matters but also order: position events become stale instantly, and losing a single packet is not critical, but a delay of hundreds of milliseconds already destroys the sense of presence.
That is why the position stream goes through a separate low-latency channel, without delivery acknowledgments and with outdated values discarded on the recipient's side.
The key difference lies in the nature of the data. A presence indicator describes a state that changes infrequently and must be consistent: if a participant has left, all clients must see it.
A live cursor describes a stream where consistency is not needed — only the latest position matters, and intermediate ones can be safely dropped.
Hence the different transport requirements: a reliable channel with acknowledgments suits statuses, while positions need a fast and "lossy" one, tuned for minimal latency.
The choice of mechanism also dictates the display modes. If the task is to show that a colleague is nearby, an indicator is enough: it is cheaper, more stable, and does not load the device.
If real-time collaborative drawing, layout markup, or document navigation is needed, a live cursor is indispensable — but then you will have to account for event throttling, motion smoothing between frames, and correct behavior when the connection is lost, otherwise the pointers will jitter or freeze.
In practice, these mechanisms are often combined: a presence indicator maintains the room roster and access rights, while a live cursor runs on top of it as a separate stream.
This separation allows both channels to be scaled independently and the expensive position transmission to be disabled where it is not needed.
Common technical concerns about cursors
Cursors are the "noisiest" part of collaborative editing: every pointer movement generates an event, and for a document with a dozen participants, events pile up into thousands per minute. Below is a breakdown of the technical concerns that most often come up during the design phase.
How does this affect server load?
The stream of coordinates does not go into persistent storage — it lives in RAM and is transmitted over a real-time channel. We batch events: the position is not sent on every movement, but at a frequency sufficient for smoothness, and redundant intermediate points are discarded.
If the connection drops, the server does not accumulate a "tail" of events, but instead sends the client only the current state — after reconnecting, a participant sees correct positions rather than an avalanche of stale ones.
What happens when the connection drops?
The client enters reconnection mode with an increasing pause between attempts so as not to flood the channel.
While there is no connection, local edits continue to be applied and are queued; after recovery they are synchronized, and other participants' cursors are redrawn from the fresh state.
Conflicts are resolved by modification time, so a network loss does not result in "stuck" cursors from others on the screen.
Are cursors compatible across different platforms?
The logic is shared across all platforms; only the rendering layer differs: on one system the pointer is drawn on top of the native interface layer, on another — inside the graphics canvas.
We establish a unified message format and identical behavior when the app is minimized and when screen orientation changes, so a participant on a phone and on a tablet sees the same picture.
Doesn't this drain the battery?
The main drain comes not from the transmission of coordinates itself, but from the redraw frequency. We lower it when the app goes to the background, stop the stream when the screen is inactive, and do not keep a persistent connection where it is not needed.
In practice, an app with active cursors consumes energy comparably to normal editing mode — the difference is noticeable only during prolonged continuous work in the background, and we address that with a separate policy.
If you still have questions about your configuration — describe your scenario, and we will get back to you with an estimate and a plan.
Let's discuss your cursors task
To come back with an implementation estimate rather than generalities, we need to understand three things: how collaboration in the app works today, how many participants are in a single session, and which platforms are the priority.
This determines the choice of transport for live cursors — a persistent connection, streaming over it, or periodic polling — as well as the position update frequency and the message compression strategy.
We put together the work plan after a short review.
Usually it looks like this: we align on the technical requirements, design the position transmission channel and the presence model, embed the layer into the existing architecture, wire up handling for disconnects and reconnections, test under load, and hand over documentation with the configuration.
Send whatever you have on hand — that's enough for an initial estimate:
- a description of the scenario: where exactly the cursors are needed — a board, an editor, a map, co-viewing;
- the current application architecture and the list of platforms you support;
- the expected number of concurrent participants in a single session and the peak load;
- requirements for response latency and the acceptable traffic consumption on the device;
- how authorization and access rights to shared objects work today;
- timeline constraints and which screens must not be touched;
- the contact of an engineer on your side for follow-up questions.
If you don't have ready data, that doesn't block the start: we'll pin down some parameters on a call, and clarify the rest during the review. Describe the task in two or three paragraphs — we'll come back with an estimate, a work plan, and the team composition for your scenario.







