Guide

Apple Health data in Python

Apple has no Health API you can call from Python: HealthKit only runs on the iPhone. You can parse the Health app's export file, or sync your iPhone with HealthAPI and read always-current daily numbers into pandas over a REST API. Code for both is below.

  • requests and pandas
  • JSON, never XML
  • Updated 20 October 2026

HealthAPI: Free for 2 days, no card needed. Then an optional 7-day free trial when you subscribe.

Two ways in

HealthAPI's REST APIThe Health app's export.xml
How currentAs of your iPhone's last syncWhen you exported it
FormatJSON, one day or metric at a timeOne XML file with every reading
Totals match the Health appYes, each source counted onceNo, you deduplicate yourself
CostA HealthAPI planFree

Read it from the API

Install HealthAPI on your iPhone and let it sync. Copy your key from the app (Connect, then Other tools) and keep it in an environment variable rather than in your code:

Shell
pip install requests pandas
export HEALTHAPI_KEY="your key"

A small helper for any endpoint, and one for a metric's daily trend. The trends endpoint tells you which field carries the day's value: total for steps and energy, avg for heart rate, HRV and the like.

healthapi.pyPython
import os
import requests
import pandas as pd

API = "https://healthapi.app/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['HEALTHAPI_KEY']}"}


def get(path, **params):
    r = requests.get(API + path, headers=HEADERS, params=params, timeout=30)
    r.raise_for_status()
    return r.json()


def trend(metric, days=90):
    """One metric, one row per day: the total for steps and energy, the average otherwise."""
    t = get("/query/trends", type=metric, days=days)
    column = "total" if t["aggregation"] == "sum" else "avg"
    rows = pd.DataFrame(t["data"])
    if rows.empty:
        return pd.Series(dtype=float, name=metric)
    return rows.set_index(pd.to_datetime(rows["date"]))[column].rename(metric)

Three metrics in one DataFrame

Python
df = pd.concat(
    [trend("stepCount"), trend("restingHeartRate"), trend("heartRateVariability")],
    axis=1,
)
print(df.tail())
print(df.corr().round(2))
Output (example)Text
            stepCount  restingHeartRate  heartRateVariability
date
2026-10-14      9120              55.0                  64.0
2026-10-15     12408              54.0                  71.0
2026-10-16      7333              56.0                  58.0
2026-10-17     10871              54.0                  69.0
2026-10-18     11284              54.0                  68.0

Days without data are left out of each series, so they show as NaN after the join. Ninety days of three metrics is three requests. Metric names are on the metrics page; the full set of endpoints, including daily and weekly summaries with sleep, is in the API reference.

Workouts

Python
w = pd.DataFrame(get("/health/workouts", start_date="2026-01-01", limit=1000))
w["hours"] = w["duration_seconds"] / 3600
print(w.groupby("activity_type")["hours"].sum().sort_values(ascending=False))

Each workout has activity_type, start and end, duration_seconds, total_distance_meters and total_energy_kcal.

Your whole history at once

For a one-off analysis of everything, download HealthAPI's JSON export. It doesn't count toward your daily requests:

Python
r = requests.get(API + "/gdpr/export", headers=HEADERS, timeout=300)
r.raise_for_status()
data = r.json()

samples = pd.DataFrame(data["health_samples"])
# HealthAPI's own daily totals carry this source; skip them to keep only readings.
readings = samples[~samples["source_app"].isin(["healthapi:agg", "healthapi:dstat"])]
hrv = readings[readings["type"] == "heartRateVariability"]

Rows from healthapi:agg are deduplicated daily totals and healthapi:dstat rows are daily averages; the export guide explains the file.

Or parse the Health app's export.xml

No account needed: in the Health app, tap your picture, then Export All Health Data, and unzip it on your computer. The file is large, so stream it with iterparse instead of loading it whole:

Python
import xml.etree.ElementTree as ET
import pandas as pd

rows = []
for _, el in ET.iterparse("apple_health_export/export.xml"):
    if el.tag == "Record" and el.get("type") == "HKQuantityTypeIdentifierRestingHeartRate":
        rows.append({
            "start": el.get("startDate"),
            "value": float(el.get("value")),
            "source": el.get("sourceName"),
        })
    el.clear()  # keeps memory flat on a file of several hundred MB

rhr = pd.DataFrame(rows)
rhr["start"] = pd.to_datetime(rhr["start"])

Type names carry Apple's prefix (HKQuantityTypeIdentifierStepCount), dates include the timezone offset, and readings from your iPhone and Apple Watch overlap: summing steps from both gives more than the Health app shows. Filter by source, or use the API's totals, which already do this.

Questions

Is there an official Apple Health API for Python?

No. HealthKit is a framework for apps on iPhone, iPad and Apple Watch, written in Swift or Objective-C, and Apple offers no web API for Health data. From Python you either parse the export file or read the data from a service your iPhone syncs to, such as HealthAPI.

Can I read HealthKit from Python on a Mac?

No. The Mac has no Health database to read, so PyObjC's HealthKit bindings have nothing to return there. The data lives on your iPhone.

How many requests does the code use?

One per call: each trend is one request for up to 365 days, so the three-metric DataFrame is three. Pro allows 100 a day and Developer 1,000; the free preview allows 25. The JSON export doesn't count. Every response carries X-RateLimit-Remaining, and GET /usage doesn't count as one.

Why not just add up the readings?

Because iPhone and Apple Watch both record steps and energy for the same minutes, so a plain sum is too high. The trends and summaries count each source once and match the Health app; the raw readings don't.

Which metric names can I use?

HealthKit's own, without the prefix: stepCount, restingHeartRate, heartRateVariability, bodyMass and so on. The metrics page lists all 50 with their units.

The HealthAPI app icon

Your Health data, in a DataFrame.

Get HealthAPI for iPhone, copy your key, and start with three lines.