Skip to main content

Health data import

Health import is composed from an authorization provider and a platform-specific sync component. Both are exposed as static members of DataSync:

  • DataSync.AppleHealthAuthorizationProvider
  • DataSync.AppleHealthSync
  • DataSync.AndroidHealthConnectAuthorizationProvider
  • DataSync.AndroidHealthSync
  • DataSync.ManuallyRequestSheet

The sync components use the active OvokClient and patient profile from @ovok/core.

Mapping model​

dataToSync maps an Ovok MeasurementTypeKey to one or more platform type identifiers and an ObservationCode:

const dataToSync = {
bodyWeight: {
typeIdentifiers: [
{
typeIdentifier: "Weight",
code: ObservationCode.BODY_WEIGHT,
},
],
minDate: new Date("2026-01-01T00:00:00.000Z"),
},
};

Use the platform's exact identifier type:

  • HKQuantityTypeIdentifier for HealthKit.
  • RecordType values from react-native-health-connect for Health Connect.

minDate limits the first read. The services also use per-code server watermarks to avoid importing the same history on every run.

Apple HealthKit​

<DataSync.AppleHealthAuthorizationProvider
readIdentifiers={iosReadIdentifiers}
writeIdentifiers={iosWriteIdentifiers}
onAuthorizationStatusChange={setHealthKitStatus}
fallback={<ActivityIndicator />}
>
<DataSync.AppleHealthSync
dataToSync={iosDataToSync}
chunkSize={500}
backgroundDelivery={{ frequency: HKUpdateFrequency.hourly }}
wifiOnly={false}
onProgress={setProgress}
onError={setError}
/>
</DataSync.AppleHealthAuthorizationProvider>

The provider reports unknown, shouldRequest, requesting, ready, or error. notRequestedReadIdentifiers and notRequestedWriteIdentifiers identify individual types whose authorization has not been answered.

By default the provider requests access automatically when needed. Set skipRequest and provide renderManualRequestUI when the app needs to explain the request first. AppleHealthSync filters out read identifiers still pending authorization, so one unchecked type does not block already-authorized types.

backgroundDelivery enables HealthKit observer delivery for the configured types. It requires the HealthKit background entitlement and does not guarantee execution while the phone is locked.

Android Health Connect​

<DataSync.AndroidHealthConnectAuthorizationProvider
readIdentifiers={androidReadIdentifiers}
writeIdentifiers={androidWriteIdentifiers}
backgroundAccess
onAuthorizationStatusChange={setHealthConnectStatus}
fallback={<ActivityIndicator />}
>
<DataSync.AndroidHealthSync
dataToSync={androidDataToSync}
chunkSize={500}
wifiOnly={true}
onProgress={setProgress}
onError={setError}
/>
</DataSync.AndroidHealthConnectAuthorizationProvider>

The provider reports unknown, shouldRequest, requesting, authorized, refused, or error. On resume it re-checks permissions and initialization. backgroundAccess additionally requests the special Health Connect background-read permission used by scheduled imports.

For process-death scheduling, use the headless Health Connect flow instead of trying to render AndroidHealthSync inside a headless task.

Network and progress behavior​

Both platforms watch NetInfo:

  • offline pauses the sync with reason offline;
  • wifiOnly pauses cellular data with reason wifi-only;
  • a connected acceptable network resumes the sync.

chunkSize defaults to 5000 samples. onProgress receives a partial map keyed by MeasurementTypeKey; SyncProgressList renders that map with localized labels. Errors are delivered to onError and should be shown/logged by the host app.

Health import checklist​

  • Use only platform identifiers that the native provider can request.
  • Map every identifier to the correct ObservationCode and unit semantics.
  • Request only the types the screen actually syncs.
  • Handle partial authorization and refusal separately from initialization errors.
  • Test a first sync, an incremental sync, offline pause/resume, and app restart.
  • Configure background entitlements/permissions before testing background delivery.