Enable Health Data Collection

Overview

Sahha requires device data such as steps, sleep, heart rate, and other health signals in order to analyse health. This guide shows you how to configure and manage device sensors, request the right permissions, check collection status, and recover from incomplete setup.

The Sahha SDK acts as a bridge between your app and the device's health data sources. It simplifies permission handling, background collection, and the process of connecting Apple Health and Health Connect data to Sahha.

This page focuses on the sensor and permission part of the integration. Before requesting health access, make sure you have already completed project setup, SDK configuration, and user authentication.


Before you request permissions

Only call enableSensors() after the following are complete:

  • The SDK has been configured
  • The correct user profile has been authenticated
  • Your app has explained what access is being requested and why

Project prerequisites

Make sure the platform setup work is already complete before you start requesting sensors:

  • iOS: HealthKit capability, HealthKit Background Delivery, Background Modes, and usage descriptions must be configured in Xcode.
  • Android: Matching uses-permission entries must be declared in AndroidManifest.xml, and devices running Android 9 through Android 13 need the Health Connect app installed.
  • Android native steps and sleep: if your app relies on native steps or sleep synchronisation, include WRITE_STEPS and WRITE_SLEEP as well as the read permissions.

Complete setup first

If project capabilities, manifest permissions, or usage descriptions are missing, enableSensors() and getSensorStatus() may not behave as expected and data collection may fail.

Review the platform setup guides before continuing:


Sensor Settings

You must specify which sensors the Sahha SDK should use. We recommend asking the user for permission to access only the sensors that your app actually needs. Requesting fewer, more relevant permissions usually improves opt-in rates and helps with App Store and Play Store review.

Choose which sensors to request user permission for

  1. Specify an array of sensors to request permission for - ONLY THOSE SENSORS will be requested.
  2. If you wish to add more sensors in future, append the new sensors to the array and follow the guide for prompting the user if sensors are not enabled.
  3. If you set the Sensor Settings value to an empty array [], you will receive an ERROR.

SahhaSensor

Each SahhaSensor has a unique identifier which can be used with multiple SDK methods. A complete list is available below.

You can check the official documentation for the matching Android and iOS sensor to see platform-specific details.

Some sensors are not available on all platforms.

SahhaSensor Requires Wearable Android Sensor iOS Sensor
gender No Sensor Not Available biologicalSex
date_of_birth No Sensor Not Available dateOfBirth
sleep No SleepSessionRecord sleepAnalysis
steps No StepsRecord stepCount
floors_climbed No FloorsClimbedRecord flightsClimbed
heart_rate Yes HeartRateRecord heartRate
resting_heart_rate Yes RestingHeartRateRecord restingHeartRate
walking_heart_rate_average Yes Sensor Not Available walkingHeartRateAverage
heart_rate_variability_rmssd Yes HeartRateVariabilityRmssdRecord Sensor Not Available
heart_rate_variability_sdnn Yes Sensor Not Available heartRateVariabilitySDNN
blood_pressure_systolic Yes BloodPressureRecord bloodPressureSystolic
blood_pressure_diastolic Yes BloodPressureRecord bloodPressureDiastolic
blood_glucose Yes BloodGlucoseRecord bloodGlucose
vo2_max Yes Vo2MaxRecord vo2Max
oxygen_saturation Yes OxygenSaturationRecord oxygenSaturation
respiratory_rate Yes RespiratoryRateRecord respiratoryRate
active_energy_burned No ActiveCaloriesBurnedRecord activeEnergyBurned
basal_energy_burned No Sensor Not Available basalEnergyBurned
total_energy_burned No TotalCaloriesBurnedRecord Sensor Not Available
basal_metabolic_rate No BasalMetabolicRateRecord Sensor Not Available
time_in_daylight No Sensor Not Available timeInDaylight
body_temperature No BodyTemperatureRecord bodyTemperature
basal_body_temperature Yes BasalBodyTemperatureRecord basalBodyTemperature
sleeping_wrist_temperature Yes Sensor Not Available appleSleepingWristTemperature
height No HeightRecord height
weight No WeightRecord bodyMass
lean_body_mass Yes LeanBodyMassRecord leanBodyMass
body_mass_index No Sensor Not Available bodyMassIndex
body_fat Yes BodyFatRecord bodyFatPercentage
body_water_mass No BodyWaterMassRecord Sensor Not Available
bone_mass No BoneMassRecord Sensor Not Available
waist_circumference No Sensor Not Available waistCircumference
stand_time No Sensor Not Available appleStandTime
move_time No Sensor Not Available appleMoveTime
exercise_time No Sensor Not Available appleExerciseTime
activity_summary No Sensor Not Available activitySummary
device_lock No devicelock Sensor Not Available
exercise No ExerciseSessionRecord workout
energy_consumed No NutritionRecord dietaryEnergyConsumed

