---
title: "Health Connect API"
canonical: "https://aifitnessapi.com/health-connect-api"
type: "cluster-index"
pages: "15"
last_reviewed: "2026-10-04"
publisher: "AIFitnessAPI"
---

# Health Connect API

> 15 pages. Each entry below shows the question the page owns, followed by its answer capsule.

## readRecords and ReadRecordsRequest: paging with pageSize and pageToken

- Question: ReadRecordsRequest
- HTML: https://aifitnessapi.com/health-connect-api/readrecords-pagination
- Markdown: https://aifitnessapi.com/health-connect-api/readrecords-pagination.md
- Last reviewed: 2026-10-04

HealthConnectClient.readRecords takes a ReadRecordsRequest (a record type, a TimeRangeFilter, an optional set of DataOrigin values, ascendingOrder, pageSize and pageToken) and returns one page of records plus a pageToken. The default pageSize is 1000; when more records match, you pass the returned pageToken into the next request to get the next page. Google's reference says the token is null when there are no more pages, but its read guide warns that some versions return an empty string instead, so end the loop on isNullOrEmpty(). For totals of cumulative types such as steps, Google says to use aggregate() rather than adding up raw records.

## aggregate() and AggregateRequest: totals, averages and deduplicated sources

- Question: AggregateRequest
- HTML: https://aifitnessapi.com/health-connect-api/aggregate-request
- Markdown: https://aifitnessapi.com/health-connect-api/aggregate-request.md
- Last reviewed: 2026-10-04

HealthConnectClient.aggregate takes an AggregateRequest (a set of AggregateMetric values such as StepsRecord.COUNT_TOTAL, a TimeRangeFilter and an optional set of DataOrigin values) and returns one AggregationResult for the whole window. You read each metric with result[metric], which is null when no record contributed to it. Google documents that for Activity and Sleep data the Aggregate API drops duplicate data and keeps only the data from the app the user has given the highest priority, while for other types it combines the data of every app that wrote it.

## aggregateGroupByDuration vs aggregateGroupByPeriod: fixed buckets or calendar buckets

- Question: aggregateGroupByDuration vs aggregateGroupByPeriod
- HTML: https://aifitnessapi.com/health-connect-api/aggregategroupbyduration-vs-period
- Markdown: https://aifitnessapi.com/health-connect-api/aggregategroupbyduration-vs-period.md
- Last reviewed: 2026-10-04

Use aggregateGroupByDuration when every bucket should be the same length of physical time, such as each minute or hour, and aggregateGroupByPeriod when buckets follow the calendar, such as days, weeks or months. Google's reference says a Period day may be 23, 24 or 25 hours long because of daylight saving time, while a Duration slice is fixed. Period requests need a LocalDateTime TimeRangeFilter, because an Instant range causes an IllegalStateException, and both methods return a sparse list that leaves out buckets with no data.

## getChanges and getChangesToken: incremental sync from Health Connect

- Question: HealthConnectClient.getChanges
- HTML: https://aifitnessapi.com/health-connect-api/getchanges-incremental-sync
- Markdown: https://aifitnessapi.com/health-connect-api/getchanges-incremental-sync.md
- Last reviewed: 2026-10-04

Health Connect's incremental sync is two calls: getChangesToken(ChangesTokenRequest(recordTypes)) returns a token that marks a point in time, and getChanges(token) returns a ChangesResponse listing the UpsertionChange and DeletionChange entries since then, plus a nextChangesToken. Google says one response may not hold every change, so you keep calling with nextChangesToken while hasMore is true and store the last token for next time. A DeletionChange carries only the deleted record's id, not its type, so you need the Health Connect ids of anything you copied.

## insertRecords and clientRecordId: how Health Connect upserts

- Question: clientRecordId
- HTML: https://aifitnessapi.com/health-connect-api/insertrecords-clientrecordid-upsert
- Markdown: https://aifitnessapi.com/health-connect-api/insertrecords-clientrecordid-upsert.md
- Last reviewed: 2026-10-04

In Health Connect, insertRecords works as an upsert when your records carry a clientRecordId in their Metadata. Google's reference says there is guaranteed a single entry for any type of data with the same client-provided identifier for a given app, and that a new insert with that identifier either replaces the stored record or is ignored depending on clientRecordVersion: the higher version wins, and Google's write guide says a version that is not higher leaves the stored value unchanged. Versions never increase on their own, so your app must supply a larger Long for every change. updateRecords is the alternative when you hold the Health Connect id instead.

