DEV Community

M TECHUB LLc
M TECHUB LLc

Posted on

Fitness Tracking App Development: Handling Duplicate and Missing Activity Data

TL;DR

  • Use scoped source identifiers to recognize repeated records.
  • Treat corrections as updates, not additional activity.
  • Resolve overlapping sources before calculating step totals.
  • Represent missing coverage separately from recorded zeros.
  • Persist changes before advancing synchronization checkpoints.
  • Recalculate historical summaries when delayed records or deletions arrive.

1. Separate Three Problems That Look Like Duplicates

Not every repeated-looking observation should be removed.

Situation Example Responsibility
Repeated delivery A retry sends the same step record again Record deduplication
Record correction A source revises a workout’s duration Version handling
Overlapping observations A phone and watch record the same walk Source selection and aggregation

Two heart-rate sensors might independently report 92 bpm at the same timestamp. Matching values do not prove duplication.

Conversely, records with different identifiers might describe the same workout because it passed through separate integrations.

Deduplication answers: “Have we already stored this source record?”

Aggregation answers: “Which stored observations should contribute to this result?”

Keep those questions separate.

2. Define an Internal Record Contract

Translate source-specific records into a consistent internal representation.

{
  "user_id": "user-42",
  "source": "watch-provider/account-17",
  "source_record_id": "steps/record-983",
  "metric": "steps",
  "value": 840,
  "unit": "count",
  "start_at": "2026-10-18T08:00:00Z",
  "end_at": "2026-10-18T08:10:00Z",
  "source_revision": 3,
  "received_at": "2026-10-18T08:14:20Z"
}
Enter fullscreen mode Exit fullscreen mode

These are internal schema fields. Not every wearable API supplies equivalent fields.

The contract should establish:

  • User identity from authenticated application context.
  • A stable integration/account namespace.
  • A source record identifier.
  • Supported metrics and canonical units.
  • Event timestamps separate from receipt timestamps.
  • Available source revision metadata.
  • Provenance and processing status.

If record identifiers are unique only within a metric type, include that type in the internal identifier or unique key.

If one record contains a heart-rate series, preserve the parent relationship when expanding it into samples. Corrections and deletions must reach every affected sample.

Define collection requirements before integration work begins. A fitness app data collection checklist helps connect each field to a product need.

3. Make Repeated Delivery Safe

Assume a synchronization request can be retried after its records have already been stored.

For example:

  1. The app submits a batch.
  2. The backend commits it.
  3. The response is lost.
  4. The app submits the same batch again.

A retry should leave records and totals unchanged.

For a simplified interval-step table:

CREATE TABLE step_record (
    user_id text NOT NULL,
    source text NOT NULL,
    source_record_id text NOT NULL,
    source_revision bigint NOT NULL
        CHECK (source_revision >= 0),
    steps bigint NOT NULL
        CHECK (steps >= 0),
    start_at timestamptz NOT NULL,
    end_at timestamptz NOT NULL,
    received_at timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (user_id, source, source_record_id),
    CHECK (end_at > start_at)
);
Enter fullscreen mode Exit fullscreen mode

The key scopes record identity to the user, source namespace, and source record.

This teaching example requires a trustworthy, monotonically increasing source revision. It is not a universal platform adapter.

Use a parameterized upsert:

INSERT INTO step_record AS stored (
    user_id,
    source,
    source_record_id,
    source_revision,
    steps,
    start_at,
    end_at
)
VALUES (
    $1, $2, $3, $4, $5, $6, $7
)
ON CONFLICT (user_id, source, source_record_id)
DO UPDATE SET
    source_revision = EXCLUDED.source_revision,
    steps = EXCLUDED.steps,
    start_at = EXCLUDED.start_at,
    end_at = EXCLUDED.end_at,
    received_at = EXCLUDED.received_at
WHERE EXCLUDED.source_revision > stored.source_revision;
Enter fullscreen mode Exit fullscreen mode

Bind $1 through $7 using the database driver’s parameter API.

Incoming revision Stored revision Outcome
3 No record Insert
3 3 Leave unchanged
4 3 Update
2 4 Leave unchanged

PostgreSQL documents conditional updates in its INSERT and ON CONFLICT reference.

An equal revision containing different values needs a conflict signal. Do not silently classify it as an ordinary retry.

Receipt time does not prove that a source record is newer. An old payload can arrive after a correction.

When reliable ordering metadata is unavailable, use an integration-specific reconciliation strategy. A payload hash detects identical content but cannot establish version order.

4. Resolve Overlap Before Summing Steps

A unique key prevents repeated records. It does not prevent duplicate counting across devices.

Source Interval Steps
Watch 08:00–08:10 840
Phone 08:00–08:10 790

A raw sum produces 1,630 steps. The records do not establish that the user took that many distinct steps.

Define a source-selection policy:

  1. Prefer the user-selected primary source.
  2. Use another source for demonstrably uncovered intervals.
  3. Retain contribution details for troubleshooting within the retention policy.

Partial overlap is harder.

If a phone reports 790 steps across ten minutes and a watch covers only five minutes, allocating half the phone count assumes uniform activity.

Prefer finer records when available. Otherwise, document the limitation and distinguish estimated allocation from exact reconstruction.

