GitHub - ninyawee/healthkit-from-backup-to-sqlite: Convert the raw HealthKit database from an iPhone backup (healthdb_secure.sqlite) into a clean, queryable SQLite file for Datasette. The backup-store companion to dogsheep/healthkit-to-sqlite. · GitHub
/" data-turbo-transient="true" />
Skip to content
Search or jump to...
Search code, repositories, users, issues, pull requests...
-->
Search
Clear
Search syntax tips
Provide feedback
--><br>We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contacted
Cancel
Submit feedback
Saved searches
Use saved searches to filter your results more quickly
-->
Name
Query
To see all available qualifiers, see our documentation.
Cancel
Create saved search
Sign in
/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up
Appearance settings
Resetting focus
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
ninyawee
healthkit-from-backup-to-sqlite
Public
Notifications<br>You must be signed in to change notification settings
Fork
Star
main
BranchesTags
Go to file
CodeOpen more actions menu
Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit
History<br>2 Commits<br>2 Commits
.gitignore
.gitignore
LICENSE
LICENSE
README.md
README.md
healthkit_from_backup_to_sqlite.py
healthkit_from_backup_to_sqlite.py
View all files
Repository files navigation
healthkit-from-backup-to-sqlite
Turn the raw HealthKit database from an iPhone backup into a clean, queryable<br>SQLite file you can browse with Datasette — no slow<br>on-device "Export All Health Data" step required.
This is the missing companion to Simon Willison's<br>healthkit-to-sqlite: that tool ingests the<br>Health app's export.zip (the "Export All Health Data" file). This one reads the raw<br>healthdb_secure.sqlite directly — the store Apple keeps on the device and syncs via iCloud —<br>which you get from an iPhone backup. The raw store is richer and avoids the slow, sometimes-failing<br>on-device XML export entirely.
healthkit-to-sqlite<br>this tool
Input<br>Health app export.zip<br>raw healthdb_secure.sqlite from a backup
Get the input<br>on-device export (slow, can fail/time out)<br>extract once from an encrypted backup
Fidelity<br>re-serialized XML<br>the original store Apple actually keeps
Output<br>SQLite for Datasette<br>SQLite for Datasette
healthdb_secure.sqlite ──[this tool]──> health.db ──> datasette<br>(source of truth, read-only) (derived, disposable lens)">iPhone backup ──> healthdb_secure.sqlite ──[this tool]──> health.db ──> datasette<br>(source of truth, read-only) (derived, disposable lens)
Why bother
The raw store is faithful but unfriendly: integer type enums with no string table, Apple-absolute<br>timestamps, per-type canonical units, and values split across quantity / original_quantity<br>columns. This tool resolves all of that into one readable database:
Readable type names — the data_type integer enum is mapped to names like HeartRate,<br>StepCount, SleepAnalysis (mapping cross-checked against<br>christophhagen/HealthDB and verified against<br>each DB's own row counts).
ISO-8601 timestamps — Apple-absolute seconds (since 2001-01-01) converted to UTC; daily<br>rollups bucket on a timezone offset you pass in.
Normalized units — pulse rates normalized to bpm (HealthKit stores some types as count/s and<br>others as count/min), distances in metres, energy in kcal.
Daily rollups — daily_steps, daily_distance_km, daily_active_energy,<br>daily_heart_rate, daily_sleep_hours.
Provenance — each sample keeps its source device and recorded timezone.
The raw DB is opened read-only and immutable — it is never modified. health.db is fully<br>regenerable: delete it and re-run any time.
Getting the raw database
Make an encrypted local backup of the iPhone (Finder/iTunes, or idevicebackup2).<br>Encryption is required — health data is only included in encrypted backups.
Extract HealthDomain/Health/healthdb_secure.sqlite from the backup (e.g. with<br>iMazing, or a backup-decryption library such as<br>iphone_backup_decrypt).
Usage
Requires uv (the script declares its own deps — none beyond<br>the stdlib — via PEP 723):
./healthkit_from_backup_to_sqlite.py healthdb_secure.sqlite health.db 7<br># ^raw (read-only) ^out ^UTC offset for daily rollups
All three args are optional (defaults: ./healthdb_secure.sqlite, ./health.db, +0/UTC).<br>Then explore:
uvx datasette health.db
What you get
The importer prints a summary as it builds (≈4 s for ~10 years of data). Illustrative run:
built health.db (220 MB)
row counts:<br>quantity_samples 1,300,000<br>category_samples 28,000<br>workouts 420
date range: ('2016-09-13 21:21:48', '2026-06-12 03:59:14')
top quantity types:<br>ActiveEnergyBurned 460,000<br>HeartRate 220,000<br>BasalEnergyBurned 170,000<br>StepCount 148,000<br>DistanceWalkingRunning 138,000
…and then the...