Using AI

Only Sleep Data Missing From the Google Health API? The Cause Is the Scope. How to Redo OAuth Consent

Only Sleep Data Missing From the Google Health API? The Cause Is the Scope. How to Redo OAuth Consent

Good morning, this is まさきん.

I switched my phone from an iPhone to Android. Taking the opportunity, I have been consolidating the path my health data travels into a single route. But sleep alone kept showing “no source recorded” in my notification every morning. The cause turned out to be an OAuth scope and the need to redo consent, so I am leaving a record here alongside the official information.

Note: The information here is current as of publication. Please check the official sites for the latest terms.

POINT
  • Sleep in the Google Health API is read with a separate scope from steps: sleep.readonly
  • Adding a scope later doesn’t add permissions to the token you already hold. You need to redo consent
  • Adding include_granted_scopes=true to the authorization URL carries over the scopes you granted before
  • You can verify the fix first with a dry run that doesn’t write to production
  • In my case, the roughly one week before I added the permission was not backfilled

The Symptom

My health data currently flows along this route. From the activity tracker to Google’s health app (Google Health). From there, through the API, to my own records (my health log). Just this one path.

Steps and the like were already coming in. But the sleep field alone would not fill. The notification I get every morning showed “no source recorded” where sleep should be.

The Cause Was a Scope Added Later

The cause was simple. I had added the permission for sleep after the fact.

When I first gave consent, what I requested were scopes for steps and so on. After that, I added the sleep scope on the code side. But I hadn’t redone the consent.

The official Google Health API documentation says this. An issued access token contains only the scopes granted by the user who consented. In other words, just adding it in code changes nothing.

The Name “Google Health API”

The Google Health API is officially described as “the next generation of the Fitbit Web API.” It is a system for handling data from Fitbit, Pixel Watch, and other devices on top of Google’s OAuth 2.0.

A shutdown schedule has been published for the legacy Fitbit Web API. Support ends on September 30, 2026. The API itself is turned off on October 30, 2026. To keep getting data, migration to the Google Health API is what is advised.

The same notice also carries a caveat, though. Its gist is that new projects are not being accepted at this time. If you are just starting out, it may be reassuring to look at the latest official guidance first.

Separating Symptoms From Causes

Here is a table of the possible causes when “only sleep won’t come through.”

SymptomPossible causeWhere to check
Only sleep comes back emptyConsent was not given for the sleep scopeThe scopes contained in the token
Every item suddenly stops coming throughToken expiry (401)Publishing status and expiry conditions
Consent succeeded but calls failThe account isn’t linked to Google HealthSettings in the Google Health app
Only certain days are emptyNo record for that day exists on Google’s sideWhat the Google Health app shows

In my case, it was the top row. Steps were coming through, which means the token itself was alive.

I covered the case where everything stops in a separate article.

Why Google refresh tokens expire in 7 days: the “Testing” status, and how to publish to production

If the publishing status is the cause, I think that one is closer.

Scopes and Data Types for Sleep Data

Google Health API scopes all begin with the same string: https://www.googleapis.com/auth/googlehealth. After it comes a name for each grouping of data.

From the official scope list and data type pages, I pulled out the ones relevant here.

Scope (suffix)Official descriptionExamples of readable data
.activity_and_fitness.readonlySee activity and fitness dataActivity data such as steps
.sleep.readonlySee sleep dataSleep sessions and sleep stages
.health_metrics_and_measurements.readonlySee health metrics and measurement dataHeart rate variability and breathing rate during sleep, and so on

The data type for sleep is sleep, and the unit of record is a session. Within a single sleep, stage intervals are lined up. There are four kinds of stage: LIGHT / DEEP / REM / AWAKE.

What I put into my health log is sleep duration, deep sleep, and REM sleep. All of these were data readable within .sleep.readonly.

Heart rate variability and blood oxygen during sleep are a different matter, however. These fall under the health metrics scope. Lumping everything under the word “sleep” could lead you to mix this up.

Google advises requesting only the scopes you need. Write scopes are set only when you send data. For read-only uses, readonly looks sufficient.

How OAuth Behaves When You Add a Scope

Refreshing the refresh token you hold doesn’t add permissions. What a refresh gives you is an access token for the range already granted.

There is one way to use a new scope. Send the authorization request again with that scope included. The user grants it on the consent screen. Only then is the new permission attached.

Incremental Authorization and include_granted_scopes

The practice of adding scopes later has an official name: incremental authorization. The idea is to ask for additional scopes at the point they become necessary.

The parameter used here is include_granted_scopes. When you set its value to true and consent goes through, the new access token also includes the earlier scopes. Google recommends it as a best practice.

