Develop Workout Experiences with Google Health API

The Google Health API tracks user workout sessions and exercise history using the exercise session data type. A session acts as a container that bundles activity metadata, pause and resume events, laps or splits, and summary metrics.

Understand how to read, write, and structure workouts in your application to deliver the best experience for your users.

Supported data types

The API supports the following data type for tracking workouts and activity sessions:

Table: Google Health API Workouts data types
Data type Available
operations
Scope
Exercise
dataType: exercise
filter parameter: exercise
Record type: Session

Compatible devices

list, get, reconcile, create, update, batchDelete .activity_and_fitness.readonly
.activity_and_fitness.writeonly

While workout sessions use the exercise data type as a container, wearable devices also record detailed, high-frequency telemetry during a session. In the Google Health API, these granular intraday telemetry data types are read-only and cannot be created or modified directly through their own REST endpoints. When writing a workout session through the REST API, pass aggregate workout metrics inside the metricsSummary object of the exercise data point.

The following table maps the summary fields inside exercise.metricsSummary to the corresponding read-only intraday telemetry data types that you can query for that workout's time window:

Summary field (metricsSummary) Intraday telemetry data type name API telemetry data type ID (read-only) Filter field (?filter=) Required read OAuth scope
caloriesKcal Active Energy Burned active-energy-burned active_energy_burned.interval.start_time activity_and_fitness.readonly
distanceMillimeters Distance distance distance.interval.start_time activity_and_fitness.readonly
steps Steps steps steps.interval.start_time activity_and_fitness.readonly
averageHeartRateBeatsPerMinute Heart Rate heart-rate heart_rate.sample_time.physical_time health_metrics_and_measurements.readonly
activeZoneMinutes Active Zone Minutes active-zone-minutes active_zone_minutes.interval.start_time activity_and_fitness.readonly

The following sections provide technical details for the exercise data type, including REST representation examples, GPS route handling, and integration guidelines.

Workout sessions

Write daily activities or workouts as exercise session data points. Each data point describes the overall session, details event intervals (such as pause and resume actions), and supplies summary metrics (like overall distance, steps, and average heart rate).

Session attributes

When structuring an exercise data point, verify the following core components:

  • Session Time (interval): The start time and end time of the overall workout session, along with the timezone offsets active at those points.
  • Activity Type (exerciseType): The category of activity performed (such as RUNNING, WALKING, BIKING, or AEROBIC_WORKOUT). Specify the exact type of physical training.
  • Display Name (displayName): A user-friendly name for the workout session. When created through the REST API, the server populates the localized display name for the exerciseType, such as "Run" for RUNNING.
  • Active Duration (activeDuration): The true active time of the workout, excluding paused intervals. Standard formatting uses Duration format (for example, "1800s"). On the server, activeDuration is calculated from the session interval minus any PAUSE/RESUME or AUTO_PAUSE/AUTO_RESUME intervals in exerciseEvents.

Summary metrics

The metricsSummary nested object contains total and average metrics calculated across the entire duration of the exercise session:

  • caloriesKcal: Total active calories burned during the workout, measured in kilocalories (kcal).
  • distanceMillimeters: Total distance covered, measured in millimeters to maintain high precision across units.
  • steps: Total steps taken during the exercise.
  • averageHeartRateBeatsPerMinute: The user's average heart rate during active minutes of the session.
  • activeZoneMinutes: Cumulative active zone minutes earned during the workout.
  • averageSpeedMillimetersPerSecond: Average movement speed in millimeters per second.
  • averagePaceSecondsPerMeter: Average pace during active minutes of the session, measured in seconds per meter.
  • elevationGainMillimeters: Total elevation gain during the session.

Laps and splits

For workouts that involve laps (such as track runs or pool swimming) synced from supported devices, splitSummaries segments the session by lap or split.

Each split contains:

  • A specific startTime and endTime.
  • An activeDuration representing true lap time.
  • A metricsSummary scoped only to that segment.
  • A splitType to define the split boundaries (such as DISTANCE, DURATION, or MANUAL).

Exercise events

To accurately compute active duration, track state transitions (like manual or automatic pause events) using exerciseEvents.

