The Google Script will download your Fitbit data via the Fitbit API and insert it into a Google spreadsheet. The first row of the spreadsheet will be a header row containing data element names like steps walked, body fat, calories burned, etc. Subsequent rows will contain data, one day per row.
This is a Google Spreadsheet bound script so you need to create a sheet first and put this code inside the Script editor. Fitbit uses metric units (weight, distance) so you may wish to convert them as per your locale.
/*
Original Fitbit script by loghound@gmail.com,
Further modifications by Mark Leavitt, Christian Stade-Schuldt, Robert Furberg, Amit Agarwal
*/
// Key of ScriptProperty for Fitbit consumer key.
var CONSUMER_KEY_PROPERTY_NAME = 'fitbitConsumerKey';
// Key of ScriptProperty for Fitbit consumer secret.
var CONSUMER_SECRET_PROPERTY_NAME = 'fitbitConsumerSecret';
// Default loggable resources (from Fitbit API docs).
var LOGGABLES = [
'activities/steps',
'activities/distance',
'activities/floors',
'activities/elevation',
'activities/calories',
'activities/activityCalories',
'activities/minutesSedentary',
'activities/minutesLightlyActive',
'activities/minutesFairlyActive',
'activities/minutesVeryActive',
'sleep/startTime',
'sleep/timeInBed',
'sleep/minutesAsleep',
'sleep/awakeningsCount',
'sleep/minutesAwake',
'sleep/minutesToFallAsleep',
'sleep/minutesAfterWakeup',
'sleep/efficiency',
'body/weight',
'body/bmi',
'body/fat',
];
// function authorize() makes a call to the Fitbit API to fetch the user profile
function authorize() {
var oAuthConfig = UrlFetchApp.addOAuthService('fitbit');
oAuthConfig.setAccessTokenUrl('https://api.fitbit.com/oauth/access_token');
oAuthConfig.setRequestTokenUrl('https://api.fitbit.com/oauth/request_token');
oAuthConfig.setAuthorizationUrl('https://api.fitbit.com/oauth/authorize');
oAuthConfig.setConsumerKey(getConsumerKey());
oAuthConfig.setConsumerSecret(getConsumerSecret());
var options = {
oAuthServiceName: 'fitbit',
oAuthUseToken: 'always',
};
// get the profile to force authentication
Logger.log('Function authorize() is attempting a fetch...');
try {
var result = UrlFetchApp.fetch('https://api.fitbit.com/1/user/-/profile.json', options);
var o = Utilities.jsonParse(result.getContentText());
return o.user;
} catch (exception) {
Logger.log(exception);
Browser.msgBox('Error attempting authorization');
return null;
}
}
// function setup accepts and stores the Consumer Key, Consumer Secret, firstDate, and list of Data Elements
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle('Setup Fitbit Download');
app.setStyleAttribute('padding', '10px');
var consumerKeyLabel = app.createLabel('Fitbit OAuth Consumer Key:*');
var consumerKey = app.createTextBox();
consumerKey.setName('consumerKey');
consumerKey.setWidth('100%');
consumerKey.setText(getConsumerKey());
var consumerSecretLabel = app.createLabel('Fitbit OAuth Consumer Secret:*');
var consumerSecret = app.createTextBox();
consumerSecret.setName('consumerSecret');
consumerSecret.setWidth('100%');
consumerSecret.setText(getConsumerSecret());
var firstDate = app.createTextBox().setId('firstDate').setName('firstDate');
firstDate.setName('firstDate');
firstDate.setWidth('100%');
firstDate.setText(getFirstDate());
// add listbox to select data elements
var loggables = app.createListBox(true).setId('loggables').setName('loggables');
loggables.setVisibleItemCount(4);
// add all possible elements (in array LOGGABLES)
var logIndex = 0;
for (var resource in LOGGABLES) {
loggables.addItem(LOGGABLES[resource]);
// check if this resource is in the getLoggables list
if (getLoggables().indexOf(LOGGABLES[resource]) > -1) {
// if so, pre-select it
loggables.setItemSelected(logIndex, true);
}
logIndex++;
}
// create the save handler and button
var saveHandler = app.createServerClickHandler('saveSetup');
var saveButton = app.createButton('Save Setup', saveHandler);
// put the controls in a grid
var listPanel = app.createGrid(6, 3);
listPanel.setWidget(1, 0, consumerKeyLabel);
listPanel.setWidget(1, 1, consumerKey);
listPanel.setWidget(2, 0, consumerSecretLabel);
listPanel.setWidget(2, 1, consumerSecret);
listPanel.setWidget(3, 0, app.createLabel(' * (obtain these at dev.fitbit.com)'));
listPanel.setWidget(4, 0, app.createLabel('Start Date for download (yyyy-mm-dd)'));
listPanel.setWidget(4, 1, firstDate);
listPanel.setWidget(5, 0, app.createLabel('Data Elements to download:'));
listPanel.setWidget(5, 1, loggables);
// Ensure that all controls in the grid are handled
saveHandler.addCallbackElement(listPanel);
// Build a FlowPanel, adding the grid and the save button
var dialogPanel = app.createFlowPanel();
dialogPanel.add(listPanel);
dialogPanel.add(saveButton);
app.add(dialogPanel);
doc.show(app);
}
// function sync() is called to download all desired data from Fitbit API to the spreadsheet
function sync() {
// if the user has never performed setup, do it now
if (!isConfigured()) {
setup();
return;
}
var user = authorize();
var doc = SpreadsheetApp.getActiveSpreadsheet();
doc.setFrozenRows(1);
var options = {
oAuthServiceName: 'fitbit',
oAuthUseToken: 'always',
method: 'GET',
};
// prepare and format today's date, and a list of desired data elements
var dateString = formatToday();
var activities = getLoggables();
// for each data element, fetch a list beginning from the firstDate, ending with today
for (var activity in activities) {
var currentActivity = activities[activity];
try {
var result = UrlFetchApp.fetch(
'https://api.fitbit.com/1/user/-/' + currentActivity + '/date/' + getFirstDate() + '/' + dateString + '.json',
options
);
} catch (exception) {
Logger.log(exception);
Browser.msgBox('Error downloading ' + currentActivity);
}
var o = Utilities.jsonParse(result.getContentText());
// set title
var titleCell = doc.getRange('a1');
titleCell.setValue('date');
var cell = doc.getRange('a2');
// fill the spreadsheet with the data
var index = 0;
for (var i in o) {
// set title for this column
var title = i.substring(i.lastIndexOf('-') + 1);
titleCell.offset(0, 1 + activity * 1.0).setValue(title);
var row = o[i];
for (var j in row) {
var val = row[j];
cell.offset(index, 0).setValue(val['dateTime']);
// set the date index
cell.offset(index, 1 + activity * 1.0).setValue(val['value']);
// set the value index index
index++;
}
}
}
}
function isConfigured() {
return getConsumerKey() != '' && getConsumerSecret() != '';
}
function setConsumerKey(key) {
ScriptProperties.setProperty(CONSUMER_KEY_PROPERTY_NAME, key);
}
function getConsumerKey() {
var key = ScriptProperties.getProperty(CONSUMER_KEY_PROPERTY_NAME);
if (key == null) {
key = '';
}
return key;
}
function setLoggables(loggable) {
ScriptProperties.setProperty('loggables', loggable);
}
function getLoggables() {
var loggable = ScriptProperties.getProperty('loggables');
if (loggable == null) {
loggable = LOGGABLES;
} else {
loggable = loggable.split(',');
}
return loggable;
}
function setFirstDate(firstDate) {
ScriptProperties.setProperty('firstDate', firstDate);
}
function getFirstDate() {
var firstDate = ScriptProperties.getProperty('firstDate');
if (firstDate == null) {
firstDate = '2012-01-01';
}
return firstDate;
}
function formatToday() {
var todayDate = new Date();
return (
todayDate.getFullYear() +
'-' +
('00' + (todayDate.getMonth() + 1)).slice(-2) +
'-' +
('00' + todayDate.getDate()).slice(-2)
);
}
function setConsumerSecret(secret) {
ScriptProperties.setProperty(CONSUMER_SECRET_PROPERTY_NAME, secret);
}
function getConsumerSecret() {
var secret = ScriptProperties.getProperty(CONSUMER_SECRET_PROPERTY_NAME);
if (secret == null) {
secret = '';
}
return secret;
}
// function saveSetup saves the setup params from the UI
function saveSetup(e) {
setConsumerKey(e.parameter.consumerKey);
setConsumerSecret(e.parameter.consumerSecret);
setLoggables(e.parameter.loggables);
setFirstDate(e.parameter.firstDate);
var app = UiApp.getActiveApplication();
app.close();
return app;
}
// function onOpen is called when the spreadsheet is opened; adds the Fitbit menu
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [
{
name: 'Sync',
functionName: 'sync',
},
{
name: 'Setup',
functionName: 'setup',
},
{
name: 'Authorize',
functionName: 'authorize',
},
];
ss.addMenu('Fitbit', menuEntries);
}
// function onInstall is called when the script is installed (obsolete?)
function onInstall() {
onOpen();
}