Skip to main content

Google Fit to Health Connect Migration in Capacitor

Migrate a Capacitor app from Google Fit to Health Connect before the Fit APIs end in 2026: data type mapping, permissions, queries, and Play review.

Article credits

Martin Donadieu

Writer

Valeria

Reviewer

Jordan

Editor

Google Fit to Health Connect Migration in Capacitor

The Google Fit to Health Connect migration means replacing every Fit API call in your Capacitor app with Health Connect on Android, and with HealthKit on iOS if you ship there too. Google stopped new Fit sign-ups on May 1, 2024, and supports the Fit APIs only until the end of 2026. This guide maps Fit data types and calls to Health Connect, shows the replacement code with @capgo/capacitor-health, and covers the Play Console review that comes with health permissions.

Google Fit deprecation timeline

Date What happened
May 1, 2024 No new developer sign-ups for Google Fit APIs
2024 to 2026 Existing Fit integrations keep working, Google directs developers to Health Connect
2026 Fit APIs, including the REST API, are deprecated
End of 2026 End of support. Google has not published an exact shutdown day

Google’s migration FAQ says there is no alternative to the Fit REST API with the same shape: on-device apps move to Health Connect, and cloud integrations move to the account-based Google Health API. If you see a precise shutdown date quoted somewhere, check it against Google’s own FAQ before planning around it.

What changes when you move to Health Connect

Google Fit Health Connect
Where data lives Google account, in the cloud On the device
Auth OAuth 2.0 with fitness scopes, Google Sign-In Android runtime permissions per data type
Setup Cloud project, OAuth client, SHA-1 fingerprints Manifest permissions, privacy policy screen
Availability Any Android device with Play services Built into Android 14+, an app from Google Play on older versions
History Full account history Last 30 days by default, older data with READ_HEALTH_DATA_HISTORY
Web/server access REST API None (use Google Health API for cloud)
iOS Not supported Not supported, use HealthKit
Store review OAuth verification for sensitive scopes Play Console Health Connect declaration

The biggest product change is the device-centric model. Health Connect data on one phone is not visible on another. If your app shows history across devices, sync readings to your own backend.

Map Fit data types to Health Connect

Google Fit data type Health Connect record @capgo/capacitor-health type
com.google.step_count.delta StepsRecord steps
com.google.distance.delta DistanceRecord distance
com.google.calories.expended TotalCaloriesBurnedRecord / ActiveCaloriesBurnedRecord totalCalories / calories
com.google.calories.bmr BasalMetabolicRateRecord basalCalories
com.google.heart_rate.bpm HeartRateRecord heartRate
com.google.weight WeightRecord weight
com.google.height HeightRecord height
com.google.body.fat.percentage BodyFatRecord bodyFat
com.google.sleep.segment SleepSessionRecord with stages sleep
com.google.oxygen_saturation OxygenSaturationRecord oxygenSaturation
com.google.blood_pressure BloodPressureRecord bloodPressure
com.google.blood_glucose BloodGlucoseRecord bloodGlucose
com.google.body.temperature BodyTemperatureRecord bodyTemperature
com.google.hydration HydrationRecord dietaryWater
com.google.nutrition NutritionRecord dietaryEnergyConsumed (energy only)
com.google.activity.segment and Sessions API ExerciseSessionRecord workouts (read via queryWorkouts)

Fit types without a direct equivalent

  • Heart Points (com.google.heart_minutes) and Move Minutes (com.google.active_minutes) were Google Fit scores. Health Connect stores raw data, not these scores. Recompute your own metric from heart rate and exercise sessions.
  • Activity samples with per-second activity types are replaced by exercise sessions with segments.
  • Location samples inside workouts become ExerciseRoute data in Health Connect, which needs a separate permission and is not exposed by the plugin.
  • Cadence, speed and power exist in Health Connect (StepsCadenceRecord, SpeedRecord, PowerRecord) but are not covered by the plugin’s types. If you depend on them, a small custom native method is the fastest path.

Audit before you write code: list every DataType and every API you call (History, Recording, Sessions, Sensors, Config, REST), and mark each one as mapped, recomputed, or dropped.