The official documentation also describes the rules for a combined authorization. With that refresh token, you can get access tokens covering all the scopes. On the other hand, if you revoke it, all the included scopes are removed at once.

So even when adding only sleep, you don’t lose the permission for steps.

Handling the Refresh Token

A tool that runs automatically needs a refresh token. Setting access_type to offline in the authorization URL is how you specify that.

There is one more important note in the official documentation. A refresh token is returned only the first time you exchange an authorization code. On second and later consents, it may not come back.

When you want to be sure of receiving a new one, add prompt=consent. It specifies showing the consent screen every time. In situations where you are redoing consent, adding it may spare you some confusion.

Here is the general flow, numbered. It follows the official OAuth 2.0 procedure for web servers.

  1. Confirm you have the intended project open in the Google Cloud console
  2. Add .sleep.readonly to the scope list on the tool side
  3. Build the authorization URL. List the required scopes in scope
  4. Add access_type=offline and include_granted_scopes=true to the same URL
  5. If you are re-obtaining the refresh token, add prompt=consent as well
  6. The account owner opens that URL in a browser, reads the consent screen, and grants access
  7. Exchange the returned authorization code for tokens
  8. Confirm the sleep scope is in the scope of the response
  9. Save the new refresh token and stop using the old one

Step 8 is unglamorous but important. On the consent screen, the user can choose whether to grant each scope.

What I Left to AI and What I Did Myself

This time I had an AI (Claude) do the groundwork on my Mac. Things like preparing the authorization URL with the added scope. What I did was open the consent screen and press allow.

TaskWhoWhy
Preparing the authorization URL with the added scopeAI (Claude)It is string assembly and easy to get wrong
Opening the consent screen and pressing allowMeIt is the owner’s own expression of intent
Looking at the next morning’s notificationMeIn the end I want to confirm with my own eyes

Consent is the act by which the data’s owner indicates “you may have this.” So I keep just the pressing of allow as something I do myself.

I wrote about how the morning notification works in a separate article.

How I have AI build a one-page “daily briefing” while I get ready in the morning

Changing phones means reviewing these integrations one by one. How about reviewing your monthly phone bill at the same time?

Try the fee simulator and get 100 points, no sign-up required Review your phone bill with Rakuten Mobile

Clicking this opens the Rakuten login page. Once you log in, you’ll see the campaign details.

Verifying With a Dry Run

After redoing consent, I didn’t send it straight to production. First, a dry run. That is, a run that only tries the fetch without writing to the production records.

In the dry run, I confirmed that sleep data came back. Then I ran the production process. Three values went into that day’s row in my health log. Sleep duration, deep sleep, and REM sleep. Having seen that much, I called it done.

With a dry run, nothing gets dirtied even if it fails. It heads off the accident of overwriting existing rows with empty values.

The order of checks is a read-only trial run first and the real write second. If you settle on never reversing that order, you can stay calm even right after redoing consent.

The Roughly One Week I Couldn’t Recover

There is just one thing that didn’t come back. The roughly one week of sleep before I added the permission.

For this period, there were no records on Google’s side either. So redoing consent doesn’t fill it in. I am leaving those rows in my health log empty.

I didn’t put estimated values into the empty rows. That is because, looking back later, they would be indistinguishable from real records. Leaving it as “what isn’t there isn’t there” feels more honest for a log, I think.

Even when the permission goes through, nothing comes back if the original records don’t exist. When isolating the problem, I think looking at what the app shows first is fastest.

If you plan to add a scope, it also seems worth noting the date you added it. When you later see an empty stretch, you can recall the reason right away.

Health Data Scopes Are Handled Strictly

Health data is sensitive information. Google treats it strictly on its side as well.

The official documentation says most Google Health API scopes are “restricted.” Apps released to the general public have to pass a review. The review has two stages: OAuth app verification and a third-party security assessment.

Apps that haven’t passed review are limited to 100 users. For a tool you use only yourself, reaching this cap seems all but impossible. However, an unverified app warning may appear before consent.

Common Mistakes and Pitfalls

MistakeWhat happensHow to prevent it
Adding the scope in code and stopping thereThe token’s permissions don’t changeRedo consent after adding it
The refresh token isn’t returnedYou keep using the old tokenAdd prompt=consent and obtain it again
Testing straight in productionRecords get overwritten with empty valuesRun a dry run first
Filling an empty period with guessesThey can’t be told apart from real recordsLeave it empty

Having built things so that the notification says “no source recorded” was something that helped.

What to Check Before You Start

Warning

If the publishing status is still “Testing,” refresh tokens expire in 7 days. Even if you add a scope and redo consent, this time limit applies separately. Checking the publishing status first may save you from doing the work twice.

Frequently Asked Questions

