Using Apple Health & Google Health Connect with the Pathmate Platform
Last updated: March 2026
Background activity tracking is essential for Just-in-Time Adaptive Intervention (JITAI). The MobileCoach app supports passive, continuous step tracking via Apple HealthKit (iOS) and Google Health Connect (Android), even when the app is not actively in use.
1. Android Setup: Google Health Connect
Android devices vary significantly by manufacturer. Health Connect serves as a unified interface between your device's health apps and MobileCoach.
1.1 Prerequisites
Before connecting to MobileCoach, ensure Health Connect is installed and receiving step data from your device.
⚠️ All Android devices require step tracking to be active in Health Connect before proceeding.
1.2 Step-by-Step Setup
- Install Health Connect if not already present.
- Health Connect runs in the background.
- Find it by searching for "Health Connect" in the Play Store and tapping Open.
- Install a step-tracking app compatible with Health Connect, such as:
- Google Fit / Google Health
- Samsung Health
- Other manufacturer-specific health apps
- Verify step recording — confirm your chosen app is actively counting steps.
- Grant the step-tracking app access in Health Connect under App Permissions.
- Do not grant MobileCoach access to Health Connect manually — this must be done through the MobileCoach app itself (see Section 2).
- Verify data flow — confirm that Health Connect shows step data under Data and Access.
📚 Helpful resources:
2. Connecting Health Apps to MobileCoach - Step-by-Step
- for iOS only: Download TestFlight (if not yet installed), but do not open it.
- Tap the Firebase/TestFlight install link on your phone to install MobileCoach.
- Disable automatic updates for MobileCoach in TestFlight.
- Open MobileCoach and scan the QR code of your coaching. Do not start the coaching yet.
- Start the coaching and follow the setup wizard:
- Grant step data permission from Apple Health or Google Health Connect
- Verify that data is being received: navigate to CoachStudio Coaching Editor → Participants → Export Data and confirm step data appears after walking.
- Keep the app running in the background — do not force-close it. If the OS closes it (e.g. after a reboot), reopen it promptly.
⚠️ Health app synchronisation must be established through the MobileCoach app, not through the phone's system settings.
3. Coaching Design Instructions
3.1 Commands
To enable and disable background health tracking, add a Micro Dialog message as a Command message with the following plain text:
Start tracking:
start-background-health-tracking $participantIdentifier $sensing_pmHealthSecret
Stop tracking:
stop-background-health-tracking
3.2 Server-Side Data Variables
Step data is stored in the following variables:
| Variable | Platform |
|---|---|
$stepsHealthIos |
Apple HealthKit (iOS) |
$stepsHealthAndroid |
Google Health Connect (Android) |
Each entry contains the total step count for that day, transmitted at the time of the data point's timestamp.
⚠️ There is currently no detection of a lost connection to the Health app. Connection loss is not reported to the server.
3.3 Calculating Step Data
The examples below show how to extract today's step count and timing information from the raw sensor data.
iOS Example:
//+ moment
// import moment from 'moment'
const sensorData = {
$$SENSOR_DATA$$: 'pmHealth',
types: ['stepsHealthIos'],
startRelativeInclusive: '2d',
endRelativeExclusive: '0m'
}
const today = moment().format('DD.MM.YYYY')
const nowTime = moment().format('DD.MM.YYYY HH:mm:ss')
const sensorDataWithDay = sensorData.map((s) => ({
...s,
day: moment(s.timestamp).format('DD.MM.YYYY')
}))
const sensorDataToday = sensorDataWithDay.filter((s) => s.day === today)
const todayStepCount =
sensorDataToday.length === 0
? -1
: JSON.parse(sensorDataToday[sensorDataToday.length - 1].data).stepCount
const lastTimestamp = sensorDataToday.length
? sensorDataToday[sensorDataToday.length - 1].timestamp : null
const firstTimestamp = sensorDataToday.length
? sensorDataToday[0].timestamp : null
const minutesSinceLastData = lastTimestamp
? moment().diff(moment(Number(lastTimestamp)), 'minutes') : null
const o = {
sensing_healthStepCountToday: todayStepCount,
sensing_healthMinutesSinceLastData: minutesSinceLastData,
sensing_healthDayValueLatest: lastTimestamp
? moment(Number(lastTimestamp)).format('DD.MM.YYYY HH:mm:ss') : null,
sensing_healthDayValueFirst: firstTimestamp
? moment(Number(firstTimestamp)).format('DD.MM.YYYY HH:mm:ss') : null,
sensing_healthToday: today,
sensing_healthNow: nowTime
}
o
Android Example:
//+ moment
// import moment from 'moment'
const sensorData = {
$$SENSOR_DATA$$: 'pmHealth',
types: ['stepsHealthAndroid'],
startRelativeInclusive: '2d',
endRelativeExclusive: '0m'
}
const today = moment().format('DD.MM.YYYY')
const nowTime = moment().format('DD.MM.YYYY HH:mm:ss')
const getStepCount = (s) => {
try {
const d = typeof s.data === 'string' ? JSON.parse(s.data) : s.data
const v = Number(d?.stepCount)
return Number.isFinite(v) ? v : 0
} catch {
return 0
}
}
const sensorDataWithDay = sensorData.map((s) => ({
...s,
day: moment(s.timestamp).format('DD.MM.YYYY')
}))
const sensorDataToday = sensorDataWithDay
.filter((s) => s.day === today)
.sort((a, b) => Number(a.timestamp) - Number(b.timestamp))
const todayStepCount =
sensorDataToday.length === 0
? -1
: getStepCount(sensorDataToday[sensorDataToday.length - 1])
const lastTimestamp = sensorDataToday.length
? sensorDataToday[sensorDataToday.length - 1].timestamp : null
const firstTimestamp = sensorDataToday.length
? sensorDataToday[0].timestamp : null
const minutesSinceLastData = lastTimestamp
? moment().diff(moment(Number(lastTimestamp)), 'minutes') : null
const o = {
sensing_healthStepCountToday: todayStepCount,
sensing_healthMinutesSinceLastData: minutesSinceLastData,
sensing_healthDayValueLatest: lastTimestamp
? moment(Number(lastTimestamp)).format('DD.MM.YYYY HH:mm:ss') : null,
sensing_healthDayValueFirst: firstTimestamp
? moment(Number(firstTimestamp)).format('DD.MM.YYYY HH:mm:ss') : null,
sensing_healthToday: today,
sensing_healthNow: nowTime
}
o
4. Performance Specifications
⚠️ Supported platforms: Android 12 or higher · iOS 15 or higher
Synchronisation behaviour depends on the app state:
| State | Description | Sync Interval |
|---|---|---|
| State 1 | App open and in use | No update while app stays open |
| State 2 | App in background, phone in use | ~every 30 min (ideal conditions) |
| State 3 | App in background, phone idle | ~every 30 min (ideal conditions) |
| State 4 | App closed | No synchronisation |
Note: Sync is driven by the OS on a best-effort basis and cannot be directly controlled by MobileCoach. Android behaviour may vary across manufacturers.
4.1 Factors That Reduce Reliability
- Low battery
- Low Power Mode enabled
- App has not been opened for an extended period
- Device has been inactive for several hours
- Device is overheating
- OS power-saving heuristics based on usage patterns
4.2 Tips to Improve Reliability
- Keep battery above 20%
- Disable Low Power Mode
- Use the smartphone regularly throughout the day
- Open the MobileCoach app at least once per day
- Never force-close the app; always allow it to run in the background
⚠️ The MobileCoach app must remain active in the background at all times for reliable data synchronisation.