Step 1: Remove Google Fit

Delete the Fit integration from your Android project and JavaScript:

  • Remove com.google.android.gms:play-services-fitness and, if only used for Fit, play-services-auth from build.gradle.
  • Remove the Fit OAuth client from Google Cloud and the fitness scopes from your consent screen.
  • Uninstall the old community Google Fit Capacitor plugin you used, then run bunx cap sync.

Keep the Fit code in a branch until the new version is live, so you can export historical data if users ask.

Step 2: Install the health plugin

bun add @capgo/capacitor-health
bunx cap sync

@capgo/capacitor-health supports Capacitor 8, uses Health Connect on Android and HealthKit on iOS, and requires Android minSdk 26.

Android setup

The plugin merges the Health Connect read and write permissions for its supported types into your manifest, plus the <queries> entry for the Health Connect package and the permission rationale activity. You need to:

  1. Provide a privacy policy. Health Connect opens it from the permission sheet. Either add android/app/src/main/assets/public/privacypolicy.html, or set a URL in android/app/src/main/res/values/strings.xml:
<string name="health_connect_privacy_policy_url">https://example.com/privacy</string>
  1. Trim permissions. Google Play reviews every Health Connect permission you declare. If you only read steps and heart rate, remove the rest with tools:node="remove":
<uses-permission
    android:name="android.permission.health.WRITE_BLOOD_GLUCOSE"
    tools:node="remove" />
  1. Add history access if you need it. Health Connect limits reads to roughly the last 30 days unless the user grants READ_HEALTH_DATA_HISTORY:
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY" />

iOS setup

Enable the HealthKit capability in Xcode and add usage strings to Info.plist:

<key>NSHealthShareUsageDescription</key>
<string>Show your steps and workouts in the app.</string>
<key>NSHealthUpdateUsageDescription</key>
<string>Save the workouts you record in the app.</string>

Step 3: Check availability

Google Fit worked anywhere Play services existed. Health Connect may be missing on Android 13 and older, or need an update.

import { Health } from '@capgo/capacitor-health';

export async function ensureHealthAvailable() {
  const result = await Health.isAvailable();
  if (result.available) return true;

  // On Android, send the user to install or update Health Connect
  if (result.platform === 'android') {
    await Health.openHealthConnectSettings();
  }
  console.warn('Health store unavailable:', result.reason);
  return false;
}

Show a short explanation screen before redirecting. Users who never heard of Health Connect are confused when the Play Store opens unprompted.

Step 4: Replace OAuth with permissions

The Fit flow was: Google Sign-In, request fitness scopes, then call APIs. The new flow is a single permission sheet:

const status = await Health.requestAuthorization({
  read: ['steps', 'distance', 'calories', 'heartRate', 'sleep', 'workouts'],
  write: ['weight'],
  requestHistoryAccess: true, // Android only
});

if (status.readDenied.length > 0) {
  // explain what will not work and offer openHealthConnectSettings()
}
if (status.historyAccessAvailable === false) {
  // provider too old: only the last 30 days are readable
}

Permissions are per data type and the user can grant any subset. Use checkAuthorization with the same options on every app start, because users can revoke access in Health Connect settings at any time. On iOS, HealthKit hides read denials for privacy, so an empty result can mean “no data” or “no access”.

Step 5: Replace History API reads

A Fit readData call for raw samples becomes readSamples:

const end = new Date();
const start = new Date(end.getTime() - 24 * 60 * 60 * 1000);

const { samples } = await Health.readSamples({
  dataType: 'heartRate',
  startDate: start.toISOString(),
  endDate: end.toISOString(),
  limit: 500,
  ascending: true,
});

for (const s of samples) {
  console.log(s.startDate, s.value, s.unit, s.sourceName, s.deviceType);
}

sourceName and, on Android, deviceType (watch, phone, chestStrap, and so on) replace Fit’s data source objects. Use them to prefer watch data over phone data when both exist.

Step 6: Replace bucketed and aggregate reads

Fit’s bucketByTime plus aggregate becomes queryAggregated:

