Data & scoring

Recreating WHOOP on Google Fitbit: What It Takes

Google Fitbit Air costs $99 and its hardware is good. Its recovery and load numbers cost another $99 a year, and unlike WHOOP's, Fitbit's are not even documented. So the obvious move is to build your own. This is what that actually involves — which inputs exist, which published methods you can legitimately build on, and the point where a Fitbit reimplementation stops being a WHOOP substitute.

We earn nothing from this page. There are no affiliate links, no sponsorship and no paid placement, and we have no commercial relationship with any tool or vendor named here. Some tools listed are paid products and we say which. How we evaluate software is set out in our editorial standards.

The short answer

You can build something genuinely useful, but it will not be WHOOP. The Google Health API gives you daily HRV, daily resting heart rate, sleep with stage breakdown, and active zone minutes — enough to compute a baseline-relative recovery score and a cardiovascular load score from published, citable methods. What you cannot do is reproduce WHOOP's numbers, because WHOOP does not publish its formula either, and the Fitbit Air lacks the two sensors that make WHOOP's approach distinctive: no ECG, and no continuous heart-rate-variability stream. Treat anything claiming a like-for-like WHOOP port to Fitbit as marketing.

What you are actually trying to reproduce

WHOOP's product is two numbers and a colour. Recovery is a 0–33% band derived mainly from heart rate variability, resting heart rate, sleep performance and respiratory rate, each compared against your own baseline. Strain is a 0–21 logarithmic scale of cardiovascular exertion accumulated across the day.

Two properties of those scores matter more than the numbers themselves:

Neither company publishes how they actually compute these. Fitbit's Readiness, Cardio Load and Sleep Score are proprietary, as is WHOOP's Recovery and Strain. That is not a scandal — it is normal — but it has a consequence that gets glossed over: there is no reference implementation to copy, and no ground truth to validate against. You are choosing a method, not reproducing a known answer.

What the Google Health API actually gives you

The API is served from health.googleapis.com under version 4, and replaces the retired Fitbit Web API. It uses Google OAuth 2.0 rather than Fitbit's own OAuth, which is the single biggest change for anyone migrating: existing tokens cannot be transferred and every user has to consent again.

Around 39 data types are available. The ones that matter for a recovery or load score, with the method that works for each, as documented by Google and confirmed in the field by open-source implementations:

SignalData typeMethodNotes
Heart rate variabilitydaily-heart-rate-variabilitylistA daily summary, not a continuous R-R stream. This is the most important limitation on the whole page.
Resting heart ratedaily-resting-heart-ratelistOne value per day. Good enough for a baseline.
Sleep, with stagessleeplistSession record. Supports list, reconcile, create, update and delete.
Active zone minutesactive-zone-minutesdailyRollUpTime in heart-rate zones. Fitbit Air is supported.
Heart rate, intradayheart-ratedailyRollUpAggregates. Raw point-in-time samples come from reconcile with the google-wearables source family.
Respiratory ratedaily-respiratory-ratelistAvailable on some devices; confirm against your own data.
Oxygen saturationdaily-oxygen-saturationlistDaily summary.
Recorded workoutsexerciselistSession metrics. Also exports as TCX.
VO2 maxvo2-maxlistSample type. May be sparse.
Steps, distance, caloriesstepsdailyRollUpInterval types, well supported.

Three traps that will cost you an afternoon each

1. Data type identifiers are kebab-case in URLs and snake_case in filters. The path takes dataTypes/heart-rate; the filter parameter takes heart_rate.sample_time.physical_time. Sending camelCase returns an HTTP 400 with an unhelpful message.

2. Rollup ranges are capped. The dailyRollUp endpoint enforces a maximum query range per data type — heart rate fails beyond roughly 14 days. Fetch long history in chunks of 14 days or less and merge the results.

3. Your refresh token dies every seven days. Every Google Health scope is a restricted scope, so production use requires Google's OAuth verification and an annual paid security assessment. Personal tools stay in Testing mode, and Testing-mode refresh tokens expire after seven days. Re-consenting takes about ten seconds. This is a platform constraint that applies to every self-hosted Fitbit tool equally, and it is the thing most likely to make you think a tool is broken when it is not.

Building the recovery score

Given the inputs above, the defensible approach is a baseline-relative z-score composite. It is not exotic, it is not original to us, and every step is published.

