iToverDose/Software· 14 MAY 2026 · 08:04

Build a sleek fitness companion app in React Native with Apple Health

Most smartwatch owners rarely glance at the device itself yet still track daily activity. Discover how to build a React Native companion app that syncs seamlessly with Apple Health and Android Health Connect to visualize health data on users' phones.

DEV Community6 min read0 Comments

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 → Dashboard

Three 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 prebuild

In 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.

Comments

00
LEAVE A COMMENT
ID #WMS1N6

0 / 1200 CHARACTERS

Human check

6 + 4 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.