Each event contains the timestamp (eventTime) and type:

  • START / STOP: Indicates boundary timestamps of when the user explicitly started or stopped the record.
  • PAUSE / RESUME: Indicates when the session was manually paused or resumed.
  • AUTO_PAUSE / AUTO_RESUME: Indicates sensor-driven auto-pauses/resumes.

Write a workout session

To create, update, or import a workout session, write a data point to the exercise data type collection. Use the create dataPoints endpoint.

REST representation example

The following example shows how to write a workout session using a POST method:

Request

POST https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints
Authorization: Bearer access-token
Content-Type: application/json

{
  "dataSource": {
    "recordingMethod": "ACTIVELY_MEASURED",
    "platform": "GOOGLE_WEB_API"
  },
  "exercise": {
    "interval": {
      "startTime": "2026-04-20T08:00:00Z",
      "startUtcOffset": "0s",
      "endTime": "2026-04-20T08:35:00Z",
      "endUtcOffset": "0s"
    },
    "exerciseType": "RUNNING",
    "activeDuration": "1800s",
    "metricsSummary": {
      "caloriesKcal": 380.0,
      "distanceMillimeters": 5000000.0,
      "steps": "6200",
      "averageHeartRateBeatsPerMinute": "148",
      "averagePaceSecondsPerMeter": 0.36
    },
    "exerciseEvents": [
      {
        "eventTime": "2026-04-20T08:15:00Z",
        "eventUtcOffset": "0s",
        "exerciseEventType": "PAUSE"
      },
      {
        "eventTime": "2026-04-20T08:20:00Z",
        "eventUtcOffset": "0s",
        "exerciseEventType": "RESUME"
      }
    ]
  }
}

Response

{
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.devicesandservices.health.v4.DataPoint",
    "name": "users/999298779973222220/dataTypes/exercise/dataPoints/3054085373369111216",
    "dataSource": {
      "recordingMethod": "ACTIVELY_MEASURED",
      "application": {
        "googleWebClientId": "438076457939-example.apps.googleusercontent.com"
      },
      "platform": "GOOGLE_WEB_API"
    },
    "exercise": {
      "interval": {
        "startTime": "2026-04-20T08:00:00Z",
        "startUtcOffset": "0s",
        "endTime": "2026-04-20T08:35:00Z",
        "endUtcOffset": "0s"
      },
      "exerciseType": "RUNNING",
      "metricsSummary": {
        "caloriesKcal": 380,
        "distanceMillimeters": 5000000,
        "steps": "6200",
        "averagePaceSecondsPerMeter": 0.36,
        "averageHeartRateBeatsPerMinute": "148"
      },
      "exerciseMetadata": {},
      "displayName": "Run",
      "activeDuration": "1800s",
      "exerciseEvents": [
        {
          "eventTime": "2026-04-20T08:15:00Z",
          "eventUtcOffset": "0s",
          "exerciseEventType": "PAUSE"
        },
        {
          "eventTime": "2026-04-20T08:20:00Z",
          "eventUtcOffset": "0s",
          "exerciseEventType": "RESUME"
        }
      ],
      "updateTime": "2026-04-20T08:35:10.123456Z",
      "createTime": "2026-04-20T08:35:10.123456Z"
    }
  }
}

GPS routes and location tracking

The API saves basic session summaries directly within the exercise data point, but handles detailed location history and GPS route coordinates as a separate stream.

To download the detailed route data for an outdoor session, call the exportExerciseTcx custom method. This endpoint returns the route in the industry-standard Training Center XML (TCX) format.

Export GPS route

Request

GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints/exercise-data-point-id:exportExerciseTcx?alt=media
Authorization: Bearer access-token

Response

An HTTP payload with Content-Type: application/tcx+xml and headers instructing the browser to save the file.