## deleteRecords: deleting Health Connect records by id, client id or time range

- Question: HealthConnectClient.deleteRecords
- HTML: https://aifitnessapi.com/health-connect-api/deleterecords
- Markdown: https://aifitnessapi.com/health-connect-api/deleterecords.md
- Last reviewed: 2026-10-04

HealthConnectClient.deleteRecords comes in two forms: one takes a record type plus a list of Health Connect record ids and a list of your client record ids, the other takes a record type and a TimeRangeFilter. Google's reference says the time-range form is automatically filtered to records belonging to the calling app, and that both forms run as a transaction, so if one deletion fails none is applied. Deleting a non-existent id, or the same record twice, causes an IPC failure for the whole call.

## PermissionController: requesting, checking and revoking Health Connect permissions

- Question: PermissionController.createRequestPermissionResultContract
- HTML: https://aifitnessapi.com/health-connect-api/permissioncontroller-request-permissions
- Markdown: https://aifitnessapi.com/health-connect-api/permissioncontroller-request-permissions.md
- Last reviewed: 2026-10-04

PermissionController is the Health Connect Jetpack interface for permissions, reached through healthConnectClient.permissionController, with a companion function, createRequestPermissionResultContract(), that returns an ActivityResultContract taking the set of permission strings you ask for and returning the set the user granted. getGrantedPermissions() returns every health permission the user has granted your app, and revokeAllPermissions() withdraws them all, although Google warns the change isn't immediately reflected in Health Connect without an app restart. Because the permission screen links to your privacy policy, the manifest also needs an activity for ACTION_SHOW_PERMISSIONS_RATIONALE and, on Android 14 and later, an activity alias for VIEW_PERMISSION_USAGE.

## READ_HEALTH_DATA_IN_BACKGROUND: reading Health Connect data from a background worker

- Question: READ_HEALTH_DATA_IN_BACKGROUND
- HTML: https://aifitnessapi.com/health-connect-api/read-health-data-in-background
- Markdown: https://aifitnessapi.com/health-connect-api/read-health-data-in-background.md
- Last reviewed: 2026-10-04

Health Connect only lets an app read while it is in the foreground unless the user grants android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND, which Google describes as an extra permission that lets you "read data after the user or system places your app in the background." It depends on the Health Connect version installed, so check HealthConnectFeatures.FEATURE_READ_HEALTH_DATA_IN_BACKGROUND with getFeatureStatus() first, then request it from the foreground with the usual permission contract. Google's documented pattern is a periodic WorkManager CoroutineWorker that calls readRecords; there is no callback, because Google says apps cannot be notified of new data.

## READ_HEALTH_DATA_HISTORY: reading Health Connect data older than 30 days

- Question: READ_HEALTH_DATA_HISTORY
- HTML: https://aifitnessapi.com/health-connect-api/read-health-data-history
- Markdown: https://aifitnessapi.com/health-connect-api/read-health-data-history.md
- Last reviewed: 2026-10-04

By default, Google says, "all applications can read data from Health Connect for up to 30 days prior to when any permission was first granted." The android.permission.health.READ_HEALTH_DATA_HISTORY permission lifts that limit for every data type and applies to readRecord, readRecords, the three aggregate methods and getChanges. Without it, readRecord on an older record fails, while the other methods quietly leave older data out. It depends on the Health Connect version, so check FEATURE_READ_HEALTH_DATA_HISTORY first, and note that uninstalling the app revokes it and restarts the 30-day window from the new grant.

## Health Connect Metadata: recordingMethod, Device and the fields Health Connect fills in

- Question: Health Connect Metadata recordingMethod
- HTML: https://aifitnessapi.com/health-connect-api/metadata-recording-method
- Markdown: https://aifitnessapi.com/health-connect-api/metadata-recording-method.md
- Last reviewed: 2026-10-04

Every Health Connect record needs a Metadata object, and since Jetpack 1.1.0-alpha12 you build it with a factory function, such as Metadata.activelyRecorded(), autoRecorded(), manualEntry() or unknownRecordingMethod(), instead of a constructor. The factory sets one of four RECORDING_METHOD constants, and the actively and automatically recorded ones require a Device with a type such as Device.TYPE_WATCH. Health Connect itself fills in id, dataOrigin and lastModifiedTime at insertion and ignores any value you assign to them beforehand.

## HealthConnectFeatures.getFeatureStatus: checking what the user's Health Connect supports

