---
title: "Resting Heart Rate API: How to Read RHR From HealthKit and Health Connect"
canonical: "https://aifitnessapi.com/data/resting-heart-rate-api"
cluster: "Health Data"
primary_query: "resting heart rate api"
last_reviewed: "2026-10-04"
description: "Read resting heart rate from HealthKit, Health Connect and wearable APIs. Apple estimates and rewrites it during the day; Android stores what apps write."
publisher: "AIFitnessAPI — independent, not sponsored"
cite_as: "\"Resting Heart Rate API: How to Read RHR From HealthKit and Health Connect\", AIFitnessAPI, https://aifitnessapi.com/data/resting-heart-rate-api"
---

# Resting Heart Rate API: How to Read RHR From HealthKit and Health Connect

> Resting heart rate reaches an app from the two on-device stores or from a wearable's cloud API, and the two stores define it differently. Apple HealthKit documents HKQuantityTypeIdentifier.restingHeartRate as an estimate of the user's lowest heart rate during periods of rest, which Apple Watch computes from sedentary heart rate samples through the day and may delete and replace with better estimates for the current or previous day. Android Health Connect documents RestingHeartRateRecord as a single instantaneous measurement holding only beatsPerMinute, time and metadata, with no statement of how a value is produced, so any app holding the write permission can put a number there. On our pages, WHOOP exposes resting heart rate under its recovery scope and Fitbit's heart rate time series includes a resting value; Strava has none, and Garmin, Oura and Polar are not documented here for this field.

