How to obtain Heart Rate (HR) Intraday Time Series by Fitbit API and Python

I wrote articles about obtaining heart rate (HR) data by “fitbit API” and “Python”.

In this article, I simply explain the method for that.

Requirements and Environment

・Python 3.5
・Fitbit surge or Fitbit charge HR
・python-fitbit(Download from here. Click “download zip”)


* I assume that you can run Python programs.

1. Sign up to Fitbit developer site

You can sign up from here.

2. Register an API by “REGISTER AN APP” in

Please enter Application Name, Description, Application Website, Organization, Organization Website.
For example, I enter this blog URL at “Website”.

Other settings:
– OAuth 1.0 Application Type => Browser
・OAuth 2.0 Application Type => Personal *This is an important point.
We need “OAuth2.0” for getting HR data.
And, we have to set “Personal” in order to obtain HR intraday time-series data.

・Callback URL => *This is alo an important point.
Callback URL is needed for the authorization of OAuth2.0.
In Python-fitbit module, Cherrypy is used and its default URL is set as
If the port 8080 is not available, you have to change the port number.

– Default Access Type => Read & Write

3. Install modules for “python-fitbit

You can install the required modules by running the following commands according to “Readme” in
sudo pip install -r requirements/base.txt
sudo pip install -r requirements/dev.txt
sudo pip install -r requirements/test.txt

Additionally, you need “cherrypy”.
If you haven’t installed it, please install it.

Obtaining “Access Token” and “Refresh Token”

By running “” in python-fitbit folder, we can get “Access Token” and “Refresh Token” for OAuth2.0.

For running the program, we need “OAuth 2.0 Client ID” and “Client (Consumer) Secret” in the API web page.

Please enter following command.

Python “OAuth 2.0 Client ID” “Client (Consumer) Secret”

And you can see the application register screen in your browser.
If the registration succeeds, you can see “You are now authorized to access the Fitbit API!”.

After that, “Access Token” and “Refresh Token” are displayed in your console.

If the registration does not succeed, the port 8080 is not available in your environment.
So, you should rewrite the following points.

– Callback URL =>”port number except 8080″

– line 17) redirect_uri=’”port number you set above”

– Changing the port number in cherrypy:
Add the following code to “” (after “import cherrypy”)


Obtaining HR data

I explain commands for obtaining HR data.

Firstly, the authorization of OAuth2.0 using “Access Token” and “Refresh Token” can be done by

auth2_client = fitbit.Fitbit(‘OAuth 2.0 Client ID’, ‘Client (Consumer) Secret’, oauth2=True, access_token=’Access Token’, refresh_token=’Refresh Token’)

After that, you can obtain data you like.

Example 1. Data every 15 minutes on 2015/11/16:

fitbit_stats = auth2_client.intraday_time_series(‘activities/heart’, base_date=’2015-11-16′, detail_level=’15min’)

Example 2. Data every 1 minute from 12 pm to 13 pm on 2015/11/1:

fitbit_stats = auth2_client.intraday_time_series(‘activities/heart’, base_date=’2015-11-01′, detail_level=’1min’, start_time=’12:00′, end_time=’13:00′)

You can get HR time-series data as “Dictionary”.

Output of Example 1:


