AnpherosAnpheros PlatformDevelopers

Health Connect to FHIR

Read Android Health Connect data from Fitbit, Garmin, Oura, Withings and Wear OS in Flutter and write it to a FHIR R4 record: permissions, history, Play review.

Health Connect is Android's on-device health store: Samsung Health, Fitbit, Garmin Connect, Oura, Withings and Wear OS apps write into it, and your app reads from it with the person's permission. To put that data in a FHIR record, read daily totals and averages on the phone, send them to your backend, and write each metric as an Observation with a LOINC code and a UCUM unit. This page covers the permissions Android requires, a Flutter example (checked with flutter analyze) that reads Health Connect on Android and Apple Health on iOS with the same code, and the rules for publishing on Google Play.

What reaches Health Connect

Health Connect is built into Android 14 and later and available as an app on older versions. It holds records such as HeartRateRecord, RestingHeartRateRecord, HeartRateVariabilityRmssdRecord, OxygenSaturationRecord, RespiratoryRateRecord, StepsRecord, DistanceRecord, ActiveCaloriesBurnedRecord, SleepSessionRecord, WeightRecord, BloodPressureRecord, BloodGlucoseRecord, BodyTemperatureRecord and ExerciseSessionRecord.

Who writes there, according to each vendor's documentation:

Source What to expect
Fitbit and Pixel Watch The Fitbit app syncs with Health Connect once the person sets it up (Google help)
Garmin Garmin Connect supports Health Connect on Android 14 and later: activity and wellness data such as heart rate and calories (Android Developers, August 2025)
Oura Heart rate, HRV, sleep with stages, steps, distance, calories and workouts (Oura)
Withings Health Mate exchanges activity, weight, sleep and other data through Health Connect (Android Developers blog)
Samsung Health, Galaxy Watch A subset, at Samsung Health's own pace — see Samsung Health to FHIR

Each vendor app must have permission to write to Health Connect, which the person grants in that app or in Health Connect's settings. If a source is missing, that is the first thing to check.

Permissions Android requires

Reading daily values in Flutter

The health package reads Health Connect on Android and Apple Health on iOS behind one API. The example uses version 13.2.1, the one Anpheros Daily ships with:

import 'dart:math' as math;

import 'package:health/health.dart';

/// One day of data from Health Connect (Android) or Apple Health (iOS), ready for your backend.
class DailyValue {
  DailyValue(this.metric, this.day, this.value, {this.min, this.max});
  final String metric; // 'heart_rate', 'steps'
  final String day; // '2026-10-01', the user's local day
  final double value;
  final double? min, max;

  Map<String, Object?> toJson() => {'metric': metric, 'day': day, 'value': value, 'min': min, 'max': max};
}

final health = Health();

Future<List<DailyValue>> collectLastDays({int days = 30}) async {
  await health.configure();
  if (!await health.isHealthConnectAvailable()) {
    await health.installHealthConnect(); // opens the Play Store on Android; always available on iOS
    return [];
  }
  const types = [HealthDataType.HEART_RATE, HealthDataType.STEPS];
  final granted = await health.requestAuthorization(types, permissions: [HealthDataAccess.READ, HealthDataAccess.READ]);
  if (!granted) return [];

  final now = DateTime.now();
  final out = <DailyValue>[];
  for (var i = days - 1; i >= 0; i--) {
    final start = DateTime(now.year, now.month, now.day - i); // local midnight, safe across DST changes
    final end = DateTime(start.year, start.month, start.day + 1);
    final day = start.toIso8601String().substring(0, 10);

    final steps = await health.getTotalStepsInInterval(start, end);
    if (steps != null) out.add(DailyValue('steps', day, steps.toDouble()));

    final samples = await health.getHealthDataFromTypes(types: [HealthDataType.HEART_RATE], startTime: start, endTime: end);
    final bpm = [for (final p in samples) if (p.value is NumericHealthValue) (p.value as NumericHealthValue).numericValue.toDouble()];
    if (bpm.isNotEmpty) {
      out.add(DailyValue('heart_rate', day, bpm.reduce((a, b) => a + b) / bpm.length,
          min: bpm.reduce(math.min), max: bpm.reduce(math.max)));
    }
  }
  return out; // POST these to your backend, which writes them to the FHIR record
}

getTotalStepsInInterval asks Health Connect for its aggregated total, which already resolves overlapping sources (a phone and a watch counting the same walk) according to the data-source priority the person set in Health Connect. Summing raw step records yourself double-counts.

Notes from shipping this in Anpheros Daily:

From Flutter values to FHIR Observations

Send the values to your backend and write one Observation per person, metric and day with a stable identifier, updating it when the same day is sent again. The full mapping table (Health Connect record → LOINC → UCUM), a validated FHIR example and the TypeScript upsert run against the platform are on Wearable data in FHIR.

Publishing on Google Play

Apps that read Health Connect must complete the Health Connect permissions declaration in the Play Console, justify every data type, and have a privacy policy that matches. Requests for data types the app does not visibly use are rejected. Plan for the review: list each type next to the screen that uses it.

Wear OS

On a Wear OS watch, an app can read live sensor data through Health Services (heart rate during a workout, for example). Data the watch's own health app records reaches the phone's Health Connect through the vendor's phone app. For a medical record, reading Health Connect on the phone is usually enough; a watch app is for live features.

Where Anpheros fits

The Anpheros Platform stores the result: the person's FHIR R4 record with each wearable value as an Observation marked as device data, behind consent, provenance and an access log. It does not read Health Connect itself; your Android app does. Anpheros' own app, Anpheros Daily, reads Health Connect on Android (Plus and Max plans) and writes daily summaries to the record.

Frequently asked questions

Does Health Connect have a cloud API?

No. Health Connect stores data on the phone, and only apps on that phone can read it, with the person's permission. To get the data to a server, your app reads it and sends it.

Why can my app only read 30 days of Health Connect data?

Without the READ_HEALTH_DATA_HISTORY permission, Health Connect limits reads to 30 days before the first permission was granted. Request the history permission if you need older data.

Does Garmin sync with Health Connect?

Yes. Google announced in August 2025 that Garmin Connect supports Health Connect on Android 14 and later, for activity and wellness data such as heart rate and calories. Garmin's own scores, such as Body Battery, are not shared.

Can I read Fitbit data without the Fitbit Web API?

On Android, yes: once the person enables Health Connect in the Fitbit app, Fitbit data is available in Health Connect for apps they authorise.

Why does the Health Connect step count differ from my vendor app?

The vendor app may not have exported its latest data yet, may export only some types, or Health Connect may prefer another source for the same period. Check the data sources and their priority in Health Connect's settings.

Related