- Canonical: https://aifitnessapi.com/data/resting-heart-rate-api
- Last reviewed: 2026-10-04
- Publisher: AIFitnessAPI (https://aifitnessapi.com) — independent, not sponsored
- Cite as: "Resting Heart Rate API: How to Read RHR From HealthKit and Health Connect", AIFitnessAPI, https://aifitnessapi.com/data/resting-heart-rate-api

---

Resting heart rate looks like the easiest field in a health store: one small integer, roughly one per day, with the same name on both platforms. It is also the clearest example of the two platforms agreeing on a label and disagreeing on what the label means. HealthKit treats it as something the system works out and revises. Health Connect treats it as something an app asserts. Build a trend line without knowing which store you are reading and you will either show users values Apple has since withdrawn, or present an unverified integer as though a platform measured it.

## HealthKit: an estimate the system keeps revising

Apple documents `HKQuantityTypeIdentifier.restingHeartRate` as "A quantity sample type that measures the user's resting heart rate," available from iOS 11.0 and watchOS 4.0, using count/time units and measuring discrete values. The discussion is unusually candid for a type page and worth quoting closely.

First, on what the number is: Apple says resting heart rate "is an estimation of the user's lowest heart rate during periods of rest, and is intended to be used as a medically relevant metric." So on iOS the value is an estimate by Apple's own description, even though the parent metric, heart rate, is measured.

Second, on how it differs from a quiet moment: "A resting heart rate sample is different than a sedentary heart rate sample," meaning an ordinary `heartRate` sample whose motion context is `HKHeartRateMotionContext.sedentary`. Apple's example is the user who finishes a high-intensity workout and sits down: the next sample may be marked sedentary, "but it is still much higher than the user's actual resting heart rate." To get a better answer, "the system estimates the resting heart rate by analyzing sedentary heart rate samples throughout the day."

Third, and this is the sentence that breaks naive sync code: "Because the resting heart rate estimates become more accurate as the day progresses, the system may delete earlier samples and replace them with better estimates. Apple Watch replaces only the samples written by the watch for the current or previous day."

The motion context that feeds this is itself documented on the `heartRate` page. Apple Watch sets `HKHeartRateMotionContext.sedentary` when the user has been still for at least five minutes before the sample and `.active` when the user is in motion; not every sample carries the key, and samples from a first-generation Apple Watch or watchOS 3 and earlier never do, so Apple says to treat those as `.notSet`. Any app can write heart rate samples with or without the key. Our [HealthKit vital signs reference](/healthkit/vital-signs#id-restingheartrate) lists the identifier beside the rest of the heart group. The group's three event types, for high heart rate, low heart rate and irregular rhythm, date from iOS 12.2; [the HealthKit types introduced in iOS 12](/healthkit-versions/ios-12) lists them.

## Health Connect: an integer somebody wrote

Google documents `RestingHeartRateRecord` as a class that "Captures the user's resting heart rate. Each record represents a single instantaneous measurement." It sits in the Vitals category as an instantaneous record, added in connect-client 1.1.0, with `beatsPerMinute`, `metadata` and `time` as its mandatory fields and a nullable `zoneOffset`. Reads and writes are gated on `android.permission.health.READ_RESTING_HEART_RATE` and `android.permission.health.WRITE_RESTING_HEART_RATE`.

The value is a `Long`, documented as "Heart beats per minute. Required field. Validation range: 1-300." That is all the reference says about the number. There is no description of how a resting value is derived, no reference to `HeartRateRecord`, and no motion context. Google's vitals guide adds only that the record "Represents a single measurement of resting heart rate." Our generated [RestingHeartRateRecord reference](/health-connect/resting-heart-rate-record) carries the full field list and the aggregate metrics.

Read that silence literally. Health Connect does not say it produces resting heart rate for you, so the presence of a record means some app with the write permission, a watch vendor's companion app for example, decided on a number and stored it. Whether that number came from an overnight minimum, a morning reading or a rolling estimate is the writing app's business, and the only place it might say so is `metadata`. Our page on [recording method metadata](/health-connect-api/metadata-recording-method) covers what that field can and cannot tell you.

## Where you can get it

| Source | What it gives you | How you access it | Verified from |
|---|---|---|---|
| Apple HealthKit | `HKQuantityTypeIdentifier.restingHeartRate`: a system-estimated value, revised and rewritten for the current and previous day | On-device read with per-type authorization; no cloud pull | Apple's HealthKit documentation for the identifier, `heartRate` and `HKHeartRateMotionContext`, fetched 2026-10-04 |
| Android Health Connect | `RestingHeartRateRecord`: one integer `beatsPerMinute` per record, written by whichever app holds the permission | On-device read/write via the Health Connect client and the resting-heart-rate permissions | Health Connect data types page and the Kotlin reference, fetched 2026-10-04 |
| Health Connect aggregates | `BPM_AVG`, `BPM_MAX`, `BPM_MIN`, all `Long` | An aggregate request against the same record type | Kotlin reference and data types page, fetched 2026-10-04 |
| WHOOP API v2 | Resting heart rate inside recovery data, under the `read:recovery` scope | Cloud OAuth 2.0 | Documented on our [WHOOP API integration guide](/integrate/whoop-api) |
| Fitbit Web API | A resting value in the heart rate time series; intraday detail needs separate approval | Cloud OAuth 2.0 with the `heartrate` scope | Documented on our [heart rate API](/data/heart-rate-api) page, marked verify |
| Oura API v2 | A resting-heart-rate trend as a Readiness Score contributor, not a standalone series on our pages | Cloud OAuth 2.0 | Documented on our [Oura vs WHOOP](/compare/oura-vs-whoop) comparison |
| Strava API | None; heart rate is a per-workout stream only | Cloud OAuth 2.0 | Documented on our heart rate API page |
| Garmin, Polar | Not documented on our pages for this field | Cloud OAuth where a field exists at all | Verify in each vendor's live data dictionary |
| Aggregators (Terra, Junction, Rook) | Whatever the underlying source supplies, under one normalized schema | One cloud API plus webhooks | Not documented on our pages for this field; verify |

## Syncing it without keeping stale values

On iOS the deletion behaviour decides your query class. A one-shot sample query copies whatever estimate exists at that moment, and if Apple later replaces it your copy is now wrong with no signal that it is. [HKAnchoredObjectQuery](/healthkit-queries/hkanchoredobjectquery) is the class that reports deleted objects as well as new samples, so it is the one to use; treat today's and yesterday's resting values as provisional and apply the deletions it hands you. Values older than that are, by Apple's statement, no longer rewritten by the watch, though another app could still delete its own.

On Android there is no documented rewrite, but there is also no documented author. If you want one number per day, decide whether that is the latest record, the minimum, or `BPM_AVG` over the day, and say which in the UI. Our [aggregate request](/health-connect-api/aggregate-request) page covers the mechanics; the record's own `zoneOffset` is nullable, and the reference says queries with user-experienced time filters assume the current system offset when it is absent, so a traveller's morning value can land on the wrong local day.

## The traps

- **Two definitions, one label.** HealthKit's value is an estimate the system computes from sedentary samples and revises. Health Connect's is a number an app wrote, with no derivation documented. Do not normalise them into one field without recording which store it came from.
- **Yesterday can change.** Apple documents replacement of watch-written samples for the current or previous day. Any "resting heart rate this morning" notification you send from the first value of the day is quoting a draft.
- **Sedentary is not resting.** A `heartRate` sample with `.sedentary` motion context is the raw material, not the answer. Apple's post-workout example shows how far apart the two can be.
- **Integer versus double.** `beatsPerMinute` is a `Long` with a documented range of 1 to 300; `restingHeartRate` is a count/time quantity whose `HKUnit` you choose. Rounding and range filtering are yours to do, and a zero on Android is outside the documented range rather than a quiet null.
- **No value without a writer.** On Android, a user whose watch vendor does not write `RestingHeartRateRecord` has no resting heart rate at all, however many `HeartRateRecord` samples exist. Design the empty state before the chart.
- **History and background need their own permissions.** Reading more than 30 days back requires [READ_HEALTH_DATA_HISTORY](/health-connect-api/read-health-data-history), declared separately from the data-type permission, and background reads need their own grant too.

## Keep the claims where the docs put them

Apple's description, "intended to be used as a medically relevant metric," is a statement about the type, not a licence for your copy. A trend line labelled as the platform's estimate stays on the wellness side; thresholds, alerts and interpretation move the product toward the line our [FDA fitness app regulation](/compliance/fda-fitness-app-regulation) page describes, and which store the number came from does not change that. Nothing here is medical or legal advice.

## Before you ship

Re-verify the identifier, the record's fields and validation range, and the permission strings against the live Apple and Google references, since all of them move. On iOS, sync with an anchored query and honour deletions. On Android, record the writing app from `metadata` and name it in the UI. For any vendor field, confirm the window the value is computed over in that vendor's own data dictionary rather than inferring it from the name.

## Sources

- [developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/restingheartrate](https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/restingheartrate) — estimate of the lowest heart rate during rest; sedentary-sample example; system may delete and replace samples; watch replaces only current or previous day; iOS 11.0, watchOS 4.0; count/time, discrete (checked 2026-10-04)
- [developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/heartrate](https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/heartrate) — motion context stored under HKMetadataKeyHeartRateMotionContext; not all samples carry it; treat missing as notSet; other apps may write with or without it (checked 2026-10-04)
- [developer.apple.com/documentation/healthkit/hkheartratemotioncontext](https://developer.apple.com/documentation/healthkit/hkheartratemotioncontext) — active, notSet, sedentary; sedentary = still for at least 5 minutes prior to the sample (checked 2026-10-04)
- [developer.android.com/reference/kotlin/androidx/health/connect/client/records/RestingHeartRateRecord](https://developer.android.com/reference/kotlin/androidx/health/connect/client/records/RestingHeartRateRecord) — single instantaneous measurement; beatsPerMinute Long, required, validation range 1-300; zoneOffset nullable; BPM_AVG, BPM_MAX, BPM_MIN; added in 1.1.0 (checked 2026-10-04)
- [developer.android.com/health-and-fitness/health-connect/data-types](https://developer.android.com/health-and-fitness/health-connect/data-types) — Resting heart rate row: Vitals, Instantaneous, mandatory beatsPerMinute/metadata/time, READ_RESTING_HEART_RATE and WRITE_RESTING_HEART_RATE, aggregates BPM_AVG/MAX/MIN (checked 2026-10-04)
- [developer.android.com/health-and-fitness/health-connect/experiences/vitals](https://developer.android.com/health-and-fitness/health-connect/experiences/vitals) — RestingHeartRateRecord described as a single measurement of resting heart rate; no derivation described (checked 2026-10-04)

## FAQ

### Why do resting heart rate samples disappear from HealthKit during the day?

Because Apple documents that behaviour. The restingHeartRate discussion states that resting heart rate estimates become more accurate as the day progresses, so the system may delete earlier samples and replace them with better estimates, and that Apple Watch replaces only the samples written by the watch for the current or previous day. A sync that copied this morning's value and never looks back will keep a number Apple itself discarded. Use HKAnchoredObjectQuery, which reports deleted objects, and treat today's and yesterday's values as provisional.

[Permalink](https://aifitnessapi.com/data/resting-heart-rate-api#faq-1)

### What is the difference between a resting heart rate sample and a sedentary heart rate sample in HealthKit?

Apple draws the line explicitly. A sedentary sample is an ordinary heartRate sample whose HKMetadataKeyHeartRateMotionContext metadata is HKHeartRateMotionContext.sedentary, which Apple defines as the user having been still for at least five minutes before the sample. A resting heart rate sample is a separate restingHeartRate quantity type that the system estimates by analysing sedentary samples across the day. Apple's own example is a user who sits down after a hard workout: the next sample may be marked sedentary while still being far above their true resting rate.

[Permalink](https://aifitnessapi.com/data/resting-heart-rate-api#faq-2)

### Does Health Connect compute resting heart rate from HeartRateRecord data?

Nothing in Google's documentation says it does. The RestingHeartRateRecord reference describes the class as capturing the user's resting heart rate, where each record represents a single instantaneous measurement, and lists beatsPerMinute, time and metadata as its mandatory fields. There is no derivation described and no link to HeartRateRecord. What Health Connect does provide is aggregation over records that already exist: BPM_AVG, BPM_MAX and BPM_MIN, all typed as Long. If no app on the device writes a RestingHeartRateRecord, an aggregate query simply has nothing to summarise.

[Permalink](https://aifitnessapi.com/data/resting-heart-rate-api#faq-3)

### What unit and type does RestingHeartRateRecord use for the value?

The Kotlin reference types beatsPerMinute as a Long, documented as heart beats per minute, a required field with a validation range of 1 to 300. That is an integer, where HealthKit's restingHeartRate uses count over time units and lets you choose the HKUnit on read. Converting a HealthKit double into a Health Connect Long therefore rounds, and a value of zero or anything above 300 falls outside the documented range on Android, so filter and round deliberately rather than letting a cross-platform layer do it for you.

[Permalink](https://aifitnessapi.com/data/resting-heart-rate-api#faq-4)

### Which wearable cloud APIs give me a daily resting heart rate?

On our pages, WHOOP's read:recovery scope grants recovery data that includes HRV and resting heart rate, and Fitbit's heart rate time series includes a resting value, with intraday detail needing separate approval. Oura reports a resting-heart-rate trend as a contributor to its Readiness Score rather than as a standalone series on the pages we document. Strava exposes heart rate only as a per-workout stream, so it has no resting value. Garmin and Polar are not documented here for this field, so verify them in each vendor's live data dictionary.

[Permalink](https://aifitnessapi.com/data/resting-heart-rate-api#faq-5)
