Skip to main content
Need help with your Google Health integration? Pop into our Discord if you have questions or want to discover how Open Wearables can solve your problems.

Overview

Google Health data reaches Open Wearables through two independent paths that share the single google provider identity:
  • Health Connect (mobile SDK) — data pushed from an Android device via the Sync SDK. See the Android SDK guide.
  • Google Health API (cloud OAuth) — this guide. A server-side OAuth 2.0 flow against the Google Health API that lets you connect a user’s Google account and pull their data over REST, plus receive notify-only webhooks.
The Google Health API is an aggregation layer: it surfaces data from every source connected to the user’s Google Health account — the phone’s Health Connect store, Fitbit, Google Fit, and other apps — not just one device.

Supported data types

Data delivery

Data granularity and fetch modes

The Health API exposes the same underlying data through three different operations. Open Wearables picks one per the DEFAULT_DATA_GRANULARITY setting, and — at the finest granularity — the GOOGLE_USE_RECONCILE flag.
GOOGLE_USE_RECONCILE only takes effect at raw granularity. hourly/daily always use windowed rollUp aggregates regardless of the flag.

Reconcile vs. list — why it matters

A user commonly has the same activity reported by multiple sources (e.g. the phone’s pedometer and the Fitbit app both counting steps). The two modes handle that overlap differently:
  • reconcile (default) returns one merged stream, deduplicated across all sources at the interval level — exactly what the native Google Health / Fitbit app displays. There is no single device behind a merged value, so reconciled points carry no device attribution (device_model is empty).
  • list returns the raw per-source points, each tagged with its originating device. This preserves device attribution but stores overlapping sources separately; Open Wearables then deduplicates on read by source priority (it does not sum them).
A concrete example — steps for one day for a user tracked by both their phone (Health Connect) and Fitbit MobileTrack: Reconcile (2560) matches the app exactly — it keeps intervals that either source captured while removing the overlap. Read-time dedup of the list data would instead pick a single source (1919), which is why reconcile is the default: it produces app-accurate totals.
Choose list (GOOGLE_USE_RECONCILE=false) only when you specifically need per-device attribution (e.g. to know which watch recorded a reading). For app-matching totals, keep the default.

What you need by the end

  • A Google Cloud project with the Health API enabled
  • OAuth client credentials (Client ID + Secret) with the Google Health scopes
  • Redirect URI registered in your OAuth client
  • (Webhooks only) A service account for project-level subscriber registration

Prerequisites

  • A Google Cloud project
  • Access to the Google Health API for that project (gcloud services enable health.googleapis.com)

Application walkthrough

1

Enable the Health API and create an OAuth client

In the Google Cloud Console, select your project and enable the Health API:
Then create an OAuth 2.0 Client ID (Web application) under APIs & Services → Credentials, and add your server-side callback as an Authorized redirect URI:
  • Local dev: http://localhost:8000/api/v1/oauth/google/callback
Store the Client Secret securely — Google shows it once.
2

Configure credentials in Open Wearables

Add the following to your .env file:
Configuration details:
The redirect URI is derived from API_BASE_URL — it must match the Authorized redirect URI on your OAuth client ({API_BASE_URL}/api/v1/oauth/google/callback).
3

Connect a user via OAuth

With credentials configured and your instance running, initiate the OAuth flow.
Using the Open Wearables frontend? You don’t need any of the curls below — open the connect view and click Connect on Google Health. The frontend runs this whole authorize → consent → callback → verify flow for you. The steps below are for integrating directly against the API.
1. Get the authorization URL:
2. Redirect the user to the returned authorization_url. They log in to Google and grant consent.3. Google redirects back to {API_BASE_URL}/api/v1/oauth/google/callback; Open Wearables exchanges the code for tokens and stores the connection. It also resolves the user’s stable healthUserId (via the Health API identity endpoint) as the connection’s provider user id — this is what inbound webhooks are matched against.4. Verify the connection:
You should see a connection with "provider": "google" and "status": "active".
4

Sync data

An initial sync runs automatically after a successful OAuth connection. To trigger one manually:
5

Verify the integration

Fetch a synced 24/7 series (e.g. steps):
If data is returned, your Google Health API integration is working end-to-end.

Webhooks

Google Health webhooks are notify-only: each notification names the changed dataType, operation (UPSERT/DELETE), and the physical-time intervals that changed — but carries no data. Open Wearables verifies the request, then fetches the changed data over REST for those intervals. Two distinct secrets are involved:
  • GOOGLE_WEBHOOK_SECRET — a bearer token you register with Google that it echoes back in the Authorization header of every notification, so Open Wearables can verify the ping is genuine. Defaults to SECRET_KEY if unset.
  • Service-account credentials — used only to register the subscriber (a project-level admin call). Not involved in receiving notifications.
Receiving and processing webhooks needs only GOOGLE_WEBHOOK_SECRET. The service account is required only to register the subscriber programmatically — you can also register it manually via gcloud/the API console.

Webhook subscriber registration

Subscribers live at the project level (POST /v4/projects/{project}/subscribers), so registration authenticates as the project via a service account, not a user’s OAuth token.
gcloud commands need the project ID (e.g. open-wearables-prod). The GOOGLE_PROJECT_ID env var, however, needs the project number (e.g. 123456789012) — the subscriber API requires the number in its path.
1

Create a service account

2

Provide the credentials

Either mount a JSON key and point to it, or rely on Application Default Credentials (ADC) if running on GCP:
Add to .env:
Subscriber registration runs in the Celery worker, not the backend/API service. The key file (or credentials) and the GOOGLE_* env vars must be present on the worker service — a key mounted only into the backend container won’t be seen.
A JSON key never expires until deleted — prefer ADC / Workload Identity in production, and keep key files out of version control.
3

Register the subscriber

Switching the provider’s live sync mode to webhook registers the subscriber automatically. Google then performs an endpoint-verification handshake (POST {"type":"verification"}) against {API_BASE_URL}/api/v1/providers/google/webhooks, which must return 2xx when authenticated. Once verified, notifications begin flowing.

Managing subscribers without app credentials (gcloud / console)

If you’d rather not give the app a service account, create and manage the subscriber yourself and leave GOOGLE_SERVICE_ACCOUNT_FILE/GOOGLE_PROJECT_ID unset. The app then needs only GOOGLE_WEBHOOK_SECRET to verify inbound notifications — it never calls the project-level subscriber API.
In this mode the in-app .../webhooks/subscriptions management endpoints (list / register / update / delete) won’t work — they require project credentials. Use the commands below instead.
The endpointAuthorization.secret you set here must equal "Bearer " + the app’s GOOGLE_WEBHOOK_SECRET (which defaults to SECRET_KEY). If they don’t match, every notification fails signature verification and Open Wearables returns 401.
All calls authenticate with your own gcloud identity, which must hold the Health API subscriber role on the project. You can also run these from the Cloud Console API Explorer, but the CLI steps below are easier to copy end-to-end. Use the same subscriberId (open-wearables) the app uses, so it stays interchangeable.
dataTypes above is an abbreviated example — use the set the app supports for webhooks (steps, distance, hydration-log, heart-rate, run-vo2-max, daily-resting-heart-rate, heart-rate-variability, weight, body-fat, blood-glucose, daily-respiratory-rate, sleep, exercise). Registering a data type the app doesn’t handle just means its notifications are ignored.

Next Steps

API Reference

Explore the Open Wearables API endpoints.

Supported Providers

See all supported providers.

Support

Need Help?