Resting Heart Rate API: How to Read RHR From HealthKit and Health Connect
Last verified October 4, 2026 · 8 min read
Sources checked (6) · October 4, 2026
- 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
- 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
- developer.apple.com/documentation/healthkit/hkheartratemotioncontext — active, notSet, sedentary; sedentary = still for at least 5 minutes prior to the sample
- 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
- 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
- developer.android.com/health-and-fitness/health-connect/experiences/vitals — RestingHeartRateRecord described as a single measurement of resting heart rate; no derivation described
Covered here:Health ConnectHealthKitWHOOPOuraFitbitGarmin
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 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 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 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 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 |
| 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 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 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 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 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
heartRatesample with.sedentarymotion context is the raw material, not the answer. Apple's post-workout example shows how far apart the two can be. - Integer versus double.
beatsPerMinuteis aLongwith a documented range of 1 to 300;restingHeartRateis a count/time quantity whoseHKUnityou 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
RestingHeartRateRecordhas no resting heart rate at all, however manyHeartRateRecordsamples 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, 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 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.
Resting heart rate, by platform
Each type links its reference page on this site. The quote is the platform's own description of the type, copied from the generated reference data, and it is the reason the type is listed: nothing here is paired by name. A platform with nothing listed has no type with a page here whose description names this metric.
Google Health API · read 2026-10-17
- daily-resting-heart-rate — Daily record · operations: list, reconcile · webhook support
“Measures the daily resting heart rate for a user, calculated using the all day heart rate measurements.” — Google
Apple HealthKit · read 2026-10-02
- restingHeartRate — discrete values · count/time units · iOS 11.0+
“A quantity sample type that measures the user’s resting heart rate.” — Apple
Android Health Connect · read 2026-10-03
- RestingHeartRateRecord — Instantaneous record · Vitals category · aggregates: BPM_AVG, BPM_MAX, BPM_MIN
“Captures the user's resting heart rate.” — Google
Wear OS Health Services · read 2026-10-04
Nothing listed.
Bluetooth GATT · read 2026-10-17
Nothing listed.
Frequently asked questions
- 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.
- 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.
- 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.
- 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.
- 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.
Keep reading
Elsewhere on the site
Pages that share this one’s concepts and sources, from other sections.
Next steps
Was this page useful?
Independent comparison, last reviewed October 4, 2026. Pricing, rate limits, and feature availability change often — confirm current details in each provider’s official documentation before you commit. Product and company names are trademarks of their respective owners; AIFitnessAPI is not affiliated with, endorsed by, or sponsored by any product listed here.
← All health data · by AIFitnessAPI