Skip to content
AF
healthkit
7 min readAIFitnessAPI

HRV: Apple Watch SDNN vs Health Connect RMSSD

Apple Watch records HRV into HealthKit as SDNN; Health Connect stores RMSSD. Different statistics, no conversion factor, one chart that quietly misleads.

healthkithealth-connectdataarchitecture

This site's cross-platform matrix verifies 10 health metrics against both Apple's and Google's own documentation. Most of the disagreements between the two platforms are about packaging: how many records a concept is split across, what the enum values are called, which permission gates it. Heart rate variability is the one where the platforms disagree about what the number is.

Apple Watch records SDNN into HealthKit. Health Connect stores RMSSD. They are different computations over the same underlying beat-to-beat intervals, and the matrix records them as not interconvertible.

Update, October 2, 2026. iOS 27 added a second HealthKit HRV identifier, HKQuantityTypeIdentifier.heartRateVariabilityRMSSD. Apple's documentation lists it with a declaration and nothing else: no abstract, no discussion. It does not say what the type measures, how it is computed, or whether Apple Watch writes it, while Apple's page for heartRateVariabilitySDNN still says HealthKit uses SDNN and that the system records those samples on Apple Watch. Until Apple documents the new type, the rest of this post describes the HRV data iPhone users actually have. The post was first published as "HRV Is SDNN on iOS and RMSSD on Android" and was retitled because iOS now has an RMSSD identifier.

AppleHealth Connect
TypeHKQuantityTypeIdentifier.heartRateVariabilitySDNNHeartRateVariabilityRmssdRecord
Statistic named in the typeSDNNRMSSD
Derived fromIntervals between heartbeatsIntervals between heartbeats
Convertible to the otherNoNo

Both platforms even put the statistic in the type name, which is the strongest hint either vendor gives you that the choice is not incidental. Apple did not name it heartRateVariability. Google did not name it HeartRateVariabilityRecord.

Of the 10 metrics in the matrix, this is the only one where the disagreement survives every layer of engineering you can throw at it. You can map two activity-type taxonomies onto each other. You can de-duplicate a phone and a watch that both wrote steps. You can decide whether calories mean active or total and enforce it. You cannot make an SDNN sample into an RMSSD sample, so this is the one row of the matrix where a naming decision in your schema is permanent.

This is not a units problem#

Unit conversion works when two systems measure the same quantity on different scales. Metres and feet. Kilojoules and kilocalories. You multiply, and nothing is lost.

SDNN and RMSSD are not two scales for one quantity. They are two different summaries computed from the same raw material. Multiplying one by a constant does not produce the other, and there is no constant to look for. Whatever relationship exists between them in a given population is a statistical observation about that population, not a transformation you can apply to one person's Tuesday.

So the mistake is not choosing the wrong factor. The mistake is believing a factor is the kind of thing that would fix this.

What actually breaks#

The single chart. A user on iPhone for a year, then on Android, gets one continuous line built from two different statistics. The step at the switchover is an artifact of your schema, and it will look to them like a physiological event.

The baseline. Recovery scores, readiness scores and "your HRV is below normal" notifications all work by comparing today against a personal baseline. If the baseline was accumulated under one statistic and today's sample is the other, the comparison is meaningless and the notification is worse than nothing. Anything that tells a user something changed about their body when the only thing that changed was their phone is a trust problem, not a rendering bug.

Cohort analytics. A mean HRV across a mixed-platform user base is an average of two different measurements. It will move whenever your platform mix moves, which is to say whenever marketing does anything. Any longitudinal claim you make about your user base — that HRV improved after a programme, that a cohort recovered faster — inherits that instability, and you will not notice, because the number looks like a number.

Your aggregator, possibly. If you read health data through an aggregator, the vendor has already made this decision for you and may not have surfaced it. Ask them directly: what does your hrv field contain for an Apple user, what does it contain for an Android user, and does the payload tell me which? If the answer is one field with no discriminator, the problem has not gone away — it has been hidden behind a normalised-looking schema.

The honest options#

OptionWhat you storeWhat the user seesWhen it fits
Label the sourceSample plus the statistic and the platform it came fromTwo series, visibly distinctAlmost always; this is the floor
Separate baselinesEverything, partitioned by statisticOne number at a time, reset on platform changeProducts with a readiness or recovery score
Derive your ownBeat-to-beat intervals you ingest yourself, plus one statistic you computeOne continuous seriesOnly if you already have interval-level data

