Overview

The Google Health API is a comprehensive solution built from the ground up, providing developers with robust access to a wide array of consented user health data and diverse data types. The Google Health API utilizes a new console for registering your apps, Google OAuth 2.0, new data types, new endpoint schema, and a new response format.

This guide is designed to help developers migrate their existing Fitbit Web API apps to the new Google Health API. It features recommendations to ensure a seamless migration while retaining users.

Why should you migrate?

This is not just an update, it's a strategic move to ensure your apps are secure and ready for future advancements in health technology. Some of the benefits of using the Google Health API are:

  • Access to Comprehensive Data: Gain robust access to a wide array of consented user health data and diverse data types.
  • Enhanced Security: Compliance with Google's security best practices, aligning with Google's security, privacy, and identity standards.
  • Consistency: Eliminates legacy inconsistencies in data formats, time zones, measurement units, and error handling for a more intuitive developer experience.
  • Scalability & Future-Proofing: Designed to scale to meet future demands and supports modern protocols like gRPC.

Transitioning from the Fitbit Web API to the Google Health API involves more than technical modifications. Because of the switch to a new OAuth library, existing access and refresh tokens cannot be transferred, requiring users to re-consent to your updated integration.

Support both login methods

Since the Fitbit Web API and the Google Health API use different systems to handle user logins, while the Fitbit Web APIs are still active, your app will temporarily need to support both authentication methods across your user base.

Instead of your app asking for data directly, implement a layer that decides whether to talk to the Fitbit Web API or Google Health API for a specific user, so the rest of your app doesn't need to worry about the details.

Update your user database to include a flag (for example, oauth_type) to identify which login system they are using.

  • For new users: Automatically set them up with the new Google Health API (oauth_type: google).
  • For existing users: Keep them on the Fitbit Web API until they update their consent (oauth_type: fitbit).
User Scenario oauth_type State Active API Stream Required Action
New user onboarding google Google Health API only Launch Google OAuth in a system browser and map IDs with users.getIdentity.
Existing Fitbit user (not yet migrated) fitbit Fitbit Web API only Continue syncing with Fitbit Web API; display a dismissible in-app prompt to upgrade.
Existing Fitbit user completing migration fitbit → google Cut over to Google Health API Verify granted scopes, call users.getIdentity (legacyUserId → healthUserId), switch oauth_type to google, and immediately revoke legacy Fitbit tokens.

To avoid disrupting the user experience, we recommend not forcing everyone to log out and log back in. Instead:

  1. When a user who remains connected to the Fitbit Web APIs engages with your app, show them a friendly notification encouraging them to update their connection.
  2. When the user accepts the update action, trigger the Google Health login flow right then.
  3. Once the Google login is successful, save the new Google credentials to the user's profile, switch their oauth_type flag from fitbit to google, and immediately disable legacy syncing by programmatically revoking their legacy Fitbit tokens to prevent duplicate data ingestion and dual-linking.

Ensure data continuity

When transitioning an integration from the legacy Fitbit Web API to the Google Health API, developer applications must account for a change in user identification structures.

The legacy Fitbit Web API identifies accounts using a 6-character alphanumeric string (such as A1B2C3), whereas the Google Health API utilizes a healthUserId formatted as a string of up to 63 digits & characters.

To bridge this gap without losing user context, developers can query the getIdentity endpoint to get the Fitbit and Health user IDs. This endpoint returns a payload containing both the legacyUserId and the new healthUserId, enabling applications to dynamically create a mapping between existing records and the new account system.

Handle new users without a Google Health profile (HTTP 412)

Users must have an initialized Google Health profile before linking their account. If a user completes Google OAuth consent but has not yet set up their profile in the Google Health app, calling users.getIdentity (or data endpoints) returns an HTTP 412 Precondition Failed error.

Don't display a generic technical error or blank screen. Instead, catch HTTP 412 responses and display an actionable prompt guiding the user to finish onboarding:

"It looks like your Google Health profile isn't ready. Open the Google Health app to complete setup, then return here to connect."

Backfill historical data

If a user does not authenticate to the new Google Health API endpoints before the legacy endpoints are turned down, their data will still be available as long as they continue syncing their device to the Google Health app. However, you may have a gap in data for this user.

To backfill their data, once the user re-authenticates to the new endpoints, you can use our Google Health API to backfill their historical data. See Query historical data for guidance.

