Most smartwatch buyers stop checking the watch face within days, yet they still expect to see their activity stats somewhere convenient. That "somewhere" is the companion app on their phone, where dashboards, streaks, and charts bring meaning to raw data captured by the wearable. Building a companion app that reads from Apple Health on iOS or Android Health Connect on Wear OS isn’t just a nice-to-have—it’s often the primary way users interact with their health data.
This guide walks through building a React Native companion app that pulls health metrics from Apple Health and Health Connect, stores the data efficiently, and presents it in a clean dashboard. We’ll cover architecture, permissions, sync models, and common production pitfalls—without diving into firmware or vendor SDKs.
Why a companion app matters more than the watch itself
Wearable devices capture data, but the companion app transforms that data into insights. The watch’s role is to collect; the phone’s role is to interpret, store, and visualize. A well-designed companion app can turn sporadic glances at the watch into a daily habit of checking progress, logging workouts, and understanding trends.
Yet many developers overlook the companion app, focusing instead on the wearable hardware or standalone app. In reality, the phone app is where users spend most of their time—and where your product’s value is truly delivered.
Core architecture: health data flows through multiple layers
A robust companion app follows a clear data pipeline:
Wearable → OS Health Store → React Native Bridge → Local Database → Sync Queue → Backend → DashboardThree key principles guide this architecture:
- The OS health store is the source of truth. HealthKit on iOS and Health Connect on Android retain data even if the app is reinstalled. Your local database acts as a cache for fast UI rendering and a buffer for user-generated entries.
- Reads flow one way; writes flow both ways. Your app reads health samples from the OS store. When users log workouts or other data in your app, you write it back to both the OS store and your backend—ensuring consistency across devices.
- Background sync is unpredictable. Apple limits background wake-ups aggressively. Design your sync logic assuming your app may only wake every 15–30 minutes, not every second. Use background delivery sparingly and test thoroughly.
Start with the biggest wearables, not all of them
Shipping a generic "wearable app" is a common mistake. Each platform has different data models, permission models, and review requirements. Focus on the platforms your users already own:
- Apple Watch (watchOS): HealthKit via
react-native-health - Wear OS (Pixel/ Galaxy Watch): Health Connect via
react-native-health-connect - Fitbit, Garmin, Whoop, Oura, Polar: Use vendor REST APIs or OAuth flows—these are typically handled as a second-phase feature
For most consumer apps, HealthKit + Health Connect cover the majority of users. They leverage existing OS-level permissions, avoid OAuth complexity, and reduce development overhead.
Step-by-step: Build the React Native companion app
1. Set up the Expo project with native modules
You’ll need a custom development client because both health libraries depend on native modules.
npx create-expo-app fitness-companion --template expo-template-blank
npx expo install expo-dev-client
npm install react-native-health react-native-health-connect
npx expo prebuildIn app.json, declare health permissions and entitlements:
{
"expo": {
"ios": {
"infoPlist": {
"NSHealthShareUsageDescription": "Read your activity to power your dashboard.",
"NSHealthUpdateUsageDescription": "Save workouts you log in the app."
},
"entitlements": {
"com.apple.developer.healthkit": true
}
},
"android": {
"permissions": [
"android.permission.health.READ_STEPS",
"android.permission.health.READ_HEART_RATE",
"android.permission.health.READ_SLEEP",
"android.permission.health.READ_EXERCISE"
]
}
}
}2. Initialize HealthKit on iOS and fetch step count
Import the library and define permissions:
import AppleHealthKit, { HealthKitPermissions } from 'react-native-health';
const permissions: HealthKitPermissions = {
permissions: {
read: [
AppleHealthKit.Constants.Permissions.Steps,
AppleHealthKit.Constants.Permissions.HeartRate,
AppleHealthKit.Constants.Permissions.SleepAnalysis,
AppleHealthKit.Constants.Permissions.Workout,
AppleHealthKit.Constants.Permissions.ActiveEnergyBurned,
],
write: [AppleHealthKit.Constants.Permissions.Workout],
},
};
AppleHealthKit.initHealthKit(permissions, (err) => {
if (err) console.error('HealthKit init failed', err);
});Fetch daily step count with proper filtering:
const startOfDay = new Date();
startOfDay.setHours(0, 0, 0, 0);
AppleHealthKit.getStepCount(
{ date: startOfDay.toISOString() },
(err, results) => {
if (err) return;
setSteps(results.value);
}
);Production tip: HealthKit aggregates can double-count if multiple sources write steps. Use getSamples with source filtering for accuracy. Also, iOS won’t surface denied permissions—silent zero returns mean you should render an empty state, not an error.
3. Read health data from Android Health Connect
Health Connect replaced Google Fit in 2025 and is now the default health store on Wear OS and Pixel devices.
import { initialize, requestPermission, readRecords } from 'react-native-health-connect';
await initialize();
await requestPermission([
{ accessType: 'read', recordType: 'Steps' },
{ accessType: 'read', recordType: 'HeartRate' },
{ accessType: 'read', recordType: 'SleepSession' },
{ accessType: 'read', recordType: 'ExerciseSession' },
]);
const result = await readRecords('Steps', {
timeRangeFilter: {
operator: 'between',
startTime: startOfDay.toISOString(),
endTime: new Date().toISOString(),
},
});
const totalSteps = result.records.reduce((sum, r) => sum + r.count, 0);Health Connect offers a simpler permission UX than HealthKit, but it only grants access to the past 30 days by default. Users must manually extend history access for long-term data.
4. Optional: Add Apple Watch bridge for quick interactions
If you want to support a minimal watchOS app—say, a quick workout button—you’ll need a watchOS target in Xcode bridged to React Native via WCSession. The watchOS app itself must be written in Swift, since React Native doesn’t run on watchOS.
A minimal Swift bridge:
class WatchBridge: NSObject, WCSessionDelegate, RCTBridgeModule {
static func moduleName() -> String! { "WatchBridge" }
@objc func sendWorkout(_ duration: NSNumber) {
WCSession.default.sendMessage(["workoutDuration": duration], replyHandler: nil, errorHandler: nil)
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
// Handle incoming messages from the watch
}
}Remember: the watchOS app is a separate UI layer. Keep it lightweight and focused on quick actions.
Sync model: the secret to avoiding production bugs
The most common failures in health companion apps stem from poor sync logic. Follow this one rule:
Make your backend POST /samples idempotent using the HealthKit UUID.Every HealthKit or Health Connect sample includes a unique identifier. Store this UUID in your local database and send it with every write. If the UUID matches an existing record, skip the insert—this prevents duplicates when users reinstall or sync across devices.
Also, design your sync queue to handle retries gracefully. Network drops, background constraints, and OS throttling are realities—build resilience into your system.
The real bottleneck: building the dashboard UI
While integrating HealthKit and Health Connect is technical, the dashboard is where most development time goes. Plan for it:
- Use a fast local database like WatermelonDB or SQLite for responsive UI
- Aggregate data in the backend for long-term trends
- Keep visualizations simple—users care about trends, not pixel-perfect charts
- Add filters for time periods, activities, and devices
What’s next: scaling beyond the basics
Once the core integration is stable, consider expanding:
- Add support for vendor APIs (Fitbit, Garmin, etc.) for users with mixed ecosystems
- Introduce social features: challenges, sharing, or community rankings
- Build a web dashboard for desktop access
- Enable remote coaching with personalized insights
But start small. Most users just want a clean, reliable way to see their health data—and that starts with a solid companion app on their phone.
The watch captures. The phone interprets. The app connects the user to their health journey.
AI summary
Learn to build a React Native companion app that syncs with Apple Health and Android Health Connect to display health data on users' phones—covering permissions, sync models, and dashboard UI.