1
Establish a rolling baseline per metric Take a trailing window — commonly 28 or 30 days — and compute the mean and standard deviation of each metric you care about: HRV, resting heart rate, sleep performance. You need roughly two weeks of history before any of this is worth computing, because a score built on a three-day baseline is noise with a colour.
2
Convert today's value to a z-score against your own baseline z = (today − baseline mean) ÷ baseline SD. The sign matters and is frequently got wrong: for HRV, higher is better, so the raw z-score is already correctly oriented. For resting heart rate, higher is worse, so the sign must be inverted before weighting.
3
Weight and combine Multiply each oriented z-score by its weight and sum. A common weighting gives HRV the largest share because it responds fastest to residual fatigue, with sleep performance next, resting heart rate next, and respiratory rate a minor term. The weights are a judgement call; several open-source projects publish theirs, and you should expect to spend a fortnight tuning them against your own experience.
4
Map to 0–100 through the normal CDF This is the step that makes the number readable. Passing the composite z through the standard normal cumulative distribution function produces a percentile: a z of 0 lands at 50, and you are at your own typical value. It also has the property people find reassuring in retrospect — you should spend roughly half your days in green, and if you do not, your weights are wrong or you are genuinely overtrained.

The RMSSD measure used to summarise HRV here is the standard short-term metric, and the reference for its interpretation is the 1996 Task Force consensus statement on heart rate variability standards, which remains the citation almost every implementation points back to.

This is our convention, not a standard

The 28-day window, the specific weights, and the choice to map through the normal CDF are our construction and our recommended defaults, not a published standard and not any vendor's method. Published literature supports the baseline-relative principle and the use of HRV as a fatigue marker. It does not prescribe a window length or a weighting. Where you see a number produced this way, treat it as one defensible choice among several, and expect to tune it.

Building the strain score

Strain is easier and more defensible, because it derives from heart rate rather than from a comparison against your own history.

Active zone minutes give you a shortcut if you would rather not process raw heart rate: time in each Fitbit-defined zone, weighted by zone, is a serviceable approximation of the same quantity. Several projects do exactly this because it is far less code and the difference in practical use is small.

On the acute:chronic workload ratio

If you go further and start tracking a weekly load ratio, be aware it is contested. The acute:chronic workload ratio originates with Foster's 1998 monitoring framework and is widely used, but its interpretation as a causal injury predictor has been substantially challenged since — most prominently by Gabbett, whose work argues the apparent relationship is largely explained by confounding from fitness already being low when athletes get injured. We report the ratio where projects expose it and do not present it as a validated risk model, because it is not one.

What the existing projects actually compute

You do not have to write any of this. Several open-source projects read the Google Health API and publish their formulas. We have not run any of them — this is documentation and repository research, and our standards page explains exactly what that means — so treat the descriptions below as claims made by each project about itself.

ProjectShapeStated scoringLicence
fitbit-health-explorer Electron desktop app, local JSON store, npm start Publishes the most detail of any of these: recovery as weighted z-scores of HRV, resting HR, sleep and respiratory rate against a trailing 30-day baseline, mapped through the normal CDF; strain 0–21 as a logarithmic load from active zone minutes, active energy and steps; readiness as a blend; plus a Physio Age estimate. All weights live in settings rather than code. Open source
fettle FastAPI + Next.js + SQLite, single user Readiness 0–100 against a 28-day baseline, a sleep score, and a TRIMP-style cardio load, with thresholds traced to citations in a metrics specification document. Ships 25 MCP tools, so an AI agent can read it directly. MIT
vitals FastAPI + vanilla JS, Docker or a single install script, multi-profile Recovery, strain, sleep performance and a body-age estimate, with the formulas documented in a dedicated algorithms file. Ships 9 read-only MCP tools and a demo mode with 150 days of synthetic data, so you can see the shape before connecting anything. MIT
Vitals Command Center TypeScript, installable PWA, MCP Takes a different angle: rather than trusting one device, it reconciles Fitbit, Oura, WHOOP and Apple Health into one weighted consensus with a per-metric confidence level, and routes each device either through the Google Health bridge or its own adapter so nothing is double-counted. MIT
HealthLog Docker PWA plus a native iOS client Broader scope than scoring: adds medication, glucose, mood and cycle tracking alongside sleep and recovery, with per-metric source priority so overlapping wearables resolve consistently. Reads Fitbit through your own Google Cloud client. PolyForm Noncommercial 1.0.0, AGPL to v1.15.18
Pulseboard Node, no third-party runtime dependencies, Docker A read-oriented dashboard rather than a scoring engine. Encrypts the persisted refresh token with AES-256-GCM, and is the one project here aimed specifically at the Fitbit Air. Open source

A licensing trap worth knowing