Label the source. Add a column recording which statistic each row holds and which platform wrote it. This is not a nice-to-have, it is the minimum condition for ever fixing the problem later, and backfilling it is cheap now and expensive after a year of rows. If you do nothing else from this post, do this.

Keep baselines per platform. A baseline is only valid inside one statistic. When a user's platform changes, start a new baseline and say so in the UI rather than pretending continuity. Treat it the same way you would treat any recomputation of a derived metric: versioned, dated, and visible.

Derive one definition yourself, but only where you actually hold the input. That means your app is already ingesting interval-level data from a chest strap or a device SDK rather than reading a platform's pre-computed summary. Check what your hardware actually exposes before planning around this — see Bluetooth heart rate monitors. If you are reading only the platforms' HRV types — heartRateVariabilitySDNN and Health Connect's HeartRateVariabilityRmssdRecord — this option is not available to you, because each holds a pre-computed summary. HealthKit does document a separate beat-level type, HKHeartbeatSeriesSample ("a sample that represents a series of heartbeats", read with HKHeartbeatSeriesQuery), so on iOS check whether your users actually have such samples before ruling this out.

What not to do#

  • Do not apply a conversion factor. There isn't one.
  • Do not average SDNN and RMSSD samples into one figure, per user or per cohort.
  • Do not name the field hrv with no qualifier. The name is the bug: it is what lets a well-meaning engineer two years from now write a query that mixes them.
  • Do not build a cross-platform leaderboard or social comparison on HRV.
  • Do not describe either number to a user as their heart rate variability without saying which measure it is. What HRV represents, and what it does not, is covered in what is HRV.

Do this week#

  1. Grep your schema for hrv. If the column has no companion column naming the statistic, that is your first migration.
  2. Backfill the statistic from the source type — heartRateVariabilitySDNN, HeartRateVariabilityRmssdRecord, or on iOS 27 heartRateVariabilityRMSSD — rather than from the platform alone, since iOS now has an identifier for each statistic. That inference is only safe to make while you still have the provenance.
  3. Break the chart series wherever the statistic changes, and label both.
  4. Find every threshold, alert and score that reads the field and confirm what it does the day a user switches phones.
  5. Read the rest of the platform differences in the HealthKit and Health Connect type reference, and the implementation detail for this metric on the HRV API page.

Normalisation across platforms is usually a mapping exercise. This one is not, and the cost of treating it as one is a number your users believe.

Frequently asked questions

Can you convert SDNN to RMSSD?
Not for the purposes of a product. The heart rate variability Apple Watch records into HealthKit is SDNN and Health Connect exposes RMSSD, and this site's cross-platform matrix records them as different measures that are not interconvertible. Treat them as two separate fields with two separate baselines rather than looking for a factor to multiply by.
What does Health Connect store for heart rate variability?
Health Connect exposes HeartRateVariabilityRmssdRecord, which Google documents as heart rate variability measured by the root mean square of successive differences between normal heartbeats, in milliseconds. Its counterpart in this site's matrix is Apple's heartRateVariabilitySDNN, the type Apple Watch records into. Both are summary statistics derived from the intervals between heartbeats, but they are different summaries, so a field called simply hrv in your schema means something different depending on which platform the sample came from.
Why did a user's HRV change when they switched from iPhone to Android?
Most likely because the stored statistic changed, not because anything about the user did. Your app started reading a different computation under the same field name. If your product shows a baseline, a trend line, or a recovery score built on heart rate variability, a platform switch will move it for reasons that have nothing to do with the person.
Does HealthKit have an RMSSD type?
Since iOS 27 it has an identifier for one, HKQuantityTypeIdentifier.heartRateVariabilityRMSSD. As of October 2, 2026, Apple's documentation lists it with a declaration only, no abstract and no discussion, so what it measures, how it is computed and whether Apple Watch writes it are not stated. Apple's page for heartRateVariabilitySDNN still says HealthKit uses SDNN and that the system records those samples on Apple Watch.

Read next

Last verified . Figures come from this site’s own published datasets; see how we verify.