public enum SahhaSensor: String, CaseIterable {
case gender
case date_of_birth
case sleep
case steps
case floors_climbed
case heart_rate
case resting_heart_rate
case walking_heart_rate_average
case heart_rate_variability_sdnn
case heart_rate_variability_rmssd
case blood_pressure_systolic
case blood_pressure_diastolic
case blood_glucose
case vo2_max
case oxygen_saturation
case respiratory_rate
case active_energy_burned
case basal_energy_burned
case total_energy_burned
case basal_metabolic_rate
case time_in_daylight
case body_temperature
case basal_body_temperature
case sleeping_wrist_temperature
case height
case weight
case lean_body_mass
case body_mass_index
case body_fat
case body_water_mass
case bone_mass
case waist_circumference
case stand_time
case move_time
case exercise_time
case activity_summary
case device_lock
case exercise
case energy_consumed
}

(Android) Uses Permission - IMPORTANT INFO

Specifying sensors for Android

For every sensor you specify in getSensorStatus() or enableSensors(), you need matching uses-permission values in your AndroidManifest.xml.

View the Android Platform Setup guide .

If the values do not match, you are likely to receive build errors and risk your app being rejected on the Google Play Store.

Also note:

  • SahhaSensor.device_lock does not require any AndroidManifest.xml permission declarations.
  • If you rely on native steps and sleep synchronisation, include WRITE_STEPS and WRITE_SLEEP in addition to the read permissions.

Example: Android manifest for steps and sleep

<manifest ...>
<!-- Read permissions -->
<uses-permission android:name="android.permission.health.READ_STEPS" />
<uses-permission android:name="android.permission.health.READ_SLEEP" />
<!-- Write permissions for native steps / sleep synchronisation -->
<uses-permission android:name="android.permission.health.WRITE_STEPS" />
<uses-permission android:name="android.permission.health.WRITE_SLEEP" />
<application ...>
...
</application>
</manifest>

Explain sensor access before calling enableSensors()

After configure() and authenticate() are complete, show a dedicated screen explaining:

  • Which sensors are being requested
  • Why they are needed for your use case
  • How enabling them improves the app experience

This gives users the right context before the system permission prompts appear and usually leads to a better opt-in rate than showing the native permission UI without explanation.

Example: enable sensors screen

Example copy for your permission explainer screen

Title
Enable health data collection
Body
We use your steps, sleep, and heart rate data to personalise your daily
health insights and show more accurate trends over time.
Why we ask
- Steps help us understand movement patterns
- Sleep helps us calculate recovery and routine
- Heart rate adds extra context for effort and readiness
Primary CTA
Enable Health Data
Secondary CTA
Not now

Only request what you can clearly justify

Apple and Google are strict about sensitive permission use. Only request the sensors that directly support the features your app provides, and explain that value in plain language before calling enableSensors().


About the device sensor status

Sensors can have multiple possible statuses that indicate whether they are enabled, unavailable, or still pending.

getSensorStatus() is the best way to determine whether collection is fully active. In a healthy onboarding flow, you should use it:

  • after the user finishes the permission prompt
  • on later app launches
  • after app updates that introduce new required sensors
  • whenever you need to decide whether to show onboarding again or display a recovery banner

