Overview
Google Health data reaches Open Wearables through two independent paths, each its own provider:- Health Connect (mobile SDK) — provider
health_connect. Data pushed from an Android device via the Mobile SDK. See the Android SDK guide. - Google Health API (cloud OAuth) — provider
google_health, 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.
connection.created / connection.revoked events.
google_health is this provider’s name everywhere — in payloads, in ?provider= filters, and in the URLs new integrations should use. Before the split it was reachable at /google/; the OAuth and webhook endpoints still serve that path so anything already registered with Google keeps working, but it is a compatibility path that goes away in 1.0.Fitbit devices
This integration is the successor to the Fitbit integration. Google turns the legacy Fitbit Web API off on November 2, 2026 and points integrations to the Google Health API (migration guide). Our Fitbit integration is feature-frozen and only syncs workouts; sleep, heart rate, HRV, SpO2 and the other data types below come from Fitbit devices throughgoogle_health. Users connect with their Google account and have to consent again - Fitbit tokens cannot be carried over.
Existing Fitbit users must first move their Fitbit account to their Google Account. Until they do, OAuth consent still succeeds but Google Health API calls fail with ACCOUNT_NOT_LINKED, so syncs for that connection fail.
Supported data types
Data delivery
Data granularity and fetch modes
The Health API exposes the same underlying data through three different operations. Open Wearables reads every 24/7 metric at native resolution, picking the operation per theGOOGLE_USE_RECONCILE flag.
dataPoints:dailyRollUp, whose windows are anchored to civil days and so do not drift.
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_modelanddevice_typeare empty).listreturns the raw per-source points, each tagged with its originating device;device_typecomes from the data source’sformFactor. This preserves device attribution but stores overlapping sources separately; Open Wearables then deduplicates on read by source priority (it does not sum them).
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
- (Production only) A verified OAuth app and a CASA Letter of Validation — see Verification and security assessment
Prerequisites
- A Google Cloud project
- Access to the Google Health API for that project (
gcloud services enable health.googleapis.com)
Application walkthrough
Enable the Health API and create an OAuth client
http://localhost:8000/api/v1/oauth/google_health/callback
GOOGLE_LEGACY_OAUTH_PATH=false so Open Wearables sends that URI. New integrations should always use this path.Configure credentials in Open Wearables
.env file:API_BASE_URL and must match an Authorized redirect URI on your OAuth client exactly: {API_BASE_URL}/api/v1/oauth/google_health/callback.Connect a user via OAuth
authorization_url. They log in to Google and grant consent.3. Google redirects back to {API_BASE_URL}/api/v1/oauth/google_health/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:"provider": "google_health" and "status": "active".Sync data
Verify the integration
Verification and security assessment
Everygooglehealth.* scope Open Wearables requests is a restricted scope, and Google gates those behind two independent reviews. Both run against your Google Cloud project — the OAuth client, consent screen and privacy policy are yours, so nobody can be verified on your behalf. Start early: the security assessment alone runs weeks, and it has to be redone every year.
Does this apply to you?
Before you submit: branding, policy and in-app disclosure
Before you submit: branding, policy and in-app disclosure
example.com covers https://app.example.com/connect.A public home page. Reachable without logging in, and clearly about the app being verified. A parked domain or a generic company landing page is rejected.A privacy policy that names Google user data. Hosted on a verified domain, linked from the consent screen, and explicit about how you access, use, store and share Google user data. It must also commit to the Limited Use requirements: the data only powers user-facing features, is not transferred except as permitted, is not read by humans without the user’s affirmative agreement, and is never used for advertising, retargeting, data brokerage or credit decisions.An in-app prominent disclosure. A separate requirement from the privacy policy, and a common reason for a second review round. Google requires that it:- is in the app itself, not only in the app description or on a website
- appears in normal usage, without the user navigating into a menu or settings
- describes the data being accessed or collected, and how it is used or shared
- is not bundled with disclosures unrelated to Google Health API data
{App name} collects health and fitness data to enable {feature}, {feature}, and {feature}.OAuth app verification: branding, scopes, demo video
OAuth app verification: branding, scopes, demo video
Publish your branding
Declare and justify every scope
Record the demonstration video
Submit and answer follow-ups
CASA security assessment: labs, cost, Letter of Validation
CASA security assessment: labs, cost, Letter of Validation
Pick an authorized lab
Pass the assessment
Submit the Letter of Validation
Running unverified: the 100-user cap and 7-day refresh tokens
Running unverified: the 100-user cap and 7-day refresh tokens
connection.revoked webhook with reason refresh_failed. The user has to run the OAuth flow again. That is workable for a demo and unusable in production — which is the practical deadline for finishing verification.Webhooks
Google Health webhooks are notify-only: each notification names the changeddataType, 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 theAuthorizationheader of every notification, so Open Wearables can verify the ping is genuine. Defaults toSECRET_KEYif unset.- Service-account credentials — used only to register the subscriber (a project-level admin call). Not involved in receiving notifications.
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.
Create a service account
Provide the credentials
.env:Register the subscriber
webhook registers the subscriber automatically. Google then performs an endpoint-verification handshake (POST {"type":"verification"}) against {API_BASE_URL}/api/v1/providers/google_health/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 leaveGOOGLE_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.
.../webhooks/subscriptions management endpoints (list / register /
update / delete) won’t work — they require project credentials. Use the commands below instead.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, daily-heart-rate-variability, weight, body-fat, blood-glucose,
daily-respiratory-rate, daily-oxygen-saturation, sleep, exercise, nutrition-log). Registering
a data type the app doesn’t handle just means its notifications are ignored.Next Steps
API Reference
Supported Providers
Support
- Join our Discord and ask a question.
- Check GitHub Discussions.
- Check the Google Health API Documentation.