---
title: Announcing the Capacitor Health Plugin
description: Our new Capacitor Health plugin reads, writes, and aggregates health data through Apple HealthKit and Android Health Connect with one typed API.
date:
  created: 2026-08-26
  updated: 2026-08-26
authors:
  - robingenz
categories:
  - Announcements
  - Capacitor
  - SDKs
links:
  - Capacitor Health: sdks/capacitor/health.md
faq: true
---

# Announcing the Capacitor Health Plugin

Health data on mobile lives in two stores: Apple HealthKit on iOS and Health Connect on Android. Today we're announcing the [Capacitor Health plugin](../../sdks/capacitor/health.md), which reads, writes, and aggregates data from both through a single, strictly typed API. Instead of handing you raw record lists and leaving the math to you, the plugin treats aggregation as the primary query model: daily step totals, weekly averages, and monthly minimums are computed by the platform's health store itself, including the deduplication of overlapping sources like a phone and a smartwatch. It's available today to all Capawesome [Insiders](../../insiders/index.md).

<!-- more -->

<div class="capawesome-z29o10a">
  <a href="https://capawesome.io/" target="_blank">
    <img alt="Build and deploy your Capacitor app with Capawesome Cloud" src="https://capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.png?t=1" />
  </a>
</div>

**Key takeaways:**

