{
  "name": "Health Data Type Matrix 2026 (HealthKit ↔ Health Connect)",
  "version": "2026.1",
  "publisher": "AIFitnessAPI (aifitnessapi.com)",
  "license": "CC BY 4.0",
  "methodology": "One row per common health metric, pairing Apple's HealthKit type identifier with Android Health Connect's record type. Every identifier was confirmed against Apple's and Google's own developer documentation (HKQuantityTypeIdentifier, HKCategoryTypeIdentifier, and the Health Connect data-types guide) before publication; the full source list and the platform-level notes are on https://aifitnessapi.com/matrix. Scope is deliberately narrow — only the two on-device platform stores, because those are the cells we could verify. watchOut is null where the module records no cross-platform gotcha; it is never a guess.",
  "generatedFrom": "src/data/matrix.ts (generated by scripts/build-datasets.mjs)",
  "fields": {
    "id": "Stable metric slug used across aifitnessapi.com",
    "label": "Human-readable metric name",
    "appleHealthKit": "Apple HealthKit type identifier(s) for this metric",
    "androidHealthConnect": "Android Health Connect record type(s) for this metric",
    "watchOut": "The cross-platform gotcha, where one exists (null = none recorded)",
    "source": "aifitnessapi.com page carrying the verified claims for this metric"
  },
  "stats": {
    "totalItems": 10,
    "platforms": [
      "Apple HealthKit",
      "Android Health Connect"
    ],
    "rowsWithBothIdentifiers": 10,
    "rowsWithWatchOut": 10,
    "rowsWithMultipleAppleIdentifiers": 5,
    "rowsWithMultipleHealthConnectIdentifiers": 5
  },
  "items": [
    {
      "id": "heart-rate",
      "label": "Heart rate",
      "appleHealthKit": "HKQuantityTypeIdentifier.heartRate, .restingHeartRate",
      "androidHealthConnect": "HeartRateRecord, RestingHeartRateRecord",
      "watchOut": "Both expose samples plus a separate resting value — don't derive resting yourself.",
      "source": "https://aifitnessapi.com/data/heart-rate-api"
    },
    {
      "id": "hrv",
      "label": "HRV",
      "appleHealthKit": "HKQuantityTypeIdentifier.heartRateVariabilitySDNN",
      "androidHealthConnect": "HeartRateVariabilityRmssdRecord",
      "watchOut": "The big one: Apple stores SDNN, Health Connect stores RMSSD. They are different measures and are not interconvertible — do not normalize one into the other.",
      "source": "https://aifitnessapi.com/data/hrv-api"
    },
    {
      "id": "vo2-max",
      "label": "VO2 max",
      "appleHealthKit": "HKQuantityTypeIdentifier.vo2Max",
      "androidHealthConnect": "Vo2MaxRecord",
      "watchOut": "An estimate on both platforms, not a lab measurement. Health Connect tags a measurement method.",
      "source": "https://aifitnessapi.com/data/vo2-max-api"
    },
    {
      "id": "blood-oxygen",
      "label": "Blood oxygen",
      "appleHealthKit": "HKQuantityTypeIdentifier.oxygenSaturation",
      "androidHealthConnect": "OxygenSaturationRecord",
      "watchOut": "The type existing doesn't mean data exists — SpO2 is device-gated, and Apple Watch availability in the US has been subject to litigation. Verify current status.",
      "source": "https://aifitnessapi.com/data/blood-oxygen-api"
    },
    {
      "id": "sleep",
      "label": "Sleep",
      "appleHealthKit": "HKCategoryTypeIdentifier.sleepAnalysis (values: inBed, awake, asleepCore, asleepDeep, asleepREM, asleepUnspecified)",
      "androidHealthConnect": "SleepSessionRecord (carries stages)",
      "watchOut": "Stage vocabularies differ and stages are estimated, not measured. Apple's .asleep is deprecated in favour of the specific stages.",
      "source": "https://aifitnessapi.com/data/sleep-tracking-api"
    },
    {
      "id": "steps",
      "label": "Steps",
      "appleHealthKit": "HKQuantityTypeIdentifier.stepCount (CMPedometer for live counts)",
      "androidHealthConnect": "StepsRecord, StepsCadenceRecord",
      "watchOut": "De-duplicate: phone and watch both write steps. On Android, from the June 2026 update on-device steps are attributed to a per-device Synthetic Package Name — read it via getCurrentDeviceDataSource(), never hardcode it.",
      "source": "https://aifitnessapi.com/data/step-counting-api"
    },
    {
      "id": "workouts",
      "label": "Workouts",
      "appleHealthKit": "HKWorkout (HKWorkoutBuilder)",
      "androidHealthConnect": "ExerciseSessionRecord, PlannedExerciseSessionRecord",
      "watchOut": "Activity-type taxonomies differ between platforms — map them explicitly rather than by name.",
      "source": "https://aifitnessapi.com/data/workout-detection-api"
    },
    {
      "id": "gps-route",
      "label": "GPS route",
      "appleHealthKit": "HKWorkoutRoute (array of CLLocation), HKWorkoutRouteQuery",
      "androidHealthConnect": "ExerciseRoute with ExerciseRoute.Location",
      "watchOut": "Health Connect gates routes behind their own permission (READ_EXERCISE_ROUTES) and restricts background reads of other apps' routes.",
      "source": "https://aifitnessapi.com/data/gps-activity-api"
    },
    {
      "id": "calories",
      "label": "Calories",
      "appleHealthKit": "HKQuantityTypeIdentifier.activeEnergyBurned, .basalEnergyBurned",
      "androidHealthConnect": "ActiveCaloriesBurnedRecord, TotalCaloriesBurnedRecord",
      "watchOut": "Modelled estimates, not measurements. Note the asymmetry: Apple splits active/basal, Android offers active and total — don't add active to total.",
      "source": "https://aifitnessapi.com/data/calorie-tracking-api"
    },
    {
      "id": "body-composition",
      "label": "Body composition",
      "appleHealthKit": "HKQuantityTypeIdentifier.bodyMass, .bodyFatPercentage, .leanBodyMass, .bodyMassIndex",
      "androidHealthConnect": "WeightRecord, BodyFatRecord, LeanBodyMassRecord, BoneMassRecord, BodyWaterMassRecord, BasalMetabolicRateRecord",
      "watchOut": "The store holds it, but something has to write it — usually a smart scale or manual entry. Body fat is a bioimpedance estimate.",
      "source": "https://aifitnessapi.com/data/body-composition-api"
    }
  ]
}