We're making some changes to the Google Fit APIs. Learn about how these changes might affect your app. Read our new policy.

Authorization, heart rate and sleep updates 2020

As part of our ongoing effort to enhance the security and privacy of Google Fit for users and developers, we’re making changes to the next version of the Google Fit API. If you're a developer with an existing app/project that uses the Google Fit APIs, learn about the changes we're making below and how they might affect your app.

Follow the relevant instructions to make sure your integration continues to work. These changes will be available for developers to test and use from 19 October 2020. The changes will become enforceable on 27 April 2021.

What's changing?

Improving the behaviour of read and write access

Before, Write scopes allowed both write-access and read-access.

Now, Write scopes allow your app to have write-access and read-access only to data written by your app.

What do you need to do?

To read data written by other apps from the Google Fit platform, update your integration to explicitly request the relevant read scopes.

Android

  1. Upgrade your app to build using SDK version 20.0.0.
  2. To read data written by other apps from the Google Fit platform, add the corresponding read constant to your code. For example, this:

    val fitnessOptions = FitnessOptions.builder()
        .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_WRITE)
        .build()
    

    becomes this:

    val fitnessOptions = FitnessOptions.builder()
        // Add the read scope.
        .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
        .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_WRITE)
        .build()
    

REST

If your application only requests the write scope, but also relies on reading data of this type that it did not write, you should explicitly add the corresponding read scope.

Separate scopes for heart rate

Before, heart rate came under the Body scope.

Now, heart data has its own, dedicated pair of scopes that apply to the heart rate data type. This increased granularity of access recognises the sensitivity of heart rate data and lets users grant access to your app to read and/or write heart rate data independently of other body data types.

What do you need to do?

Android

  1. Upgrade your app to build using SDK version 20.0.0.
  2. Post-upgrade, the first time your app requests the heart rate data type, by using the appropriate data type in FitnessOptions, the app will request permission for the new scope.

REST

Modify your application to request the appropriate additional scope(s) as necessary:

    https://www.googleapis.com/auth/fitness.heart_rate.read
    https://www.googleapis.com/auth/fitness.heart_rate.write

Separate scopes and new data type for sleep

Before, sleep was treated as an activity, under the activity data type.

Now, sleep data has:

  • Its own, separate data type. This increases the clarity around how Google Fit treats activity data versus sleep data.
  • Its own, dedicated pair of scopes that apply to the new sleep data type. This increased granularity of access recognises the sensitivity of sleep data and lets users grant access to your app to read and/or write sleep data independently of other activity data types.

What do you need to do?

Android

  1. Upgrade your app to build using SDK version 20.0.0.
  2. Use the new sleep data type. The first time your app requests the sleep.segments data type, post-upgrade, the app will request permission for the new scope.

    val fitnessOptions = FitnessOptions.builder() .addDataType(DataType.TYPE_SLEEP_SEGMENT, FitnessOptions.ACCESS_READ) .build()

  3. Migrate to the new data type in your data sources, for example

     val dataSource  = DataSource.Builder()
        .setType(DataSource.TYPE_RAW)
        .setDataType(DataType.TYPE_SLEEP_SEGMENT)
        .setAppPackageName(this)
        .setStreamName(streamName)
        .build()
    
  4. Migrate your construction of data points to use the new data type:

    val dataSet = DataSet.builder(dataSource)
        .add(
            DataPoint.builder(dataSource)
                .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
                .setField(Field.FIELD_SLEEP_SEGMENT_TYPE, SleepStages.SLEEP_LIGHT)
                .build()
        ).build()
    
  5. To read sleep sessions, use the .includeSleepSessions() method as sleep sessions aren't returned by default. Learn more about reading sleep data.

     SessionReadRequest request = new SessionReadRequest.Builder()
        .readSessionsFromAllApps()
        // By default, only activity sessions are included, so you
        // need to explicitly request sleep sessions.
        .includeSleepSessions()
        .read(DataType.TYPE_SLEEP_SEGMENT)
        .setTimeInterval(1576690819, 1576750401, TimeUnit.SECONDS)
        .build();
    