Yes, you do. That is because a token contains only the scopes the user has granted. Just adding it to code or settings doesn’t increase the permissions.

Q. If I refresh the refresh token, will the new scope be attached too?

No. What a refresh gives you is an access token for the range already granted. A new scope is attached only once it is granted on the consent screen.

Q. Which scope reads sleep data?

In the Google Health API, it is .sleep.readonly. You can read sleep sessions and the stages within them. Heart rate variability during sleep and the like separately require the health metrics scope.

Q. Can I get deep sleep and REM sleep?

In the official data type, there are four kinds of stage: LIGHT / DEEP / REM / AWAKE. Support differs by device, so checking the official table of supported devices as well is the sure way.

Q. Can I go back and get sleep from days before I consented?

I think it depends on whether the original records exist on Google’s side. In my case, about a week of records didn’t exist on Google’s side either. So that period remains empty.

I don’t. That is because I regard consent as the expression of intent by the data’s owner. I ask the AI only for the groundwork, such as preparing the authorization URL.

Q. Can I keep using the Fitbit Web API as is?

Officially, it is announced to be turned off on October 30, 2026. If you want to keep getting data, you need to migrate to the Google Health API. Please check the official guidance for the status of new project acceptance.

Official Sources I Referred To

Wrap-Up

The reason only sleep showed “no source recorded” was a scope I added later. Once you add one, redo consent. Once you understand it, that is all there is to it.

I left the groundwork to AI and pressed allow myself. I verified with a dry run before sending it to production. The final check of whether it is fixed is tomorrow morning’s notification. That is still ahead of me.

If you have just changed phones, take one look through the permissions of the apps you have connected.

If you are also thinking about switching carriers, there is my article summarizing the MNP number-porting steps as well.

Try the fee simulator and get 100 points, no sign-up required Check Rakuten Mobile's rate plans

Clicking this opens the Rakuten login page. Once you log in, you’ll see the campaign details.

This article contains affiliate advertising. If you sign up for a product or service through a link on this site, we may receive compensation from the partner company. The site operator is also an employee of Rakuten Group and may receive compensation through an employee referral program. The content and opinions here are based on the operator’s own experience and research regardless of any advertising relationship, but please read with the above in mind. See the Disclaimer & Affiliate Disclosure for details. Disclaimer & Affiliate Disclosure

This article includes machine-translated content. Please check the official Rakuten Mobile multilingual page for exact terms.

If you have concerns about Rakuten Mobile coverage or signal quality, you can consult through the official signal improvement request form .

ABOUT THE AUTHOR
まさきん

Rakuten Group employee · Digital Marketer (holds a Financial Planner qualification)

In his early 40s, part of a dual-income household with four kids. Works as a digital marketer at Rakuten Group, while also using his Financial Planner (FP) qualification to focus on household finances and building assets.

View Profile

Related Articles

RELATED
Gemini (Google AI Pro) Family Sharing Covers Up to 5 Family Members: Setup Steps and Scope Using AI

Gemini (Google AI Pro) Family Sharing Covers Up to 5 Family Members: Setup Steps and Scope

Google AI Pro can be shared with up to 5 family members besides the manager. The Gemini app and storage are shared, while YouTube Premium Lite is for the manager only. Flow limits are shared across the family. I went through the official help to sort out the setup steps and how child accounts are handled.

2026.10.13 · 11 min read
3 Reasons Your AI Subscription Billing Date Does Not Match Your Budget: Claude Upgrades Change It Using AI

3 Reasons Your AI Subscription Billing Date Does Not Match Your Budget: Claude Upgrades Change It

If you upgrade Claude to Max mid-month, your billing cycle resets and that day becomes your new billing date. The yen conversion of dollar charges is set when the data reaches your card company, and statements and budgeting apps lag by a few days. Here are 5 steps to decide the month using the receipt email as your source of truth.

2026.10.13 · 12 min read
Turning Unprocessed freee Accounting Transactions into a Monthly Reconciliation Run: 7:30 on the 5th, 3 Categories, and a Cap of 15 Items Handed to a Human Using AI

Turning Unprocessed freee Accounting Transactions into a Monthly Reconciliation Run: 7:30 on the 5th, 3 Categories, and a Cap of 15 Items Handed to a Human

About 18 unprocessed transactions sat untouched in freee Accounting across 6 weekly checks. Here is my design for a reconciliation run on my home Mac at 7:30 a.m. on the 5th of each month, and where I drew the line: one monthly task for the items that can be confirmed, and one task each, capped at 15, for the ones that need a human decision.

2026.10.12 · 13 min read
Switch to Rakuten Mobile, get up to 14,000 points Try the fee simulator and get 100 points, no sign-up required →
Apply Now →