PulsHealth
Free on the App Store · Open source

Apple Health, in your own database

PulsHealth for iOS reads Apple Health and sends every sample to a server you run. It never writes back to Apple Health. It syncs the full history first, then keeps up in the background. There is no PulsHealth account and no PulsHealth cloud.

The basics
What to know before you install.
  • It is on the App Store. Free, for iPhone. You can also build it yourself with Xcode 26 and XcodeGen. Running your own build on a real iPhone needs a paid Apple Developer team, because the HealthKit background-delivery entitlement requires one.
  • You need a server first. The app has nowhere to sync until a backend exists. The reference stack comes up with one command; anything that speaks the documented protocol works just as well.
  • All of it is open source. The app, the sync library, the server stack, the protocol and the dashboards are in one Apache-2.0 repository.

How the Sync Works

Each HealthKit type has its own cursor, saved only after your server confirms the batch. A failed upload re-sends the same page and the server deduplicates by sample UUID, so nothing is lost or duplicated.

Full History First
The initial backfill exports everything from the start date you choose, four types at a time, with live per-type progress, rate and ETA. It saves its place after every batch, so interrupting it costs nothing.
Then It Keeps Up
A HealthKit observer and background delivery pick up new samples and deletions as iOS allows. A background task catches up while the phone is idle, and opening the app runs a full pass.
Read-Only, Always
The app asks Apple Health for read permission and nothing else. It never writes, edits or deletes anything in HealthKit, and the usage strings say so.
Pair by Scanning
Your server prints a pairing block with the URL, bearer token and user ID, plus a QR code that encodes all three. Scan it, or type the values in by hand.
Aggregates and Rings
Any quantity type can also be sent as on-device buckets (hourly sums, daily averages, optionally split by Watch and iPhone). Daily activity rings arrive as one row per day.
Logs and Diagnostics
A live event log, per-type progress, and a record of every background wake iOS granted. You can export all of it, and a built-in benchmark shows how fast your phone can read HealthKit.
80
HealthKit types it can sync
0
Third-party dependencies
0
Accounts, servers or trackers run by the developer
iOS 17+
Free on the App Store

What You Can Sync

80 HealthKit types, grouped the way Apple Health groups them. Turn on a starter set in one tap, or choose type by type. Nothing is read until you enable it and iOS grants permission.

Activity27
Heart13
Body8
Respiratory2
Sleep3
Nutrition9
Vitals5
Workouts1
Other12
Every type, by nameshow 80

Activity

  • Active Energykcal
  • Activity Rings
  • Cycling Cadencecount/min
  • Cycling Distancem
  • Cycling PowerW
  • Cycling Speedm/s
  • Double Support %%
  • Exercise Minutesmin
  • Flights Climbedcount
  • Ground Contact Timems
  • Move Minutesmin
  • Physical Effortkcal/hr*kg
  • Resting Energykcal
  • Running PowerW
  • Running Speedm/s
  • Running Stride Lengthm
  • Stand Hours
  • Stand Minutesmin
  • Step Lengthm
  • Stepscount
  • Swimming Distancem
  • Swimming Strokescount
  • Vertical Oscillationcm
  • VO₂ Maxml/kg*min
  • Walking + Running Distancem
  • Walking Asymmetry %%
  • Walking Speedm/s

Heart

  • AFib Burden%
  • ECG
  • Heart Ratecount/min
  • Heartbeat Series (beat-to-beat)
  • High HR Events
  • HR Recovery (1 min)count/min
  • HRV (SDNN)ms
  • Irregular Rhythm Events
  • Low Cardio Fitness Events
  • Low HR Events
  • Perfusion Index%
  • Resting Heart Ratecount/min
  • Walking HR Averagecount/min

Body

  • Basal Body TemperaturedegC
  • BMIcount
  • Body Fat %%
  • Body TemperaturedegC
  • Body Weightkg
  • Heightm
  • Lean Body Masskg
  • Waist Circumferencem

Respiratory

  • Blood Oxygen%
  • Respiratory Ratecount/min

Sleep

  • Sleep Apnea Events
  • Sleep Stages
  • Wrist Temperature (Sleep)degC

Nutrition

  • Caffeinemg
  • Carbohydratesg
  • Dietary Energykcal
  • Fiberg
  • Proteing
  • Sodiummg
  • Sugarg
  • Total Fatg
  • WatermL

Vitals

  • Blood Alcohol Content%
  • Blood Glucosemg/dL
  • Blood Pressure (Diastolic)mmHg
  • Blood Pressure (Systolic)mmHg
  • Fallscount

Workouts

  • Workouts

Other

  • Environmental SounddBASPL
  • Handwashing Events
  • Headphone AudiodBASPL
  • Loud Environment Events
  • Loud Headphone Events
  • Medication Doses
  • Mindful Minutes
  • Sound ReductiondBASPL
  • State of Mind
  • Time in Daylightmin
  • Toothbrushing Events
  • UV Exposurecount

Rendered at build time from the protocol's published vocabulary, catalog.json. Units are the canonical ones every sample is converted to before upload.

Workouts carry their GPS routes and per-second sensor series; ECGs bring their microvolt trace; State of Mind, sleep apnea events and medication doses come across on the iOS versions that support them.

Open Protocol

One URL, one documented format

The app posts gzip-compressed NDJSON over HTTPS to the address you enter, with a bearer token you also choose. That is its only network destination. The format has a written spec, so the reference stack is one possible receiver rather than the only one.

Puls Sync Protocol v1

A JSON Schema for every line type, canonical units for every quantity, epoch-millisecond timestamps, and the retry and idempotency rules a receiver can rely on.

Write Your Own Backend

A fixture corpus, a batch checker, and a complete receiver in one standard-library Python file that writes to SQLite. Copy it, or read it alongside the spec.

Benchmark Before You Backfill

Reading HealthKit on the phone is the slow part, not the network. The in-app benchmark reads real data without uploading it, so you can see how long a backfill will take before starting one.

POST https://health.example.net/v1/batches
Authorization: Bearer <your token>
Content-Encoding: gzip
X-User-ID: <your user id>

{"batchID":"...","quantityCount":2,...}
{"uuid":"...","type":"HKQuantityType...
{"uuid":"...","type":"HKQuantityType...

→ 200 OK   (only now does the phone
            advance its cursor)

What you can do with it

All of this ships in the same repository as the app.

postgres
SQL and Grafana
Data lands in PostgreSQL 17 with TimescaleDB. Query it directly, or use the provisioned Grafana dashboards and the web viewer that ship with the stack.
/v1/export
CSV and JSONL
The product API streams any dataset as CSV or JSONL, and puls-export is a small CLI wrapper for it. For a spreadsheet or a notebook, that is the shortest path.
mcp
AI Assistants
A read-only MCP server lets Claude, Claude Code or Cursor answer questions from your data. ChatGPT connects through the API's OpenAPI document instead.

Follow the project

Watch the repository for releases, subscribe to the feed, or leave your email for occasional updates.

ReleasesFeed

Install it, then point it at your server

You need an iPhone on iOS 17 or later and a server you can reach. Apple Watch data arrives once iOS syncs it to the phone. If you would rather build it yourself, the repository has the Xcode instructions.

PulsHealth is not a medical device and gives no medical advice. Data is only as accurate as whatever recorded it into Apple Health. The name and logo belong to the developer; the code is Apache-2.0, so a fork ships under its own name.