const { samples: daily } = await Health.queryAggregated({
  dataType: 'steps',
  startDate: new Date(Date.now() - 7 * 86_400_000).toISOString(),
  endDate: new Date().toISOString(),
  bucket: 'day',          // 'hour' | 'day' | 'week' | 'month'
  aggregation: 'sum',
});

const { samples: hr } = await Health.queryAggregated({
  dataType: 'heartRate',
  bucket: 'hour',
  aggregation: ['min', 'average', 'max'],
  startDate: new Date(Date.now() - 86_400_000).toISOString(),
  endDate: new Date().toISOString(),
});
// hr[i].values.min, hr[i].values.average, hr[i].values.max

Always aggregate steps instead of summing raw samples. Health Connect deduplicates overlapping data from several apps during aggregation, and raw sums often double count when a watch and a phone both record steps.

Step 7: Replace the Sessions API

Fit sessions map to exercise sessions:

const { workouts, anchor } = await Health.queryWorkouts({
  workoutType: 'running',
  startDate: new Date(Date.now() - 30 * 86_400_000).toISOString(),
  endDate: new Date().toISOString(),
  limit: 50,
});

for (const w of workouts) {
  console.log(w.workoutType, w.duration, w.totalDistance, w.totalEnergyBurned);
}
// pass `anchor` back to fetch the next page

Request workouts in read permissions first. The plugin reads workouts but does not write exercise sessions, so if your app records workouts, write the underlying samples (distance, calories, heart rate) and keep the session itself in your backend, or add a native method for ExerciseSessionRecord.

Step 8: Replace inserts

Fit’s insertData becomes saveSample:

await Health.saveSample({
  dataType: 'weight',
  value: 72.4, // kilograms
  startDate: new Date().toISOString(),
});

await Health.saveSample({
  dataType: 'bloodPressure',
  value: 120,
  systolic: 120,
  diastolic: 80,
  startDate: new Date().toISOString(),
});

Values must use the default unit of each type (kilograms, meters, kilocalories, bpm). The metadata option is ignored by Health Connect.

Step 9: Pass Google Play review

Health permissions trigger extra review:

  1. In Play Console, open App content and complete the Health apps declaration and the Health Connect permissions form. Justify every permission you request.
  2. Make sure the privacy policy linked in Play Console and the one shown in the Health Connect sheet describe health data use.
  3. Update the Data safety form: health and fitness data, collected or not, shared or not.
  4. Submit a build that only declares the permissions you justified. Extra declared permissions are the most common rejection.

Plan for review to take longer than a normal update. Ship the migration as its own release, not mixed with unrelated features.

Step 10: Migrate user expectations

  • Tell users their history now comes from Health Connect, and that older data may be limited to 30 days until they grant history access.
  • If your app used Fit as its cloud sync, move that responsibility to your backend now.
  • Remove “Connect Google Fit” buttons and rename them “Connect Health Connect” on Android and “Connect Apple Health” on iOS.

Troubleshooting

isAvailable() returns false on Android 13: Health Connect is not installed or outdated. Call openHealthConnectSettings().

The permission sheet never appears: the permission is not declared in the merged manifest, or you removed it with tools:node="remove". Check android/app/build/intermediates/merged_manifests.

Reads return only 30 days: request requestHistoryAccess: true and declare READ_HEALTH_DATA_HISTORY.

Step totals are higher than Google Fit: you summed raw samples. Use queryAggregated.

Empty results on iOS: either no data or read permission denied. HealthKit does not tell you which.

Play Console rejects the update: remove undeclared or unjustified Health Connect permissions and resubmit with a clear justification.

Ship the migration in stages

The native part (plugin, manifest, HealthKit capability) needs a store release. After that, queries, UI and data mapping are JavaScript, which you can iterate on with Capgo live updates while users test the new flow. If you also read live sensor data, see our guide to building a heart rate monitor with Capacitor, and the health plugin docs for every data type.

Live updates for Capacitor apps

When a web-layer bug is live, ship the fix through Capgo instead of waiting days for app store approval. Users get the update in the background while native changes stay in the normal review path.

human support from Martin

Get Started Now

Latest from our Blog

Capgo gives you the best insights you need to create a truly professional mobile app.