A sensor set should only be treated as fully ready when getSensorStatus() returns enabled. In practice, that is the state where the required permissions are in place and the SDK collectors are running.

public enum SensorStatus: Int {
case pending = 0 // Sensors pending (before prompting user for permission)
case unavailable = 1 // Sensors not supported by user's device
case disabled = 2 // Sensors disabled (after prompting user for permission)
case enabled = 3 // Sensors enabled (after prompting user for permission)
}

(iOS) Permission Privacy - IMPORTANT INFO

Apple limits the ability to detect the true sensor status to protect user privacy

Apple documentation:

To help protect the user’s privacy, your app doesn’t know whether the user granted or denied permission to read data from HealthKit. If the user denied permission, attempts to query data from HealthKit return only samples that your app successfully saved to the HealthKit store.

This means that if a sensor is available, the only possible SensorStatus values on iOS are usually:

  • pending if you have not already prompted the user for permission
  • enabled if you have already prompted the user for permission

The disabled status is not triggered even if the user declines permission.

The disabled status is only included in the iOS SDK to keep parity with the Android SDK.


Getting the device sensor status

You can check the current status of a sensor set by calling getSensorStatus(). This method is asynchronous and returns the updated SahhaSensorStatus in its callback.

Configure the SDK before you get sensor status

On app launch, SensorStatus will always be pending until the SDK has been configured. You must call configure() before you can trust the result of getSensorStatus().

We suggest calling getSensorStatus() after configuration is complete. In most production onboarding flows, you should also make sure the user is authenticated before using the result to decide the next step.

// Get status of `steps` and `sleep` sensors
Sahha.getSensorStatus([SahhaSensor.steps, SahhaSensor.sleep]) { error, sensorStatus in
if let error = error {
print(error)
} else if sensorStatus == .pending {
// Sensors are NOT enabled and ready - show your custom UI before asking for user permission
} else if sensorStatus == .enabled {
// Sensors are enabled and ready
} else {
// Sensors are disabled or unavailable
}
}

Enabling device sensors

Before the SDK can start collecting data, you need to enable sensors by calling enableSensors(). This method is asynchronous and returns the updated SahhaSensorStatus in its callback.

Use a button - IMPORTANT INFO

ALWAYS use a button to enable sensors

DO NOT call enableSensors() inside app init code or inside useEffect / auto-run lifecycle code.

enableSensors() displays system UI for the user. If you call it on init, your user may be shown a permission popup immediately on every app launch.

This is poor user experience and may cause your app to be rejected by Apple or Google.

Always use enableSensors() from a user action such as a button press on your signup screen, onboarding flow, or health-permission screen.

// ALWAYS use a button to enable sensors
Button {
// Enable `steps` and `sleep` sensors
Sahha.enableSensors([SahhaSensor.steps, SahhaSensor.sleep]) { error, sensorStatus in
if let error = error {
print(error)
} else if sensorStatus == .enabled {
// Sensors are enabled and ready
} else {
// Sensors are disabled or unavailable
}
}
} label: {
HStack {
Spacer()
Text("Enable Sensors")
Spacer()
}
}

(iOS) Sleep Sensor - IMPORTANT INFO

Set up Sleep before using the sleep sensor

For the Sahha SDK to collect data from the sleep sensor, Sleep functionality must already be enabled by your user before calling enableSensors().

If the HealthKit permission flow has not been shown yet and getSensorStatus() is still pending, this is a good time to show custom UI that helps the user set up Sleep in the Health app before you request access.

Read more in Apple's setup guide:

Sleep for iOS


Prompt the user if sensors are not enabled

Users do not always enable every permission during onboarding. Also, later app releases may introduce new sensors that require extra access.

If getSensorStatus() does not return enabled, show an in-app banner or prompt that helps the user return to sensor setup.

