Releasesv0.1.0

Introduction

Health data from devices and apps, in one clean model. Self-hosted, free, one Go binary plus Postgres.

Open Health Sync (ohs) is a self-hosted ingestion and normalization layer for health data. It pulls from providers, accepts uploads from phones, stores each payload verbatim, maps it to one canonical model with one set of units, and serves it over a REST API and a read-only MCP server.

Apple Health

Your iOS app uploads gzip NDJSON parts.

Cloud providers

OAuth pulls and push notifications.

Raw store

Every payload kept verbatim, on disk or S3, never rewritten.

ETL

Map, convert units, validate, de-duplicate, roll up local days.

Postgres

One canonical model, scoped by tenant and user.

REST API

Described by OpenAPI 3.1.

MCP server

Read only, for AI agents.

It stops at clean, traceable data. It is not a dashboard, a coaching app or a medical device: scores, insights and products belong in what you build on top.

Why it exists

Every health source speaks its own dialect. Apple Health sends one JSON line per HealthKit sample, heart rate in count/min, oxygen saturation as a fraction. Withings sends a daily activity object keyed by date, and intraday series keyed by Unix epoch. Each one has its own idea of a day, a device and a duplicate.

So teams write a script per provider: a parser, a table, a cron job. It works until the second provider, the first re-sent upload, the first mapper bug that needs a backfill, or the first person who asks you to delete everything you hold about them. Open Health Sync is that layer, written once, with the boring parts done properly.

A script per providerOpen Health Sync
Add a sourcea new parser, new tables, a new cron joba connector that maps into the same model
Unitswhatever each API sendsone unit per quantity, the original kept in metadata
"Today"UTC, or the provider's clockthe local calendar day of the record's time zone
A re-sent uploadstored twiceanswered 200 with "duplicate": true
Raw payloadsparsed, then thrown awaykept verbatim, so a user can be re-processed after a fix
Is it done?guess, or read the logsGET /coverage: pending, parked and rejected counts
Provider OAuth tokensa plain columnsealed with AES-256-GCM
Delete a usergrep across tables and bucketsDELETE /v1/users/{id}, then poll the job

What ships today

Available Sources: Apple Health through your iOS app or a Health app export, and Withings, Oura, WHOOP, Strava, Polar, Fitbit, Suunto, Ultrahuman and intervals.icu over OAuth.

Available Outputs: the REST API, the read-only MCP server and a FHIR R4 export.

Planned Next: more connectors, more standard outputs (Open mHealth, exports, webhooks, client SDKs), then health records (EHR) through SMART on FHIR. The sources page tracks each one.

Early preview

Releases are 0.x: the API, the configuration and the schema may change in any of them. Read the changelog before you upgrade.

Who sees the data

Only whoever runs the instance. Open Health Sync is software you run, with no account to create, no analytics and no call home. The server talks to the providers you enable and to your own database and raw store. Logs never contain tokens, keys or health values.

Edit on GitHub

On this page