- Question: HealthConnectFeatures getFeatureStatus
- HTML: https://aifitnessapi.com/health-connect-api/getfeaturestatus-feature-availability
- Markdown: https://aifitnessapi.com/health-connect-api/getfeaturestatus-feature-availability.md
- Last reviewed: 2026-10-04

HealthConnectFeatures.getFeatureStatus(feature) tells you whether one Health Connect capability works on the user's device, returning FEATURE_STATUS_AVAILABLE (2) or FEATURE_STATUS_UNAVAILABLE (1). You call it through healthConnectClient.features with one of the FEATURE_ constants, such as FEATURE_READ_HEALTH_DATA_IN_BACKGROUND, FEATURE_READ_HEALTH_DATA_HISTORY or FEATURE_PLANNED_EXERCISE. Google's reference lists ten flags, one more than its availability guide. When a feature is unavailable, Google says to ask the user to update Health Connect, noting that features tied to the system module stay unavailable on Android 13 and lower even with the APK.

## Health Connect exercise routes: ExerciseRouteResult and the per-session consent flow

- Question: ExerciseRouteResult.ConsentRequired
- HTML: https://aifitnessapi.com/health-connect-api/exercise-route-consent
- Markdown: https://aifitnessapi.com/health-connect-api/exercise-route-consent.md
- Last reviewed: 2026-10-04

A Health Connect exercise route is read from ExerciseSessionRecord.exerciseRouteResult, which is one of three results: Data with the route, NoData when the session has none, or ConsentRequired, which Google's reference describes as "a permission hasn't been granted and a value couldn't be returned." READ_EXERCISE_ROUTES cannot be requested through the normal permission contract; the user grants it in Settings, or approves one route at a time through the dialog launched by ExerciseRouteRequestContract with the session ID. Google says routes created by other apps cannot be read while your app is in the background.

## PlannedExerciseSessionRecord: training plans in Health Connect

- Question: PlannedExerciseSessionRecord
- HTML: https://aifitnessapi.com/health-connect-api/planned-exercise-session-training-plans
- Markdown: https://aifitnessapi.com/health-connect-api/planned-exercise-session-training-plans.md
- Last reviewed: 2026-10-04

PlannedExerciseSessionRecord is Health Connect's training-plan record, which Google's reference describes as "a planned exercise session, also commonly referred to as a training plan." A plan holds blocks, each block repeats a list of steps, and each step has an exercise phase, a completion goal and performance targets such as a heart-rate range; its start and end may be in the future. The workout app links its ExerciseSessionRecord back by setting plannedExerciseSessionId, and Health Connect fills in the plan's completedExerciseSessionId automatically. The record requires FEATURE_PLANNED_EXERCISE and has no supported aggregations.

## Health Connect permission UI: Google's guidance for onboarding, requests and settings

- Question: Health Connect permission UI guidelines
- HTML: https://aifitnessapi.com/health-connect-api/permission-ui-guidelines
- Markdown: https://aifitnessapi.com/health-connect-api/permission-ui-guidelines.md
- Last reviewed: 2026-10-04

Google's Health Connect UI guidance asks you to lead with the user benefit, avoid button labels like "Connect to Health Connect" in favour of verb phrases such as "set up" or "get started", and ask for each permission where it makes sense, such as routes after a workout. When adding data types later, only the new ones should appear on the permissions screen. Your settings should offer a sync toggle and a link to manage access, and if the user cancels the permission request twice in a row, Google says they must re-enable permissions from Health Connect settings.

## HealthKit to Health Connect: the API equivalents, call by call

- Question: HealthKit to Health Connect API equivalents
- HTML: https://aifitnessapi.com/health-connect-api/healthkit-vs-health-connect-api-equivalents
- Markdown: https://aifitnessapi.com/health-connect-api/healthkit-vs-health-connect-api-equivalents.md
- Last reviewed: 2026-10-04

Most HealthKit calls have a direct Health Connect counterpart: HKSampleQuery maps to readRecords, HKStatisticsQuery to aggregate, HKStatisticsCollectionQuery to aggregateGroupByDuration or aggregateGroupByPeriod, HKAnchoredObjectQuery to getChangesToken and getChanges, requestAuthorization to PermissionController's request contract, and save and delete to insertRecords and deleteRecords. HKObserverQuery with background delivery has no equivalent: Google says apps cannot be notified of new data, so Android apps poll, in the background through WorkManager with READ_HEALTH_DATA_IN_BACKGROUND. Paging, token expiry and permission visibility also differ.