Health Connect provides its own aggregation behavior. Do not add platform totals to the records that already contributed to them.

These decisions belong in the broader wearable workout data handling design.

5. Model Missing Data Explicitly

A missing observation is not a recorded zero.

Condition Meaning
Step record reports zero Source recorded zero steps for that interval
No records received Activity is unknown
Workout exists without heart-rate samples Session available; heart-rate coverage unavailable
Latest records stop hours ago Displayed activity may be incomplete

Store synchronization state separately from measurements.

{
  "source": "watch-provider/account-17",
  "last_successful_sync_at": "2026-10-18T08:15:00Z",
  "latest_event_end_at": "2026-10-18T08:10:00Z",
  "sync_state": "idle",
  "coverage_state": "unknown"
}
Enter fullscreen mode Exit fullscreen mode

A successful request does not establish complete coverage. The device might not have uploaded its latest observations.

The earliest and latest timestamps also do not prove continuous measurement between them.

In the interface:

  • Show the last successful synchronization.
  • Leave meaningful gaps in heart-rate charts.
  • Mark partial totals when coverage information supports that label.
  • Display unavailable data without inventing zeros.
  • Label estimated values if interpolation supports a specific feature.

6. Process Late Arrivals and Deletions

If yesterday’s workout arrives today, store its event timestamps and recompute the affected historical summaries.

Its receipt date should not move the activity into today’s total.

Corrections can change both values and intervals. If a workout moves across a reporting-day boundary, invalidate the original day and the corrected day.

Define calendar reporting during travel and daylight saving transitions. UTC storage preserves instants; your reporting-zone policy determines calendar-day membership.

Deletion handling also needs explicit logic.

HealthKit anchored queries support retrieving added samples and deleted objects. Health Connect synchronization includes upsertion and deletion changes.

Preserve the identifiers needed to map source deletions to local records.

After a deletion:

  1. Exclude the record from derived results.
  2. Recompute affected summaries.
  3. Prevent stale retries from restoring deleted activity.
  4. Apply the retention policy to associated records.

A minimal tombstone or ordered change state can prevent resurrection. The correct ordering strategy depends on the integration.

7. Advance Checkpoints After Durable Processing

A synchronization checkpoint represents processed progress.

Advancing it before persistence can create a permanent gap:

Fetch changes
Advance checkpoint
Crash before persistence
Resume after missing records
Enter fullscreen mode Exit fullscreen mode

Use this sequence:

Fetch changes
Persist records and deletion state
Persist aggregate invalidation work
Advance checkpoint
Enter fullscreen mode Exit fullscreen mode

Where possible, commit related database changes together.

For asynchronous aggregation, a transactional outbox can preserve recomputation work alongside record updates.

A crash after persistence but before checkpoint advancement can cause replay. Idempotent writes make that replay manageable.

Do not increment a daily total for every delivery. Derive totals from selected current records or use transactional change calculations that distinguish retries from actual updates.

8. Test the Failure Cases

Check stored state and user-visible results.

Scenario Expected result
Same record delivered repeatedly One current record; unchanged total
Higher revision corrects steps Updated record and affected aggregate
Older revision arrives later Newer data remains
Phone and watch overlap Source policy applies
Workout arrives the next morning Correct historical day updates
Heart-rate samples are missing Visible gaps; no fabricated readings
Access becomes unavailable Appropriate unavailable state
Source deletes activity Contribution removed
Sync crashes before checkpoint commit Safe replay
User crosses a time-zone boundary Reporting-day policy applies

Include these fixtures when testing fitness app integrations.

Keep processing correctness separate from measurement accuracy. Faithfully importing heart-rate samples does not establish that the sensor measured correctly.

That requires a separate fitness tracker accuracy testing protocol.

9. Monitor What Users Experience

Track:

  • Repeated-delivery and stale-update rates.
  • Validation failures by source and reason.
  • Event age when records arrive.
  • Time from receipt to durable processing.
  • Synchronization failures and checkpoint recovery.
  • Aggregate recomputation failures.
  • Available coverage where it can be established.

A low database-conflict rate does not prove that cross-device double counting is solved.

Avoid logging unnecessary health values or full payloads. Use reason codes, restricted diagnostics, and defined retention periods.

For teams planning the wider product, healthcare and fitness app development should connect integration decisions with tracking behavior, privacy controls, and user-facing explanations.

Users should be able to understand which source contributed, when it last updated, and whether the displayed result may be incomplete.

Implementation Checklist

  • [ ] Scope record identity to the user and source namespace.
  • [ ] Keep event time separate from receipt time.
  • [ ] Define how source corrections are ordered.
  • [ ] Detect conflicting payloads with equal revisions.
  • [ ] Document cross-source selection rules.
  • [ ] Preserve missing values separately from zeros.
  • [ ] Recompute historical summaries after delayed changes.
  • [ ] Process deletions without stale-record resurrection.
  • [ ] Advance checkpoints after durable processing.
  • [ ] Test retries, interruptions, and time-zone changes.
  • [ ] Display freshness and incomplete coverage.
  • [ ] Minimize sensitive diagnostic data.

References

Top comments (0)