miniHabits
BUILD LOG · OUTLINE · 9 APR 2026

HealthKit integration notes from an app that reads five metrics

Permissions you cannot query, observers that over-fire, and duplicate samples from three sources.

build log 324 words of 1 700 planned

miniHabits reads five things from HealthKit: steps, exercise minutes, workouts, sleep and mindful minutes. Five is not many, and the integration still took longer than the entire statistics screen.

Three things account for that. Read permissions are deliberately opaque: for privacy reasons you cannot ask whether the user granted read access to a type, only whether they were asked. So an empty result means either no permission or no data, and your UI has to handle both without accusing the user of anything. Observer queries fire more often than you expect, including for samples that change retroactively when another app writes history, which means a naive implementation recomputes a habit twenty times an hour.

Duplicates are the third. A single walk can produce step samples from the phone, the Watch and a third party app, and summing them gives a number that is confidently wrong. The statistics query handles this if you use it, and the sample query does not, which is not obvious from the names.

This post covers each of those with the code that ended up shipping, plus background delivery behaviour, what happens on a fresh install with existing history, and the two metrics I decided not to read at all.

Outline

Status: outline. The introduction above is finished copy. Everything below is the section plan for the full draft, targeted at about 1 700 words.

  1. The five metrics. Why these, and what each one maps to in the app.
  2. Opaque read permissions. The API, the reason for it, and the UI that has to cope.
  3. Observer queries. Over-firing, retroactive edits, and the debounce that fixed it.
  4. Duplicate samples. Statistics query versus sample query, with numbers.
  5. Background delivery. What you get, how often, and what the system throttles.
  6. Fresh install with old history. Backfilling without a twenty second launch.
  7. Two metrics I skipped. And the reason each one is a bad habit target.
Try miniHabits free — 10 habits, no account.
Get it