A persistent in-app prompt is often the easiest way to recover from:

  • Incomplete onboarding
  • Previously denied permissions
  • Newly added sensors after an app update
  • Platform-specific edge cases where expected data is still missing

Example: enable sensors banner

Example banner copy

Title
Finish enabling health access
Body
We still need access to Steps and Sleep so we can keep your health insights up to date.
Primary action
Review permissions
Secondary action
Not now

Example decision logic for a recovery banner

status = getSensorStatus(requiredSensors)
if status != enabled:
showBanner(
title: "Finish enabling health access",
action: "Review permissions"
)
else:
hideBanner()

Offer a manual permissions recovery flow

If you want to go the extra mile, provide a fallback flow that helps users manually verify and re-enable permissions.

This is especially helpful in two situations:

  • the user is still having trouble enabling sensors
  • on iOS, where the system may restrict your ability to know the exact read-permission state after the first permission flow

In these cases, getSensorStatus() may say enabled even though expected data is no longer arriving.

A practical recovery flow looks like this:

  1. Check getSensorStatus() for the sensors your app depends on.
  2. If the status is enabled but expected data is still missing, make a lightweight verification request.
  3. If that request still returns no expected result, show a recovery banner or help screen.
  4. Give the user a button that calls openAppSettings().

Example: verify expected data after permissions look enabled

Use the method that matches the part of the product you are validating:

  • getStats() if you want to verify raw sensor-driven daily stats such as steps or sleep
  • getBiomarkers() if your product depends on Sahha-generated biomarkers
status = getSensorStatus(requiredSensors)
if status == enabled:
stats = getStats(steps or sleep for a period you expect data to exist)
if stats are missing:
showManualPermissionRecoveryHelp()

Guide users to settings

Your help screen can guide users to:

  • Open your app in system settings
  • Review Apple Health or Health Connect access for your app
  • Re-enable the specific sensors your app requires
  • Return to the app and retry data collection

Open App Settings

If a user disables a sensor, or you need them to manually re-check their permissions, send them to settings with openAppSettings().

Sahha.openAppSettings()

(iOS) Permission Changes - IMPORTANT INFO

Your app will terminate if iOS permissions change while it is backgrounded

If the user enables or disables a Health permission from device settings while your app is in the background, iOS will force your app to terminate. This is intentional system behaviour and the app will need to be relaunched.


Platform caveats that affect real-world data collection

Android: Health Connect availability

Health Connect is available on Android 9 (API 28) and above. On Android 9 through Android 13, the user must install the Health Connect app. On Android 14 and above, Health Connect is built in.

If a user cannot complete the permission flow on Android, check that Health Connect is available and installed before troubleshooting anything else.

Historical readback limits

Both Apple Health and Health Connect can only provide a limited amount of historical data before the first successful permission grant. If the app is later uninstalled and reinstalled, that read window resets from the new permission date.

Example

A user first grants permission on March 30, 2023.
The earliest readable data may be February 28, 2023 onward.
The user deletes the app on May 10, 2023.
They reinstall it and grant permission again on May 15, 2023.
The earliest readable data may now be April 15, 2023 onward.

This is important when validating onboarding because a fresh install may not immediately show older historical data you expected to see.

iOS: locked-device restriction

Apple Health restricts reading data while the device is locked. Data recorded while the device is locked can become available after the user unlocks the phone again.

If you are testing overnight or background collection, remember that data availability may not update until after unlock.


Why this flow matters

This flow helps ensure the SDK is set up correctly and actually delivering data.

  • configure() connects the SDK to the correct environment
  • authenticate() associates the SDK with the correct user
  • enableSensors() requests the required health permissions
  • getSensorStatus() confirms whether collection is ready
  • If status is not enabled, banners help repair incomplete permission states
  • If status looks enabled but expected data is still missing, offer a manual recovery flow and openAppSettings()

When these pieces are implemented together, you get a much more reliable onboarding experience and a better chance of continuous data collection.


This order helps ensure the SDK is connected to the correct environment, associated with the correct user profile, and ready to start collecting the sensor data your product needs.