REST

  1. Modify your application to request the appropriate additional scope(s):

    https://www.googleapis.com/auth/fitness.sleep.read
    https://www.googleapis.com/auth/fitness.sleep.write
    

    It's best practice to request authorization from users for resources at the time you need them. Follow the guidelines on requesting incremental authorization.

  2. Migrate from using com.google.activity.segment to com.google.sleep.segment, and change the integer for the type of sleep to the new sleep_segment_type enum:

    {
        "dataTypeName": "com.google.activity.segment",
        "startTimeNanos": startTime,
        "endTimeNanos": endTime,
        "value": [
            {
                intVal: 109 // Light sleep
            }
        ]
    }
    

    becomes

    {
        "dataTypeName": "com.google.sleep.segment",
        "startTimeNanos": startTime,
        "endTimeNanos": endTime,
        "value": [
            {
                intVal: 4 // Light sleep
            }
        ]
    }
    

Activity segments with a sleep activity type will be automatically 1-time copied into sleep segments at or before migration start date. This will ensure that any data read from sleep.segment will always contain all sleep data for the user.

Increasing clarity around session versus data access

If you're using our Android APIs, currently using FitnessOptions lets you specify which types of data you want access to, but it doesn't let you be explicit about what types of sessions you want access to. Sessions are metadata about something users did, like an activity, a workout or a night’s sleep.

Now, when working with the SessionsClient, you need to specify what type of session your app needs to access, using the appropriate methods from FitnessOptions. For example, to read sessions relating to running you might choose:

        val fitnessOptions = FitnessOptions.builder()
            .accessActivitySessions(FitnessOptions.ACCESS_READ)
            .addDataType(DataType.TYPE_HEART_RATE_BPM, FitnessOptions.ACCESS_READ)
            .addDataType(DataType.TYPE_SPEED, FitnessOptions.ACCESS_READ)
            .addDataType(DataType.TYPE_LOCATION_SAMPLE, FitnessOptions.ACCESS_READ)
            .build()

This example specifies that your app wants to access activity session metadata, and it also specifies the data types it wants to read within those sessions; the heart rate, speed and location data types are used in this example.

Strengthening the review system for apps using Google Fit

We're conscious that health and wellness data is particularly sensitive to users. Ensuring the security and privacy of that data is of utmost importance. So, we will be enhancing the review system that apps using Google Fit need to go through. This enhanced review process will begin in the second quarter of 2021.

To enable the enhanced review, we’ll be updating all Fitness API scopes for Write access to Sensitive, and all scopes for Read access to Restricted. To understand the implications for your apps, learn more about requesting access to sensitive and restricted OAuth scopes.

What do you need to do?

When to apply for verification?

  • If your app is affected by these API changes and you need to update your integration/required scopes, you have until 27 April 2021 (when enforcement begins) to do this and go through verification. Wait until you’re contacted by the Trust and Safety team who will reach out at least a month before enforcement starts to give you more information on the verification process and next steps. Your app will continue to have access to the data and scopes it currently does until then.

  • If your app is not affected by these API changes and you want to request access to a new scope or scopes, you can apply for verification whenever you're ready to submit your application.

Thinking about user experience

When you update your app to request a new scope (for example, if you add the new sleep or heart rate scopes, or add a read scope), users will be prompted that your app is requesting these access to these scopes and they can choose to grant or reject access.

It's best practice to request authorization from users for resources at the time you need them. Follow the guidelines on requesting incremental authorization.

Users will be more likely to grant access if they understand why/how your app uses this data:

  • Consider adding a screen that warns/informs users that they'll be asked for these scopes.
  • Clearly explain why your app is asking for access to these scopes/data so users can make an informed decision.

Learn more about best practices around app permissions for Android.

Testing your integration before enforcement

You can test your integration before the enforcement date to check your changes work as expected.

Android

Use SDK 20.0.0 or later to switch to the new authorization model.

REST

Use the use2020ScopeRestrictions parameter to switch to the new authorisation model before the enforcement date to test your integration.

../fitness/v1/users/me/dataSources -H 'Authorization: Bearer ' -H 'FitAuthOptions: use_2020_scope_restrictions:true