Export Google Fit Daily Steps, Weight and Distance to a Google Sheet

Updated on Friday, December 29, 2023

Comments Page 2

Return to post.


Darren Wall

My sheet stopped pulling data from Google Fit on 21st September. I came back here to refresh my memory as I believe in the past this happened when the script needed re-signing. Google have changed things!!!!! "Script Editor" is no longer under "Tools" I believe what we need to use now is "Apps Script" under "Extensions". I've not yet got it working again but I'll update as/if/when I do. This blog post is a fantastic little community of it's own :D Thanks for starting and maintaining this Rob.


Just to update, I got this working.

In the Oauth I did not get an option to select the application type (web application) until after I had configured the consent screen. Ignore what I said about scopes - you don't need to select those at all.

Great resource, thanks. Actually unbelievable that Google doesn't provide this as part of the Google Fit app


Like Alex, I also cannot get past the Oauth part in the cloud console

I've selected the scopes I think I need (auth/fitness.activity.read, auth/fitness.body.read, auth/fitness.location.read) but there is nowhere to add a redirect URL and it doesn't have a client ID or client secret.

It also will not let me publish it without submitting for verification. As I'm the only person who will use it, that seems overkill.

Any idea where to go from here?

Robert Ellison

Alex - it's Credentials now rather then Keys. I've updated the step. If that's not helping please be a little more specific about where you're stuck.


Hi Robert, thanks for your guide, but I am having trouble at the google API console. Has it perhaps changed since you made the guide? Because when i try to create an OAuth Client ID the information is different to what you are saying, and I am not familiar enough with google APIs in order to see what I should do. Please let me know




Does anybody know how to prevent the authorization from expiring?

With "Publishing Status" set to "Testing" in the GCP console, the credentials expire after 7 days. If I publish the app and the status becomes "In Production" (without going though any verification steps), the credentials expire within a few hours.

The 7-day expiry seems to be expected behavior (see "How to add authentication to a Google apps script without it expiring?" on stackoverflow) but I haven't found a way around it without having to go through Google's verification process.


Here's my code for fetching sleep data. Make sure you add the appropriate scope (fitness.sleep.read), and then trigger getSleepData().


// Populate sleep data

function getSleepData() {

const numDaysToGet = 10;

const tabName = 'GFitImportSleep';

const timezone = 'America/Los_Angeles';

getDailySleepData(numDaysToGet, 0, tabName, timezone);


// Format string number of milliseconds using provided timezone and format string

function toDate(millis, tz, format) {

var d = new Date(parseInt(millis));

return Utilities.formatDate(d, tz, format);



Load sleep sessions and overwrite the given tab with the data.

First line of output is a description, second line is headers.


function getDailySleepData(fromDaysAgo, toDaysAgo, tabName, timezone) {

let start = new Date();


start.setDate(start.getDate() - fromDaysAgo);

let end = new Date();


end.setDate(end.getDate() - toDaysAgo);

const url = `https://www.googleapis.com/fitness/v1/users/me/sessions?startTime=${start.toISOString()}&endTime=${end.toISOString()}&activityType=72`;

const fitService = getFitService();

const response = UrlFetchApp.fetch(url, {

headers: {

Authorization: 'Bearer ' + fitService.getAccessToken()


'method' : 'GET',


const json = JSON.parse(response.getContentText());


let ss = SpreadsheetApp.getActiveSpreadsheet();

let sheet = ss.getSheetByName(tabName);

sheet.clear({ formatOnly: false, contentsOnly: true });

sheet.appendRow(["This sheet is generated via Apps Script using the GFit API. Use the 'Google Fit' menu to regenerate manually. If seeing authorization errors, click 'Reset Settings' and then 'Authorize' in that menu."])

sheet.appendRow(["startTimeMillis", "start time", "endTimeMillis", "end time", "end date", "duration (h)", "data"]);

for(var s = 0; s < json.session.length; s++) {

const session = json.session[s];

const duration_m = (session.endTimeMillis - session.startTimeMillis)/(1000 * 60 * 60);



toDate(session.startTimeMillis, timezone, 'h:mm:ss a MM/dd/yy z'),


toDate(session.endTimeMillis, timezone, 'h:mm:ss a MM/dd/yy z'),

toDate(session.endTimeMillis, timezone, 'MM/dd/yy'),






Baran Gulmez

i wanted to add sleep data too but i just couldn't find the documentation of google for below lines anywhere. how can i find sleep data's dataTypeName and dataSourceId ?


"dataTypeName": "derived:com.google.step_count.delta",

"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"



"dataTypeName": "com.google.weight.summary",

"dataSourceId": "derived:com.google.weight:com.google.android.gms:merge_weight"



"dataTypeName": "com.google.distance.delta",

"dataSourceId": "derived:com.google.distance.delta:com.google.android.gms:merge_distance_delta"


Diedrich S

Hi Robert and others interested,

I figured out what the problem was. It was getting the data, but it wasn't being treated correctly. In the function getMetricsForDays, there's a for loop where it looks like there's commands to assign numerical data types. In the case of move minutes, it's an integer value, and I was assigning it a floating point value, fpValue, and it should be intVal, just like the number of steps. After changing this, it worked just fine.



Diedrich S

Hi Robert,

Thanks for your reply. I'm not sure how to check the JSON response, I am not that familiar with Java scripting.

The strange thing is that I get nothing for move minutes. I also don't get any error, either. But, what has changed is that I need to re-authorize the script each day, whereas before adding in the move minutes changes, I didn't need to.

The stackoverflow link I provided in the previous comment claims that it works for that person.

Since I'm not familiar with this type of scripting, I am not sure where to begin debugging it.



Add Comment

All comments are moderated. Your email address is used to display a Gravatar and optionally for notification of new comments and to sign up for the newsletter.