<?xml version="1.0" encoding="UTF-8"?>
<TrainingCenterDatabase xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">
  <Activities>
    <Activity Sport="Running">
      <Id>2026-04-20T08:00:00Z</Id>
      <Lap StartTime="2026-04-20T08:00:00Z">
        <TotalTimeSeconds>1800</TotalTimeSeconds>
        <DistanceMeters>5000</DistanceMeters>
        <Calories>380</Calories>
        <Intensity>Active</Intensity>
        <TriggerMethod>Manual</TriggerMethod>
        <Track>
          <Trackpoint>
            <Time>2026-04-20T08:00:00Z</Time>
            <Position>
              <LatitudeDegrees>37.7749</LatitudeDegrees>
              <LongitudeDegrees>-122.4194</LongitudeDegrees>
            </Position>
            <AltitudeMeters>15.0</AltitudeMeters>
            <DistanceMeters>0.0</DistanceMeters>
          </Trackpoint>
        </Track>
      </Lap>
    </Activity>
  </Activities>
</TrainingCenterDatabase>

Required scopes and location

To use the GPS routes and location tracking feature, your app must request the following OAuth scopes:

  • Read: https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly
  • Write: https://www.googleapis.com/auth/googlehealth.activity_and_fitness.writeonly
  • Read: https://www.googleapis.com/auth/googlehealth.location.readonly

Guidelines

When integrating workout tracking into your app, follow these design and implementation guidelines.

Active versus total duration

To calculate speed or pace metrics, always use activeDuration rather than the difference between startTime and endTime. This prevents paused intervals from skewing your metrics.

For example, if a user starts a workout at 08:00 and finishes at 08:35, the workout has a total elapsed duration of 2,100 seconds. If the user paused the workout for 5 minutes (300 seconds) and you include PAUSE and RESUME events in exerciseEvents, the active duration is "1800s" (2,100 - 300). The API uses active duration to calculate averages, dividing total distance by 1,800 seconds instead of 2,100.

Speed and pace calculation

The Google Health API uses standard formulas to calculate speed and pace:

  • Speed = distance / time(hour)
  • Pace = time(seconds) / distance

The Accept-Language header specified in the request determines the unit of distance.

Request location early

If your app maps workout routes, request location permissions and the Google Health location scope in addition to the activity and fitness scope. Explain to users why your app requires the location scope when reviewing GPS exercises.

When your app requests the location scope (https://www.googleapis.com/auth/googlehealth.location.readonly), Google OAuth displays a consent prompt to the user. Explain to your users that this permission is necessary to render route overlays and export GPS track files (TCX). If a user grants the activity scope but denies location permission, exportExerciseTcx returns an authorization error, though you can still access session aggregates in metricsSummary.

Sync using webhooks

Subscribe to the exercise data type to notify your backend using webhooks when new workout data becomes available. This lets you trigger post-workout experiences automatically.

When your server receives a webhook notification, it contains the healthUserId and the civil time interval (civilIso8601TimeInterval) of the updated workout. Your server should acknowledge the notification immediately with 204 No Content, process the payload asynchronously, and query the reconciled exercise endpoint using an exercise.interval.civil_start_time filter (note that exercise only supports filtering by civil_start_time):

GET https://health.googleapis.com/v4/users/healthUserId/dataTypes/exercise/dataPoints:reconcile?filter=exercise.interval.civil_start_time >= "2026-04-20T08:00:00" AND exercise.interval.civil_start_time < "2026-04-20T10:00:00"

For details on how to set up subscriptions, see Webhook subscriptions.

Maintain consistent metrics

To provide a complete workout experience, include summary metrics when writing exercise sessions and query the read-only telemetry endpoints using time-range filters when rendering detail charts.

Write workout summary metrics (write path)

When importing or writing a completed workout to the Google Health API, include the workout's aggregate telemetry metrics (steps, caloriesKcal, distanceMillimeters, averageHeartRateBeatsPerMinute, and averagePaceSecondsPerMeter) inside the metricsSummary object of the exercise data point:

  • POST https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints

Query detailed data for charts (read path)

To build workout dashboards or charts for a specific session, query the reconciled telemetry endpoints for that workout's time window:

  1. Fetch the workout session from the exercise endpoint using a civil_start_time filter to get its interval and metricsSummary:

    GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints:reconcile?filter=exercise.interval.civil_start_time >= "2026-04-20T00:00:00" AND exercise.interval.civil_start_time < "2026-04-21T00:00:00"
  2. Use the session's interval.startTime and interval.endTime to query the telemetry endpoints for that physical time window.

  3. If exerciseMetadata.hasGps is true, call exportExerciseTcx to download the route coordinates.