Apple Health in Home Assistant in 5 steps

Syncky Health posts your Apple Health data straight from your iPhone to Home Assistant's webhook. Nothing passes through Syncky's servers on this route, and there is no account.

Before you start: the Syncky Health app and Home Assistant reachable from your iPhone, either on your home network (for example http://homeassistant.local:8123) or through Tailscale Serve using the remote setup below. Setting up and checking the connection is free; sending data needs the Sync plan.

1. Add sensors that listen on a webhook

Add trigger-based template sensors to configuration.yaml. Each one keeps its last value when a delivery has no sample of its type, so the app's test request and other types leave it alone:

template:
  - triggers:
      - trigger: webhook
        webhook_id: syncky-health
        allowed_methods: [POST]
        local_only: true
    sensor:
      - name: "Steps (last sample)"
        unit_of_measurement: "steps"
        state: >
          {{ trigger.json.samples | selectattr('type', 'eq', 'steps')
             | sort(attribute='start') | map(attribute='value') | list | last | default(this.state) }}
      - name: "Heart rate"
        unit_of_measurement: "bpm"
        state: >
          {{ trigger.json.samples | selectattr('type', 'eq', 'heart_rate')
             | sort(attribute='start') | map(attribute='value') | list | last | default(this.state) }}
      - name: "Body mass"
        unit_of_measurement: "kg"
        state: >
          {{ trigger.json.samples | selectattr('type', 'eq', 'body_mass')
             | sort(attribute='start') | map(attribute='value') | list | last | default(this.state) }}

Type names and units are in types.json: a quantity comes in its type's unit, for example kg for body_mass and count/min for heart_rate. The server guide has an automation that logs every delivery instead; use one or the other on the same webhook id.

2. Restart Home Assistant

Restart once so it loads the template sensors.

3. Add the server in Syncky Health

Settings › Connections › + › Home Assistant. The template fills in the format (Syncky JSON), the path /api/webhook/syncky-health and no authentication. Enter your Home Assistant address and choose the data types: steps, heart rate and body mass for the sensors above. Replace syncky-health in the YAML and URL with the same long unpredictable webhook id.

For remote access, the recommended setup is Tailscale Serve on the Home Assistant host. Enable HTTPS certificates in the tailnet's DNS settings, then run:

tailscale serve --bg 8123

Keep the iPhone connected to the tailnet and use https://<host>.<tailnet>.ts.net/api/webhook/<id> as the server URL. Home Assistant sees the local proxy, so keep the default local_only (true); the explicit local_only: true above is also suitable.

The plain-HTTP alternative is direct access to a tailnet address in 100.64.0.0/10, for example http://100.119.70.126:8123/api/webhook/<id>; only this direct-tailnet alternative needs local_only: false. Home Assistant does not count this direct tailnet request as local. Keep the iPhone on the tailnet and restrict access there.

4. Check the connection

Tap Check connection. The app sends one test request with no health data, and Home Assistant answers it. The sensors stay unknown until real data arrives.

5. Sync

Tap Sync now once to see the sensors fill in. After that, with the Sync plan, the app sends new samples whenever iOS wakes it while your iPhone is unlocked.

Good to know