{‘activities-heart-intraday’: {‘dataset’: [{‘value’: 85, ‘time’: ’00:30:00′}, {‘value’: 73, ‘time’: ’00:45:00′}, {‘value’: 67, ‘time’: ’01:00:00′}, {‘value’: 65, ‘time’: ’01:15:00′}, {‘value’: 65, ‘time’: ’01:30:00′}, {‘value’: 65, ‘time’: ’01:45:00′}, {‘value’: 66, ‘time’: ’02:00:00′}, {‘value’: 62, ‘time’: ’02:15:00′}, {‘value’: 59, ‘time’: ’02:30:00′}, {‘value’: 58, ‘time’: ’02:45:00′}, {‘value’: 58, ‘time’: ’03:00:00′}, {‘value’: 62, ‘time’: ’03:15:00′}, {‘value’: 64, ‘time’: ’03:30:00′}, {‘value’: 61, ‘time’: ’03:45:00′}, {‘value’: 59, ‘time’: ’04:00:00′}, {‘value’: 58, ‘time’: ’04:15:00′}, {‘value’: 60, ‘time’: ’04:30:00′}, {‘value’: 60, ‘time’: ’04:45:00′}, {‘value’: 60, ‘time’: ’05:00:00′}, {‘value’: 64, ‘time’: ’05:15:00′}, {‘value’: 61, ‘time’: ’05:30:00′}, {‘value’: 58, ‘time’: ’05:45:00′}, {‘value’: 60, ‘time’: ’06:00:00′}, {‘value’: 58, ‘time’: ’06:15:00′}, {‘value’: 58, ‘time’: ’06:30:00′}, {‘value’: 62, ‘time’: ’06:45:00′}, {‘value’: 60, ‘time’: ’07:00:00′}, {‘value’: 61, ‘time’: ’07:15:00′}, {‘value’: 59, ‘time’: ’07:30:00′}, {‘value’: 64, ‘time’: ’07:45:00′}, {‘value’: 61, ‘time’: ’08:00:00′}, {‘value’: 57, ‘time’: ’08:15:00′}, {‘value’: 58, ‘time’: ’08:30:00′}, {‘value’: 60, ‘time’: ’08:45:00′}, {‘value’: 61, ‘time’: ’09:00:00′}, {‘value’: 59, ‘time’: ’09:15:00′}, {‘value’: 58, ‘time’: ’09:30:00′}, {‘value’: 62, ‘time’: ’09:45:00′}, {‘value’: 64, ‘time’: ’10:00:00′}, {‘value’: 65, ‘time’: ’10:15:00′}, {‘value’: 64, ‘time’: ’10:30:00′}, {‘value’: 61, ‘time’: ’10:45:00′}, {‘value’: 62, ‘time’: ’11:00:00′}, {‘value’: 63, ‘time’: ’11:15:00′}, {‘value’: 63, ‘time’: ’11:30:00′}, {‘value’: 66, ‘time’: ’11:45:00′}, {‘value’: 68, ‘time’: ’12:00:00′}, {‘value’: 66, ‘time’: ’12:15:00′}, {‘value’: 65, ‘time’: ’12:30:00′}, {‘value’: 62, ‘time’: ’12:45:00′}, {‘value’: 63, ‘time’: ’13:00:00′}, {‘value’: 66, ‘time’: ’13:15:00′}, {‘value’: 73, ‘time’: ’13:30:00′}, {‘value’: 80, ‘time’: ’13:45:00′}, {‘value’: 83, ‘time’: ’14:00:00′}, {‘value’: 78, ‘time’: ’14:15:00′}, {‘value’: 80, ‘time’: ’14:30:00′}, {‘value’: 79, ‘time’: ’14:45:00′}, {‘value’: 80, ‘time’: ’15:00:00′}, {‘value’: 93, ‘time’: ’15:15:00′}, {‘value’: 108, ‘time’: ’15:30:00′}, {‘value’: 89, ‘time’: ’15:45:00′}, {‘value’: 85, ‘time’: ’16:00:00′}, {‘value’: 88, ‘time’: ’16:15:00′}, {‘value’: 74, ‘time’: ’16:30:00′}, {‘value’: 71, ‘time’: ’16:45:00′}, {‘value’: 68, ‘time’: ’17:00:00′}, {‘value’: 71, ‘time’: ’17:15:00′}, {‘value’: 67, ‘time’: ’17:30:00′}, {‘value’: 66, ‘time’: ’17:45:00′}, {‘value’: 64, ‘time’: ’18:00:00′}, {‘value’: 66, ‘time’: ’18:15:00′}, {‘value’: 65, ‘time’: ’18:30:00′}, {‘value’: 64, ‘time’: ’18:45:00′}, {‘value’: 65, ‘time’: ’19:00:00′}, {‘value’: 70, ‘time’: ’19:15:00′}, {‘value’: 97, ‘time’: ’19:30:00′}, {‘value’: 79, ‘time’: ’19:45:00′}, {‘value’: 86, ‘time’: ’20:00:00′}, {‘value’: 82, ‘time’: ’20:15:00′}, {‘value’: 97, ‘time’: ’20:30:00′}], ‘datasetType’: ‘minute’, ‘datasetInterval’: 15}, ‘activities-heart’: [{‘dateTime’: ‘2015-11-16’, ‘value’: {‘customHeartRateZones’: [], ‘restingHeartRate’: 67, ‘heartRateZones’: [{‘min’: 30, ‘caloriesOut’: 1423.58755, ‘max’: 97, ‘name’: ‘Out of Range’, ‘minutes’: 1162}, {‘min’: 97, ‘caloriesOut’: 234.92623, ‘max’: 135, ‘name’: ‘Fat Burn’, ‘minutes’: 43}, {‘min’: 135, ‘caloriesOut’: 0, ‘max’: 164, ‘name’: ‘Cardio’, ‘minutes’: 0}, {‘min’: 164, ‘caloriesOut’: 0, ‘max’: 220, ‘name’: ‘Peak’, ‘minutes’: 0}]}}]}