HealthLog is source available, not open source, and the distinction matters. It is free to run and free to modify for noncommercial use; commercial use requires a separate agreement. If your interest is a personal dashboard, that is fine. If it is ever going in a product, that licence is a blocker, and it is the reason the table lists licences rather than leaving them out.

If you also want an AI assistant to read the same data rather than just a human-facing dashboard, add an MCP server. Several exist for the Google Health API specifically — one exposes 29 read-only tools, another adds sync into an Obsidian vault, and a third implements remote MCP with OAuth so it can be registered as a ChatGPT connector. That is a different article, and it is covered on the cluster index alongside the platform differences that determine which approach you need.

Where this stops being a WHOOP clone

This is the part that decides whether you should build it at all, so it is worth being blunt rather than encouraging.

1

Fitbit Air has no ECG.

WHOOP straps and some Fitbit models carry single-lead ECG for atrial fibrillation detection. Fitbit Air offers irregular-rhythm notification alerts, which is a different thing. If irregular-heart-rhythm detection is why you were considering WHOOP, no amount of software substitutes for the sensor.

2

You get a daily HRV summary, not a continuous stream.

This is the deepest limitation. WHOOP computes recovery from continuous beat-to-beat data. The Google Health API's daily-heart-rate-variability type is an aggregate for the whole day. That is enough to see a trend against your baseline; it is not enough to reproduce any method that depends on within-day structure, such as detecting overnight HRV deterioration or a parasympathetic rebound pattern.

3

Neither vendor publishes its formula, so neither is verifiable.

You cannot validate your score against WHOOP's, and you cannot validate it against Fitbit's. What you can check is whether it tracks your own experience — whether green days feel green. That is a weaker guarantee than it sounds, because it is easy to fit a score to your memory after the fact.

4

Google can change the ground under you.

The Fitbit Web API is being retired and the Google Fit API dies at the end of 2026. Fitbit has already removed its web dashboard, its challenges and its badges once. Your data is portable, but the platform you read it through is demonstrably not a stable contract.

5

Sync scores compute from first-party data only.

If you connect a Garmin or an Oura into Google Health to enrich your history, Google's own documentation states that Sleep Score and Cardio Load are calculated from first-party data only. Those scores will not improve. Anything you compute yourself will, because you control the inputs.

Given all that, here is the honest recommendation. If you want a recovery number to make training decisions, buy the subscription — not because the number is better validated than yours would be, but because supporting the raw sensor is the part you cannot replicate. If you want to look at a year of your own data on a laptop, build it, because Google removed that capability and will not bring it back. Those are two different problems and the right answer is different for each.

Frequently asked

Can you recreate WHOOP on a Fitbit?

Partly. The Google Health API exposes daily heart rate variability, daily resting heart rate, sleep with stage breakdown, and active zone minutes — enough to compute a baseline-relative recovery score and a cardiovascular load score from published methods. But Fitbit publishes no formula for its own Readiness or Cardio Load, and Fitbit Air has neither an ECG nor continuous HRV, so the result is a different instrument rather than a copy of WHOOP's.

What data can I pull from the Google Health API?

Around 39 data types, including steps, distance, active and total calories, active minutes, active zone minutes, intraday heart rate, daily resting heart rate, daily heart rate variability, oxygen saturation, respiratory rate, VO2 max, body fat, sleep sessions with stages, and recorded exercise sessions. It is served from health.googleapis.com under version 4, using Google OAuth 2.0 rather than the retired Fitbit OAuth, so existing tokens cannot be migrated and users must consent again.

Is there an open-source WHOOP alternative that reads Fitbit data?

Several. They split into self-hosted dashboards — Vitals, Vitals Command Center, Fitbit Health Explorer, fettle, HealthLog and Pulseboard — and Model Context Protocol servers that expose the same data to AI assistants. Most use your own Google Cloud OAuth client rather than a shared backend, so your credentials never pass through someone else's server.

Why does my self-hosted Fitbit tool keep asking me to sign in again?

Because every Google Health API scope is restricted. Production use requires Google's OAuth verification, which for restricted scopes means an annual paid security assessment. Personal tools stay in Testing mode, and Testing-mode refresh tokens expire after seven days. Re-consent takes about ten seconds. It is a platform constraint, not a fault in the project.

Is a self-computed recovery score as good as WHOOP's?

You cannot judge it that way, because neither number is validated against a reference standard — WHOOP's formula and Fitbit's are both proprietary. What you can judge is whether your score tracks your own baseline consistently over weeks, which is the property that actually matters for training decisions. We would hold any new score to that test before trusting it with a training decision.

Related

Sources