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
  dataType
  filter parameter
Record
type
Available
operations
Scope Webhook
support
True zeros
support
Exercise
  exercise
  exercise
Session list, get, reconcile, create, update, batchDelete activity_and_fitness

While workout sessions use the exercise data type as a container, typical workout trackers write and read detailed, high-frequency telemetry during the session. These measurements (such as heart rate or step count) must be read or written using their own respective data types.

The following table maps the fields inside the metricsSummary object of the exercise data type to the corresponding raw telemetry data types of the Google Health API:

Summary field (metricsSummary) Intraday telemetry data type name API telemetry data type ID
caloriesKcal Active Energy Burned active-energy-burned
distanceMillimeters Distance distance
steps Steps steps
averageHeartRateBeatsPerMinute Heart Rate heart-rate
activeZoneMinutes Active Zone Minutes active-zone-minutes

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 (for example, "Afternoon Trail Run").
  • Active Duration (activeDuration): The true active time of the workout, excluding paused intervals. Standard formatting uses Duration format (for example, "1800s").

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), use splitSummaries.

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 data points 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"
  },
  "exercise": {
    "interval": {
      "startTime": "2026-04-20T08:00:00Z",
      "startUtcOffset": "0s",
      "endTime": "2026-04-20T08:35:00Z",
      "endUtcOffset": "0s"
    },
    "exerciseType": "RUNNING",
    "displayName": "Morning Trail Run",
    "activeDuration": "1800s",
    "metricsSummary": {
      "caloriesKcal": 380.0,
      "distanceMillimeters": 5000000.0,
      "steps": "6200",
      "averageSpeedMillimetersPerSecond": 2777.78,
      "averagePaceSecondsPerMeter": 360.0,
      "averageHeartRateBeatsPerMinute": "148",
      "activeZoneMinutes": "30"
    },
    "exerciseMetadata": {
      "hasGps": true
    },
    "exerciseEvents": [
      {
        "eventTime": "2026-04-20T08:15:00Z",
        "eventUtcOffset": "0s",
        "exerciseEventType": "PAUSE"
      },
      {
        "eventTime": "2026-04-20T08:20:00Z",
        "eventUtcOffset": "0s",
        "exerciseEventType": "RESUME"
      }
    ],
    "splitSummaries": [
      {
        "startTime": "2026-04-20T08:00:00Z",
        "startUtcOffset": "0s",
        "endTime": "2026-04-20T08:15:00Z",
        "endUtcOffset": "0s",
        "splitType": "DISTANCE",
        "metricsSummary": {
          "distanceMillimeters": 2500000.0,
          "caloriesKcal": 190.0
        }
      }
    ]
  }
}

Response

{
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.devicesandservices.health.v4main.DataPoint",
    "name": "users/me/dataTypes/exercise/dataPoints/morning-trail-run-123456",
    "dataSource": {
      "recordingMethod": "ACTIVELY_MEASURED",
      "application": {
        "packageName": "com.example.workoutapp"
      },
      "platform": "GOOGLE_WEB_API"
    },
    "exercise": {
      "interval": {
        "startTime": "2026-04-20T08:00:00Z",
        "startUtcOffset": "0s",
        "endTime": "2026-04-20T08:35:00Z",
        "endUtcOffset": "0s"
      },
      "exerciseType": "RUNNING",
      "displayName": "Morning Trail Run",
      "activeDuration": "1800s",
      "metricsSummary": {
        "caloriesKcal": 380.0,
        "distanceMillimeters": 5000000.0,
        "steps": "6200",
        "averageSpeedMillimetersPerSecond": 2777.78,
        "averagePaceSecondsPerMeter": 360.0,
        "averageHeartRateBeatsPerMinute": "148",
        "activeZoneMinutes": "30"
      },
      "exerciseMetadata": {
        "hasGps": true
      },
      "exerciseEvents": [
        {
          "eventTime": "2026-04-20T08:15:00Z",
          "eventUtcOffset": "0s",
          "exerciseEventType": "PAUSE"
        },
        {
          "eventTime": "2026-04-20T08:20:00Z",
          "eventUtcOffset": "0s",
          "exerciseEventType": "RESUME"
        }
      ],
      "splitSummaries": [
        {
          "startTime": "2026-04-20T08:00:00Z",
          "startUtcOffset": "0s",
          "endTime": "2026-04-20T08:15:00Z",
          "endUtcOffset": "0s",
          "activeDuration": "900s",
          "splitType": "DISTANCE",
          "metricsSummary": {
            "distanceMillimeters": 2500000.0,
            "caloriesKcal": 190.0
          }
        }
      ]
    }
  }
}

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 read or write data for GPS routes and location tracking, request the following OAuth scopes in your application's access token:

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

If a required scope is missing from the authorization headers, the Google Health API returns an authorization error.

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), set activeDuration to "1800s" (2,100 - 300). The API uses active duration to calculate averages, dividing total distance by 1,800 seconds instead of 2,100.

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.

Real-time 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 in real time.

When your server receives a webhook notification, it contains the healthUserId and the specific physical time interval of the workout. Your server should process the notification asynchronously and then request the new exercise data point from the /users/me/dataTypes/exercise/dataPoints endpoint. For details on how to set up subscriptions, see Webhook subscriptions.

Maintain consistent metrics

To provide a complete workout experience, your app must synchronize high-frequency telemetry data points alongside the overall exercise session. This ensures that the user's daily totals, historical trends, and detail charts remain fully aligned.

Sync telemetry and sessions (write path)

When importing or writing a completed workout to the Google Health API, implement a multi-step write pattern:

  1. Write the session: File the summary event by posting a data point to POST /users/me/dataTypes/exercise/dataPoints.
  2. Write time-series intervals: Concurrently write the granular data points logged during the workout (for example, minute-by-minute steps or calorie burn intervals) to their respective collections:
    • POST /users/me/dataTypes/steps/dataPoints
    • POST /users/me/dataTypes/active-energy-burned/dataPoints
    • POST /users/me/dataTypes/heart-rate/dataPoints

Query detailed data for charts (read path)

When rendering historical workout dashboards or performance graphs for a specific workout session, query the granular telemetry using the session's time window:

  1. Query the session summaries: Call /users/me/dataTypes/exercise/dataPoints to fetch the overall workout details and the final metricsSummary.
  2. Fetch chart metrics: Inspect the workout's interval.startTime and interval.endTime. Make secondary GET calls to the telemetry collections for that specific time window:
    • GET /users/me/dataTypes/heart-rate/dataPoints?startTime=2026-04-20T08:00:00Z&endTime=2026-04-20T08:35:00Z
  3. Fetch GPS routes: If the session's metadata indicates GPS data is present (exerciseMetadata.hasGps is true), invoke the exportExerciseTcx helper method to download route coordinates.