Data handling

I’d like to introduce my code for displaying HR histogram.

This code includes the OAuth2.0 authorization process by reference to “”, and output a text file of HR time-series data(dataHR-timeseries.txt).

Code: Displaying histogram of heart rate time series on 2015/11/1


11 thoughts on “How to obtain Heart Rate (HR) Intraday Time Series by Fitbit API and Python

  1. When I run “” I get the following error message on the Fitbit web page that loads:

    “The app you’re trying to connect did not provide valid information to Fitbit. Please report this issue to them.
    Developer information: invalid_request – Invalid redirect_uri parameter value”

    I’ve tried changing the port as recommended, but it’s had no effect.

    Anyone got any ideas?

    1. Thank you for your comment.

      I run my python program and got same error today.
      But, I solved this error by trying following revision.
      Please revise “the callback URL” to “” (last slash is important).

      Additionally, you said that you changed the port number.
      Did you change the port number in “cherrypy” too?

  2. Hey man,

    nice work on the tutorial, so farm it’s been the best one I found.
    I’ve been stuck on gathering access&refresh tokens though.
    After clicking “Allow” on the auth page, instead of getting my keys into console, I get this error:

    Looking forward to hear from you,

    1. Thank you for your comment.

      I think the error is caused by “wrong default encoding”.
      Please try the following

      $ python
      >>> import sys
      >>> sys.getdefaultencoding()

      If you get ‘ascii’ as the response, you have to change ‘ascii’ to ‘UTF-8’.

      The default encoding can be changed by making or editing “” in “/usr/lib/python2.7/dist-packages/”(perhaps in your environment).
      Please add the following code to “”

      import sys

      And, try the above command again.
      If you get ‘utf-8’ as the response, you maybe run the program.

        1. You can get “dataHR-timeserieses.txt”, which is just the time-series data of HR, if you run the program in “”.
          Did you see that data? I just use the data and MS Excel to show the time-series HR in the post you stated.

          Thank you.

  3. Hi!

    i’m getting troubles with refresh token. is it supposed to be automatically? i checked all the code. In the makerequest function it is supposed to refresh the token but it keeps me giving the 401 error after 1 hour of the code running

    1. Thank you for your comment.

      As stated in “”, the access tokens have a one-hour lifetime.
      Please visit the page “”.

  4. こんにちは

    1. 質問ありがとうございます。



Comments are closed.