DEV Community

antivex
antivex

Posted on

Fitbit Web API returns 410 Gone: how to keep sleep, HRV and weight flowing into intervals.icu

On 2 November 2026 Google turned off the legacy Fitbit Web API. If a script, app or sync tool that fed your Fitbit data into intervals.icu stopped working this week, this is the most likely reason. Here is what changed, how to recognise it, and the routes that still work, with their real limits.

What changed

Google's developer page for the Google Health API gives the timeline:

  • 30 September 2026: support for the legacy Fitbit Web API ended.
  • 2 November 2026: the Fitbit Web API and the Fitbit OAuth endpoints were turned off. Requests to them now fail with HTTP 410 Gone.

The replacement is the Google Health API (health.googleapis.com), with new OAuth scopes and new data types. Old Fitbit tokens don't carry over.

On the app side, Google's help page says its support team can't restore a broken third-party connection: "Reconnection must be enabled by the partner app's developer."

How to tell it's the shutdown

  • Your tool's log shows 410 on calls to api.fitbit.com, or the Fitbit sign-in step fails.
  • Reinstalling the app or signing in again doesn't help: the endpoint itself is gone.
  • If you maintain a tool: 410 is permanent. Retrying or backing off won't bring it back, so fail with a clear message instead of looping.
r = requests.get(url, headers=headers, timeout=30)
if r.status_code == 410:
    raise SystemExit("Fitbit Web API is turned off (410 Gone): move this tool to the Google Health API.")
r.raise_for_status()
Enter fullscreen mode Exit fullscreen mode

Route 1. Android: Health Connect (no code)

Google's help page says connections through Health Connect and Apple Health are not affected by the change.

In the Google Health app: Connections > Partner apps > Sync your favorite health apps > Set up.

According to Google's table, Google Health writes these to Health Connect:

  • sleep sessions and stages;
  • heart rate variability and resting heart rate;
  • weight, steps, VO2 max and respiratory rate.

Oxygen saturation (SpO2) appears only in the "read" column, so don't count on SpO2 arriving this way.

To finish the route, use an app that reads Health Connect and writes to intervals.icu. Check that it lists the fields you care about.

Route 2. iPhone: Apple Health, or Health Sync

In the Google Health app: Connections > Apps and services > Apple Health.

Google Health writes sleep, resting heart rate, oxygen saturation, weight and steps to Apple Health. Heart rate variability is read-only, so HRV does not go from Google Health to Apple Health. If HRV drives your training decisions, use Health Sync or route 3.

Health Sync can read Google Health directly. As of late October it was a paid licence after a one-week trial.

Route 3. Any phone: read the Google Health API yourself

If you are comfortable with GitHub, you can read the new API directly. Two open-source tools do this for intervals.icu:

The setup for google-health-to-intervals takes about 20-30 minutes, once:

  1. Create your private copy with Use this template.
  2. Create a Google Cloud project and enable the Google Health API.
  3. On the consent screen:
    • choose External and leave the publishing status on Testing;
    • add yourself as a test user;
    • add three read-only scopes: googlehealth.sleep.readonly, googlehealth.health_metrics_and_measurements.readonly and googlehealth.activity_and_fitness.readonly.
  4. Create an OAuth client of type Desktop app.
  5. In intervals.icu, open Settings > Developer Settings, create an API key and note your athlete ID (it looks like i123456).
  6. Add four repository secrets: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, INTERVALS_API_KEY and INTERVALS_ATHLETE_ID.
  7. Run the Re-authorize workflow and approve access in the browser.
    • The browser then ends on an error page. That is expected: copy the whole address, which starts with http://127.0.0.1:8765/?state=.
    • Paste that address into a second run of the workflow. The first run copies the last 14 days.

It reads health.googleapis.com/v4/users/me/dataTypes and writes everything in one call to PUT /api/v1/athlete/{id}/wellness-bulk on intervals.icu:

Google Health intervals.icu wellness field
Sleep duration (naps excluded) sleepSecs
Resting heart rate restingHR
Heart rate variability (nightly rMSSD) hrv
Weight (last weigh-in of the day) weight
SpO2 (daily average) spO2
Steps steps
VO2 max vo2max
Breathing rate respiration

Empty values are never sent, so they never erase what you already have in intervals.icu.

Route 4. History: Google Takeout + CSV upload

For past data, export from Google Takeout with Google Health selected, then load the values into intervals.icu:

  1. In the calendar's grid view, open Options > Wellness.
  2. Download a CSV first, so its header row becomes your template.
  3. Fill in the template and upload it from the same panel.

The upload rules:

  • the first column is date in yyyy-mm-dd format;
  • use a comma as the separator and a dot for decimals;
  • weight goes in kilograms.

The same upload works through the API: POST /api/v1/athlete/{id}/wellness with the CSV as multipart/form-data.

The real limits

  • Sleep Score is not in the Google Health API as far as its documentation shows, so sleepScore stays manual whatever route you pick.
  • The 7-day rule. Google's setup page says refresh tokens in Testing mode are "time-based and expire after 7 days", and new OAuth clients are capped at 100 users. That is why every user creates their own project. The bridge turns the weekly renewal into a one-minute step, and GitHub emails you a reminder the day before.
  • Not real time: the bridge copies four times a day.
  • Early version: some Google Health field names in the bridge have not been checked against real data yet. They are marked in the code; if a value looks wrong, please open an issue.
  • Gaps by route: SpO2 doesn't arrive through Health Connect, and HRV doesn't arrive through Apple Health.

Sources (checked on 2 November 2026)


This article was written with AI assistance and published by the antivex team.

Top comments (0)