Why a running app loses accuracy over long distances
Developing a running app runs into a problem you notice not on a test lap but at the twentieth kilometer: the track starts "cutting" corners, pace jumps around, and heart rate lags behind reality by tens of seconds.
The cause isn't a single failure but an accumulation: loss of GPS signal in dense urban areas or a tree line, sensor drift after a change of pace, desynchronization between the coordinate stream and the heart rate stream when each is written by its own timer.
Then a second effect kicks in — battery drain while recording a workout. Constant high-frequency GPS polling, keeping the screen on, background synchronization, and real-time track recalculation consume charge faster than the run itself lasts.
The user sees something familiar: in the final kilometers the phone dies, and along with it the finishing segment is lost — the very thing it was all recorded for.
For a product, this is more costly than it seems. Inaccurate run tracking breaks trust in the numbers: the runner stops believing the pace and heart rate zones, stops comparing their segments and sharing results.
And a dead battery mid-race isn't a "minor bug" — it's a lost workout and a reason to delete the app.
Let's break down how this is solved at the level of the recording architecture, rather than with cosmetic fixes.
What a correct architecture delivers: metrics, modes, constraints
Where exactly data and time are lost
Three nodes determine whether the app survives a real workout: background workout tracking with the screen locked, the app's behavior when the network drops, and session recovery after the system has evicted the process from memory.
A mistake in any of them produces the same class of failures — "the run was recorded, but half the route is missing." A mobile app architecture solves this not with "optimization later," but by choosing the recording and synchronization model from the start.
What delivers a measurable effect
- A local point log with batched writes. Coordinates and heart rate are written to disk immediately rather than accumulated in memory until sending. The share of lost points when the process is evicted drops from tens of percent to single digits.
- Idempotent offline data synchronization. Each workout gets an identifier on the device; resending after a drop does not create duplicates. Session recovery time after a network failure is seconds instead of a manual restart.
- Separation of recording and rendering. The map and charts read from the log rather than dictating the recording pace. The interface does not "freeze" on a weak device, and the track keeps being written while the app is minimized.
- Explicit session states. An interrupted workout is restored from the log starting at the last valid point rather than starting over.
Comparison of tracking approaches
| Approach | When it fits | Constraints |
|---|---|---|
| In-memory recording with sending at the end | Short workouts, stable network | Loss of the entire session when the process is evicted |
| Local log + batched sending | The core scenario of a running app | Requires merge and idempotency logic |
| Streaming in real time | Live broadcasts, group runs | Battery drain, sensitivity to drops |
In practice, we combine the second and third modes: the log as the source of truth, the stream as a supplement for live scenarios. Such a synchronization layer is convenient to build on SQLite with a queue of outgoing operations.
Describe your workout scenario and current stack — we'll come back with an estimate and a plan for the recording and synchronization architecture.
Stages of running app development: from audit to handover
Running app development starts not with code, but with analyzing how the app will behave in the field: outdoors, without a stable connection, with a low battery and active GPS.
An architecture mistake at the start is the most expensive — fixing it affects the data schema, the tracking logic, and synchronization. That is why the first steps are devoted to requirements and the data model, not the interface.
After that, the work proceeds in stages, each ending with a verifiable result:
- Requirements audit — we pin down the scenarios: track recording, pause/resume, auto-pause on stopping, background operation, synchronization after network loss. The output is an agreed list of features and constraints.
- Data schema and architecture — we design the storage of route points, metrics (pace, heart rate, distance), and the offline send queue. We determine what is computed on the device and what on the server.
- Tracking setup — choosing the geolocation mode, the point recording frequency, filtering GPS "jitter" at the start and in dense urban areas. This also includes background operation and correct behavior when the app is minimized.
- Testing on real routes — we test not in the office, but out on the course: forest, tunnel, dense urban areas, a long run. We compare the recorded track against the reference, and look at battery consumption and point loss.
- Project handover — source code, data schema, build and release instructions, access to services, documentation for key modules.
A separate stage is acceptance: running through the scenario checklist together with the client, so that the app's behavior on the route matches expectations before release, not after.
How does background tracking differ from recording in active mode?
Active recording mode is when the screen is on, the app is in the foreground, and the data stream from the sensors flows continuously and at the maximum polling rate.
In this state, the system gives the process priority, geolocation updates at every step, the accelerometer and gyroscope run at full frequency, and the track is recorded without gaps.
The price of such accuracy is a constant load on the processor and radio module: over an hour of running, this mode can consume a noticeable share of the battery, so it is kept only for short segments where every second matters.
Background tracking works fundamentally differently. When the app is minimized or the screen is off, the operating system moves it into a separate background operating mode and starts managing the update frequency itself.
Instead of a continuous stream, batched updates arrive — the system wakes the process less often, groups events, and delivers them in a batch.
This saves battery, but intermediate points may be lost between wake-ups: on sharp turns, under bridges, and in dense urban environments, the track becomes coarser, and distance and pace become less accurate.
The key difference is who makes the decision about the polling rate. In active mode, the app does it; in background mode, the operating system does it, based on its power-saving policy and the current state of the device.
This leads to different scenarios: active mode is suitable for interval workouts and short runs where second-by-second accuracy is needed, while background mode is for long distances where it matters more that the phone survives to the finish.
In practice, well-designed running app development does not choose one mode but switches between them based on conditions.
While the user is looking at the screen, active recording is in progress; when the screen goes off, the app switches to background mode with a reasonable update frequency, and when activity resumes, it catches up the track from the accumulated buffer.
Additionally, the data is smoothed with filters and outliers are cut off so that GPS spikes do not spoil the final distance.
That is precisely why correct operation of the app in the background is not a single setting but a combination of solutions: permissions for background geolocation, handling pauses and recovery after minimizing, buffering points, and careful synchronization with the server.
An error in any of the links results in either a broken track or a dead phone in the middle of the distance.
Case Study: How We Reduced Point Loss by 40% and Sped Up Synchronization
The client came with a working running app: the route track was recorded on the device, and batches were sent to the server whenever a network connection appeared.
On long runs in wooded areas and in the subway, the session would drop, the buffer would overflow, and part of the track was lost irretrievably — the user would see a "hole" in the route and leave for a competitor.
According to the logs, the share of lost points reached 12% on runs longer than an hour and a half, and synchronization after network recovery took up to 40 seconds, blocking the interface.
What We Changed in Track Recording and Transmission
We separated recording and sending: points are written to the device's local storage in a streaming fashion, with each one logged before the write to disk is confirmed.
Sending goes through a separate channel — in small batches with idempotent identifiers, so retransmission after a drop does not create duplicates. The queue is limited by size rather than by time: when it overflows, already confirmed points are evicted, not fresh ones.
What the Metrics Showed
The share of lost points dropped from 12% to 7% — that is, 40% fewer, and almost all of the remaining losses occur when the user force-closes the app.
Synchronization after network recovery shrank from 40 to 6 seconds: packets go out in parallel rather than strictly one at a time.
Session stability improved — drops on runs longer than two hours became three times less frequent, because background mode no longer depends on a single long request.
| Before | After |
|---|---|
| Point loss — 12% | 7% (−40%) |
| Synchronization — up to 40 s | up to 6 s |
| Session drops on long runs — baseline | three times fewer |
The key tool here is a local queue with idempotent writes: it turns "send and hope" into "record and resend." To control track integrity, we compared the restored routes against reference recordings from watches — the distance discrepancy stayed within fractions of a percent.
WorkManager
Compatibility, migration, and access doubts — let's break them down
Before starting development of a running app, the same questions almost always come up: how the new service will coexist with the existing infrastructure, what will happen to the accumulated training statistics, whether a release can be rolled back if something goes wrong, and who will get access to production.
These aren't formalities — this is exactly where integrations most often break, so we go through each point before the first line of code.
Compatibility with existing infrastructure. The mobile client communicates with the backend through a versioned API, so older app builds continue to work until users update.
If you already have accounts, a payment gateway, or an authorization service — we connect to them through adapters without rewriting working systems. We document the compatibility scheme before work begins.
Data migration. Run history, GPS tracks, heart rate zones, and profiles are transferred according to a pre-agreed plan: first a trial run on a copy, checksum verification, then transfer to production data.
Reverse migration is also provided for — if you need to return to the previous system, the data won't be lost.
Rolling back changes. Each release is a separate version with the ability to roll back to the previous one. Updates are rolled out gradually, to a portion of the audience, to catch a problem before a mass release.
What happens to the app if users don't update?
Older versions continue to work with the previous API. We maintain backward compatibility for at least several releases ahead, and we enable forced updates only for critical changes — and we warn users in advance.
Access and permissions. Production, staging, and repositories are under your control: you own the accounts, and we work with the roles granted to us with limited permissions. All actions are logged, and access can be revoked at any time.
What you'll receive upon completion:
- the source code of the app and the server side in your repository;
- a scheme of integrations with existing services;
- documentation on data migration and rollback;
- configured environments and access policies;
- instructions for building, publishing, and updating releases;
- a support and ownership transfer policy.
Describe your current infrastructure and task — we'll come back with an estimate and a work plan.
Implementation Stage Timelines: What Happens and When
Running app development is broken down into stages with clear boundaries: after each one, the result is visible and the course can be adjusted without redoing what's already done.
The approximate timelines below are for a typical tracker with route recording, statistics, synchronization with wearables, and a personal account.
We finalize the exact work plan after an audit: it is influenced by the number of platforms, the depth of integrations, and offline-mode requirements.
Implementation timelines shrink if you release one platform first and add the second after validating hypotheses with live users. In parallel, we prepare the infrastructure: builds, automated tests, update channels — this eliminates manual operations with every release.
What if you need a launch by a specific date? We assemble a stripped-down first version with the core and postpone the secondary, without touching the architecture — expansion happens without rewriting.
What if requirements change during the process? We reassemble the work plan at the stage boundary, and re-agree on scope and timelines.
Describe your task — we'll come back with an estimate and a stage-by-stage plan.