- `@capawesome-team/capacitor-health` covers Apple HealthKit on iOS and Health Connect on Android with one typed API and around 20 data types, from steps and heart rate to sleep, blood pressure, and workouts.
- [`aggregate(...)`](../../sdks/capacitor/health.md#aggregate) queries sums, averages, minimums, and maximums bucketed by hour, day, week, or month, with multi-source deduplication done by the platform.
- The permission model reports what each platform actually reveals; on iOS, read permissions are never reported as `granted` because HealthKit hides them by design.
- Health Connect availability states are modeled explicitly, including an [`installHealthConnect()`](../../sdks/capacitor/health.md#installhealthconnect) helper for Android 9 to 13.
- The documentation covers the Google Play Health apps declaration and Apple's App Review Guideline 5.1.3.
- Requires Capacitor 8 or later, no web implementation, part of the Capawesome Insiders subscription.

## Why We Built a New Capacitor Health Plugin

The timing follows the platforms. The Google Fit APIs shut down at the end of 2026, and Health Connect takes over as the health store on Android; we covered the details in [Migrating from Google Fit to Health Connect in Capacitor](./google-fit-to-health-connect-migration-in-capacitor.md). On iOS, HealthKit has held that role all along. A cross-platform app therefore programs against two stores that disagree on permissions, sleep modeling, calorie types, and more.

There's a second problem hiding behind the first. Health data usually comes from several sources at once, and a user with a smartwatch produces step records from the watch and the phone for the same minutes. If a plugin only gives you raw records and you sum them up in JavaScript, you count that overlap twice. Both HealthKit and Health Connect solve this with native aggregation queries that deduplicate sources before returning a number, so we built the plugin around those queries instead of around record lists.

One scoping note: the plugin reads what the health stores already hold. For live step counting from the device's motion sensors, reach for the [Capacitor Pedometer plugin](../../sdks/capacitor/pedometer.md) instead.

## Installation

To install the Capacitor Health plugin, please refer to the [Installation](../../sdks/capacitor/health.md/#installation) section in the plugin documentation. It's published to the Capawesome npm registry, so installation requires the license key that comes with a [Capawesome Insiders](../../insiders/index.md) subscription.

Two setup decisions are deliberate and worth knowing up front. First, the Health Connect permissions are declared in your own `AndroidManifest.xml`, not by the plugin, because Google Play reviews every declared health permission and your app must only declare what it actually uses. Second, the Android side requires a `minSdkVersion` of 26, and on iOS you add the HealthKit capability plus the two usage description keys. The documentation lists the exact manifest entry for every data type.

## Usage

Here's what an integration looks like, from the availability check to writing your first record.

### Check availability

Health Connect exists in three states on Android: available, not installed, or unsupported by the device. On Android 9 to 13 it's a separate app the user may not have, while on Android 14 and later it's part of the operating system. [`isAvailable()`](../../sdks/capacitor/health.md#isavailable) reports the state, and [`installHealthConnect()`](../../sdks/capacitor/health.md#installhealthconnect) opens the Play Store when something is missing:

```typescript
import { Health } from '@capawesome-team/capacitor-health';

const checkAvailability = async () => {
  const { available, reason } = await Health.isAvailable();
  if (!available && reason === 'health-connect-not-installed') {
    await Health.installHealthConnect();
  }
  return available;
};
```

On iOS, the same method reports whether the device supports health data at all, so a single code path handles both platforms.

### Request permissions

Permissions are requested per data type and separately for reading and writing with [`requestPermissions(...)`](../../sdks/capacitor/health.md#requestpermissions). Request only what your app uses; both platforms show the user a picker with exactly these types:

```typescript
import { DataType, Health } from '@capawesome-team/capacitor-health';

const requestPermissions = async () => {
  const { permissions } = await Health.requestPermissions({
    read: [DataType.Steps, DataType.HeartRate, DataType.Sleep],
    write: [DataType.Weight],
  });
  return permissions;
};
```

### Aggregate health data

This is the method the plugin is built around. [`aggregate(...)`](../../sdks/capacitor/health.md#aggregate) asks the platform's health store to compute values over a time range, grouped into buckets. A week of daily step totals is one call:

```typescript
import { DataType, Health } from '@capawesome-team/capacitor-health';

const readDailySteps = async () => {
  const { buckets } = await Health.aggregate({
    dataType: DataType.Steps,
    startDate: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),
    endDate: new Date().toISOString(),
    bucket: 'day',
    operations: ['sum'],
  });
  return buckets.map((bucket) => bucket.values[0].value);
};
```

Each bucket carries its own start and end date plus one value per requested operation, with `null` when the bucket holds no data. The `day`, `week`, and `month` buckets are calendar-aware and follow the device's time zone, so a "day" is an actual calendar day rather than a fixed count of hours. And because the platform computes the numbers, overlapping records from multiple sources are deduplicated before you ever see them.

Cumulative data types such as steps, distance, calories, and hydration support the `sum` operation; sampled types such as heart rate, weight, and height support `average`, `maximum`, and `minimum`. An unsupported combination rejects with the `INVALID_AGGREGATION` error code instead of resolving with silently empty results, which turns a mistyped query into a bug you find in development rather than a dashboard that shows zeros in production.

### Read and write records

When you need the individual samples, for example to chart heart rate over a workout, [`readRecords(...)`](../../sdks/capacitor/health.md#readrecords) returns them with their timestamps and source. Writing works for the record types apps commonly log, such as weight, hydration, blood pressure, and workouts:

```typescript
import { DataType, Health } from '@capawesome-team/capacitor-health';

const readHeartRateSamples = async () => {
  const { records } = await Health.readRecords({
    dataType: DataType.HeartRate,
    startDate: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
    endDate: new Date().toISOString(),
  });
  return records;
};

const logWeight = async () => {
  await Health.writeRecord({
    dataType: DataType.Weight,
    startDate: new Date().toISOString(),
    value: 71.5,
  });
};
```

Workouts have their own reader: [`readWorkouts(...)`](../../sdks/capacitor/health.md#readworkouts) returns exercise sessions with type, duration, and totals, whether they were logged by your app or by another one.

## An Honest Permission Model

[`checkPermissions(...)`](../../sdks/capacitor/health.md#checkpermissions) tells you the truth, and on iOS the truth is less than you might expect. HealthKit deliberately hides whether a read permission was granted, because a denied permission that is distinguishable from missing data would leak sensitive information: an app that knows it was denied blood glucose access could conclude the user is likely diabetic. The plugin therefore reports iOS read permissions as `prompt` before the first request and `unknown` afterwards, never as `granted`. Reporting `granted` there would be an invented value, so the plugin doesn't do it, even though that answer looks less convenient. Design your app around the presence of data: request the permissions, query, and show a helpful empty state when nothing comes back.

Health Connect reveals more, though still not everything. Read and write permissions are reported as `granted` or `prompt`, and `denied` only appears immediately after the user rejects a request. The [Platform Behavior](../../sdks/capacitor/health.md#platform-behavior) table in the documentation spells out all of these rules per platform.

The same honesty applies to the data itself. The documentation states, for example, that Android limits historical reads to 30 days before the permission was first granted, that iOS models sleep as individual staged samples while Android uses sessions, and that heart rate variability values are not comparable across platforms because Android provides RMSSD and iOS provides SDNN metrics.

## Built to Pass App Review

Health integrations fail review more often than they fail at runtime. Every Android app that integrates with Health Connect must complete the Health apps declaration in the Google Play Console, declare only the permissions it uses, and provide a privacy policy; Apple checks health apps against [App Review Guideline 5.1.3](https://developer.apple.com/app-store/review/guidelines/#health-and-health-research){:target="_blank"}. The plugin documentation includes dedicated sections for the [Google Play declaration](../../sdks/capacitor/health.md#google-play-health-apps-declaration) and the [Apple guideline](../../sdks/capacitor/health.md#app-review-guideline-513), so the policy work is part of the setup instead of a surprise at submission time.

## FAQ

### Is there one Capacitor plugin for both HealthKit and Health Connect?

Yes. The [Capacitor Health plugin](../../sdks/capacitor/health.md) covers Apple HealthKit on iOS and Health Connect on Android with a single, strictly typed API: around 20 data types, platform-side aggregation with buckets, workout reads, and writing for commonly logged record types.

### Why don't steps from my phone and smartwatch add up?

They do, if you let the platform do the math. Summing individual records from `readRecords(...)` counts overlapping data from multiple sources twice. Use `aggregate(...)` for totals; the health store deduplicates the sources automatically.

### Can I read data older than 30 days on Android?

Not yet. Health Connect only allows reading data from up to 30 days before the permission was first granted, and revoking and re-granting restarts that window. Support for the `READ_HEALTH_DATA_HISTORY` permission is planned as a fast-follow feature.

### Does the plugin work on the web?

No. There is no web API for health data, so all methods reject with an unimplemented error on the web.

### Does it work with Ionic, Angular, React, or Vue?

Yes. The plugin is framework-agnostic and works in any Capacitor app, including Ionic with Angular, React, or Vue, as well as plain JavaScript projects.

## Availability

The Capacitor Health plugin is available today to all Capawesome [Insiders](../../insiders/index.md) and requires Capacitor 8 or later. The subscription covers every other Insiders plugin as well, so there's no separate license to buy.

New plugins and notable releases are announced in the Capawesome newsletter first.

[Subscribe to the Capawesome Newsletter](https://capawesome.io/newsletter/){ .md-button .md-button--primary }

## Conclusion

Two health stores, one API, and no pretending they behave the same: that's the short version of the Capacitor Health plugin. The platform computes your aggregates and deduplicates your sources, the permission model reports what the operating systems actually expose, and the review requirements are documented next to the code they apply to.

**Further reading:**

- [Migrating from Google Fit to Health Connect in Capacitor](./google-fit-to-health-connect-migration-in-capacitor.md) — the shutdown timeline and a full data type mapping
- [API Reference](../../sdks/capacitor/health.md#api) — every method, option, and data type

**Missing a feature?** [Create a feature request](https://github.com/capawesome-team/capacitor-plugins/issues/new/choose){:target="_blank"} in our GitHub repository.

If you have any questions, join us on the [Capawesome Discord server](https://discord.gg/VCXxSVjefW){:target="_blank"}. To stay updated on the latest news, subscribe to the [Capawesome newsletter](https://capawesome.io/newsletter/){:target="_blank"}.