Sample migration and linking implementation

The following reference implementation demonstrates how to handle the OAuth callback, validate partial or zero consent, resolve user identity with users.getIdentity (including HTTP 412 handling), prevent dual-linking by revoking legacy Fitbit tokens, and route data requests using oauth_type:

import requests

GOOGLE_HEALTH_IDENTITY_URL = "https://health.googleapis.com/v4/users/me/identity"
FITBIT_REVOKE_URL = "https://api.fitbit.com/oauth2/revoke"


def complete_google_health_linking(user_record: dict, oauth_token_response: dict, fitbit_client_creds: str) -> dict:
  """Completes Google Health account linking and migrates legacy Fitbit users."""
  # 1. Check granted scopes (handle zero consent and partial consent)
  granted_scopes = set(oauth_token_response.get("scope", "").split())
  health_scopes = {s for s in granted_scopes if s.startswith("https://www.googleapis.com/auth/googlehealth")}
  if not health_scopes:
    return {
        "status": "MISSING_PERMISSIONS",
        "ui_action": "ROUTE_TO_MISSING_PERMISSIONS_SCREEN",
        "message": "At least one permission is required to connect to Google Health.",
    }

  access_token = oauth_token_response["access_token"]

  # 2. Call users.getIdentity and handle HTTP 412 (Profile not set up)
  identity_resp = requests.get(
      GOOGLE_HEALTH_IDENTITY_URL,
      headers={"Authorization": f"Bearer {access_token}", "Accept": "application/json"},
      timeout=10,
  )
  if identity_resp.status_code == 412:
    return {
        "status": "PROFILE_SETUP_REQUIRED",
        "ui_action": "PROMPT_OPEN_GOOGLE_HEALTH_APP",
        "message": (
            "It looks like your Google Health profile isn't ready. "
            "Open the Google Health app to complete setup, then return here to connect."
        ),
    }
  identity_resp.raise_for_status()
  identity = identity_resp.json()

  # 3. Map legacyUserId -> healthUserId and cut over oauth_type to prevent dual-linking
  previous_oauth_type = user_record.get("oauth_type")
  legacy_fitbit_refresh_token = user_record.get("fitbit_refresh_token")

  user_record.update({
      "health_user_id": identity.get("healthUserId"),
      "legacy_user_id": identity.get("legacyUserId") or user_record.get("legacy_user_id"),
      "google_access_token": access_token,
      "google_refresh_token": oauth_token_response.get("refresh_token"),
      "granted_scopes": list(health_scopes),
      "oauth_type": "google",
      "fitbit_access_token": None,
      "fitbit_refresh_token": None,
  })

  # 4. Immediately revoke legacy Fitbit token so both APIs never run simultaneously
  if previous_oauth_type == "fitbit" and legacy_fitbit_refresh_token:
    requests.post(
        FITBIT_REVOKE_URL,
        headers={
            "Authorization": f"Basic {fitbit_client_creds}",
            "Content-Type": "application/x-www-form-urlencoded",
        },
        data={"token": legacy_fitbit_refresh_token},
        timeout=10,
    )

  return {
      "status": "CONNECTED",
      "health_user_id": user_record["health_user_id"],
      "granted_scopes": user_record["granted_scopes"],
  }

Communication and timing

To help your users move from their existing Fitbit OAuth to the new Google OAuth, follow these best practices.

Value-first communication

Don't lead with "We updated our API", lead with the benefits integrating Google Health data into your app but ensure they are aware that they need to re-authenticate if they want their data to sync:

  • Clearly explain what features are available in your app that are powered by the integration, and tailor your message to how a user benefits from those features.
  • Focus on your features and provide use cases instead of technical implementation details.
  • Don't say: "You will not be able to connect to the Fitbit API."
  • Do say: "To continue seeing detailed workouts with heart rate data, re-consent to the Google Health APIs."

When to notify users

In all user communications, adhere to the Google Health brand guidelines, and use dismissible banners, cards, or alerts.

  • Don't trigger the re-consent screen while a user is in the middle of a workout or manually logging something.
  • Only make the re-consent mandatory after several weeks of warnings, coinciding with the official Fitbit Web API deprecation deadlines.
  • If a user has not re-consented after the hard cutoff, provide a graceful recovery path. Provide a help message in a banner, card or tooltip that helps them understand why their data is missing, and how to fix it.