Skip to main content
RapidDev - Software Development Agency
flutterflow-integrationsCustom Action (Dart)

HealthKit

Connect FlutterFlow to HealthKit by writing a Custom Action (Dart) that wraps the `health` pub.dev package. There is no HealthKit REST API — it is an on-device iOS framework. Your Custom Action calls `Health().requestAuthorization()` and `getHealthDataFromTypes()`, gated behind a `Platform.isIOS` check, and requires the HealthKit entitlement and NSHealthShareUsageDescription in your exported Xcode project.

What you'll learn

  • Why HealthKit has no REST API and why a Custom Action is the only FlutterFlow path
  • How to add the `health` package under Custom Code → Pubspec Dependencies
  • How to write a Dart Custom Action that requests HealthKit authorization and reads health data
  • How to enable the HealthKit capability and add required usage description strings to Info.plist in your exported Xcode project
  • How to guard your action with Platform.isIOS and test on a real iPhone
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced15 min read2-3 hoursHealth & FitnessLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to HealthKit by writing a Custom Action (Dart) that wraps the `health` pub.dev package. There is no HealthKit REST API — it is an on-device iOS framework. Your Custom Action calls `Health().requestAuthorization()` and `getHealthDataFromTypes()`, gated behind a `Platform.isIOS` check, and requires the HealthKit entitlement and NSHealthShareUsageDescription in your exported Xcode project.

Quick facts about this guide
FactValue
ToolHealthKit
CategoryHealth & Fitness
MethodCustom Action (Dart)
DifficultyAdvanced
Time required2-3 hours
Last updatedJuly 2026

HealthKit in FlutterFlow: What You Need to Know Before You Build

Every tutorial that tells you to create an API Call to HealthKit is wrong. HealthKit is an on-device iOS framework, not a cloud service — Apple deliberately designed it this way so health data never leaves the device without explicit user consent. There is no base URL, no API key, and no REST endpoint to configure in FlutterFlow's API Calls panel. The only way to access HealthKit from a FlutterFlow app is through a Custom Action that wraps the `health` pub.dev package, which acts as a Flutter/Dart bridge to the native iOS HealthKit APIs.

The good news is that this means there are no API keys to manage, no OAuth flows, and no billing. The `health` package is free and covers both HealthKit on iOS and Health Connect on Android under a single unified interface. For a FlutterFlow fitness app, you would write one Custom Action that requests authorization for the data types you need (steps, heart rate, sleep stages, workouts), then reads the data for a given date range — all from the user's device, instantly.

The important limitations: HealthKit Custom Actions do not work in FlutterFlow's web preview or Run mode at all — they will throw MissingPluginException. You need to export your project (requires FlutterFlow's Basic plan at $39/mo) or push to GitHub, then build and install on a real iPhone. You also need a paid Apple Developer account ($99/yr) and must enable the HealthKit entitlement in Xcode's Signing & Capabilities. These are real requirements, and they shape the build timeline — plan for them up front.

Integration method

Custom Action (Dart)

HealthKit has no REST API and no cloud endpoint — it is an on-device iOS framework accessed exclusively through Apple's HealthKit SDK. The only way to reach it from a FlutterFlow app is through a Custom Action wrapping the `health` pub.dev package, which bridges Flutter Dart code to the native HealthKit APIs on-device. This Custom Action requests user authorization, reads health data types (steps, heart rate, sleep, etc.), and returns the data to App State where FlutterFlow widgets can display it.

Prerequisites

  • FlutterFlow account on a paid plan (Basic or higher) for code export or GitHub integration
  • Paid Apple Developer account ($99/yr) to enable the HealthKit entitlement and sign the app
  • A real iPhone for testing — HealthKit Custom Actions will not work in FlutterFlow's web preview or Run mode
  • Basic familiarity with FlutterFlow's Custom Code panel for adding packages and writing Dart
  • Mac with Xcode installed for editing the exported project's Signing & Capabilities and Info.plist

Step-by-step guide

1

Add the `health` package to Pubspec Dependencies

In your FlutterFlow project, click Custom Code in the left navigation panel. At the top of the Custom Code screen, you will see a Pubspec Dependencies section — this is where you add pub.dev packages. Click the + button and type `health` in the package name field. Check pub.dev/packages/health for the current stable version (for example, `health: ^12.0.0`) and enter that version number. Click Save after adding the package. FlutterFlow automatically downloads and links the package into your project's dependency tree in the background — you do not need to run any terminal commands. Once saved, the `health` package will be available to import in any Custom Action or Custom Function you write. This single package covers both HealthKit on iOS and Health Connect on Android, so the same code supports both platforms when guarded with platform checks. If FlutterFlow shows a version conflict after adding the package, check whether other packages in your project depend on a different version of `health` and adjust the version pin to resolve it.

Pro tip: Pin an exact version in Pubspec Dependencies rather than a caret range to avoid unexpected breakage when a new major version ships while your app is in production.

Expected result: The `health` package appears in your Pubspec Dependencies list and the project builds without dependency errors in FlutterFlow's build panel.

2

Write the getHealthData Custom Action

Still in Custom Code, click + Add → Action and name it `getHealthData`. This action will do two things: request authorization for the health types you want to read, and then read the data for a given date range. In the action's Dart editor, import the package with `import 'package:health/health.dart';` and `import 'dart:io' show Platform;` and `import 'dart:convert';`. Configure the action to accept two DateTime arguments named `startDate` and `endDate`, and set the return type to String (a JSON-encoded list of data points, since FlutterFlow Custom Action return types are limited). Inside the action body, start with a platform guard: `if (!Platform.isIOS) return '[]';` — this prevents crashes on Android or web where HealthKit is unavailable. Then create a `Health()` instance, call `health.configure()`, define a list of the HealthDataType values you want (for example STEPS, HEART_RATE, SLEEP_ASLEEP, ACTIVE_ENERGY_BURNED), and call `await health.requestAuthorization(types)`. Check the returned boolean — if false, the user denied access, so return `'[]'` rather than crashing. If authorized, call `await health.getHealthDataFromTypes(startDate: startDate, endDate: endDate, types: types)` and convert the resulting list of HealthDataPoint objects into a list of maps using the `.map()` method, then JSON-encode it with `jsonEncode()` and return the string. Click Save in the Custom Code panel after writing and verifying the action.

custom_action.dart
1// custom_action.dart — getHealthData
2import 'package:flutter/material.dart';
3import 'package:health/health.dart';
4import 'dart:io' show Platform;
5import 'dart:convert';
6
7Future<String> getHealthData(
8 DateTime startDate,
9 DateTime endDate,
10) async {
11 // HealthKit is iOS-only
12 if (!Platform.isIOS) return '[]';
13
14 final health = Health();
15 health.configure();
16
17 final types = [
18 HealthDataType.STEPS,
19 HealthDataType.HEART_RATE,
20 HealthDataType.SLEEP_ASLEEP,
21 HealthDataType.ACTIVE_ENERGY_BURNED,
22 ];
23
24 // Request native Apple permission dialog
25 final authorized = await health.requestAuthorization(types);
26 if (!authorized) return '[]';
27
28 // Read data for the given date range
29 final dataPoints = await health.getHealthDataFromTypes(
30 startDate: startDate,
31 endDate: endDate,
32 types: types,
33 );
34
35 // Convert to JSON-encodable list
36 final result = dataPoints.map((dp) => {
37 'type': dp.typeString,
38 'value': dp.value.toString(),
39 'unit': dp.unitString,
40 'dateFrom': dp.dateFrom.toIso8601String(),
41 'dateTo': dp.dateTo.toIso8601String(),
42 }).toList();
43
44 return jsonEncode(result);
45}

Pro tip: Request only the health types your feature actually needs. Apple reviewers check that each type in your Info.plist authorization list is genuinely used in the app — requesting types you do not show to the user is a common App Store rejection reason.

Expected result: The Custom Action saves without Dart compilation errors and appears in your Actions list, ready to be used in the Action Flow Editor on any button or page event.

3

Enable the HealthKit entitlement and add Info.plist usage strings

This is the step most tutorials skip and the one that causes App Store rejections. FlutterFlow cannot set the HealthKit entitlement or add Info.plist usage description strings from within its visual interface — these are native iOS project settings that require the exported Xcode project. Export your project from FlutterFlow using the Export Code option in the top menu (requires the Basic plan at $39/mo) or push to GitHub via Settings → Integrations → GitHub and clone the repo. Open the `.xcworkspace` file in Xcode on a Mac. In Xcode, select your app target in the Project Navigator, then click the Signing & Capabilities tab. Click the + Capability button, search for HealthKit, and double-click to add it. This writes the HealthKit entitlement into your app's `.entitlements` file. Next, open `Info.plist` in Xcode (or in your code editor) and add the key `NSHealthShareUsageDescription` with a string value explaining in plain language why your app needs to read health data — for example: 'This app reads your step count, heart rate, and sleep to show your daily fitness summary.' If your app writes health data (saves workouts, etc.), also add `NSHealthUpdateUsageDescription` with an explanation. These strings appear verbatim in the iOS permission dialog that users see, so write them in clear, friendly language. Without NSHealthShareUsageDescription, HealthKit will crash when it tries to show the permission dialog and your app will be rejected from the App Store during review. After making these changes, build and run on your iPhone from Xcode to verify that the permission dialog appears with your usage strings.

Info.plist
1<!-- Add inside the <dict> tag in ios/Runner/Info.plist -->
2<key>NSHealthShareUsageDescription</key>
3<string>This app reads your step count, heart rate, and sleep data to show your daily fitness summary.</string>
4<key>NSHealthUpdateUsageDescription</key>
5<string>This app saves your workout sessions to Apple Health so you can track your fitness history.</string>

Pro tip: Every time you re-export your project from FlutterFlow, you may need to re-check that these Info.plist keys are still present. Keep a record of the exact strings you used so you can restore them quickly after each export.

Expected result: Xcode shows HealthKit under Signing & Capabilities for your target, and Info.plist contains both NSHealthShareUsageDescription and NSHealthUpdateUsageDescription. Building and running on iPhone shows the native Apple health permission dialog.

4

Trigger the action from a button and store results in App State

Back in FlutterFlow, create an App State variable to hold the health data. Open App State from the left panel and click + Add State Variable. Name it `healthDataJson`, set the type to String, and give it a default value of `'[]'`. Now place a button on your page (for example, labeled 'Sync Health Data') and open its Actions panel. In the Action Flow Editor, click + Add Action → Custom Action → getHealthData. Map the `startDate` argument: click the argument field, select From Variable, and use a DateTime value representing 7 days ago. You can compute this using a Custom Function that returns `DateTime.now().subtract(Duration(days: 7))` — create that function in Custom Code → Function first. Map `endDate` to Now (DateTime.now()). After the Custom Action, add a second action: Update App State → set `healthDataJson` to the return value of the Custom Action (available under Action Outputs in the variable picker). Add a Text widget bound to `healthDataJson` App State to confirm data is flowing. For a richer display, add a chart widget and configure it with parsed step values. Consider triggering this action On Page Load (in the page's Action Flow) so users see their stats as soon as the page opens, rather than having to tap a button every time. For date range selection, add a DateRangePicker widget and pass those DateTime values as arguments to the Custom Action instead of hardcoded dates.

Pro tip: Store the returned JSON string in App State and decode it once per session rather than re-reading HealthKit on every page navigation. This is gentler on device resources and feels faster to the user.

Expected result: Tapping the button stores a JSON string in the healthDataJson App State variable. The Text widget (or chart) on the page updates to reflect the health data returned from the Custom Action.

5

Test on a real iPhone — not in the web preview

HealthKit Custom Actions will not work in FlutterFlow's Run mode or any browser-based preview. When you tap your button in Run mode, the `Platform.isIOS` guard returns false (because the code is running in a web browser context) and the action returns an empty array — this is safe, intentional behavior, not a bug. To test the real HealthKit integration, you must build and install on a physical iPhone. Use option A: export your project from FlutterFlow and build from Xcode on a Mac with your paid Apple Developer account. Or use option B: push to GitHub via FlutterFlow's GitHub integration, clone the repo on a Mac, and run `flutter run` targeting your connected iPhone. Before testing, add some health data to the iPhone's Health app manually — go to Health app → Browse → Activity → Steps → Add Data — so the permission dialog has something to authorize and the data read has entries to return. On first launch, the native Apple health permission sheet will appear listing each health data type your action requests — tap Allow All. If you see no data returned after granting permission, check that the date range you passed covers days that have health data recorded. If you see MissingPluginException in the Xcode console even on a real device, clean the Xcode build folder (Product → Clean Build Folder) and rebuild.

Pro tip: To reset health permissions and test the first-run experience again during development, go to iPhone Settings → Privacy & Security → Health → your app name and turn off all permissions.

Expected result: The app on a real iPhone shows the native HealthKit permission dialog on first run. After the user taps Allow, the health data (steps, heart rate, sleep) appears in the FlutterFlow UI widgets on the page.

Common use cases

Daily step counter and activity dashboard

Build a fitness app that reads the user's step count, active energy burned, and exercise minutes from HealthKit each morning and displays them in a colorful dashboard with FlutterFlow chart widgets. Users grant permission once through the native Apple permission dialog, and the app reads data silently on each open.

FlutterFlow Prompt

A screen that shows today's step count, heart rate, and calories burned from HealthKit, with a line chart showing steps over the last 7 days

Copy this prompt to try it in FlutterFlow

Sleep tracking journal

Create a sleep journal app that reads sleep analysis data from HealthKit for the past 30 nights, displays an average sleep duration, and lets users add personal notes against each night. All data lives on-device — no backend is needed for the core feature.

FlutterFlow Prompt

A sleep tracker page that pulls the last 30 days of HealthKit sleep data, shows average hours per night in a bar chart, and lets the user add a text note for each night

Copy this prompt to try it in FlutterFlow

Heart rate and workout summary

Build a post-workout summary screen that reads heart rate samples from the last workout session in HealthKit, calculates average and peak heart rate, and displays a summary card. Integrates naturally with Apple Watch data stored in the Health app.

FlutterFlow Prompt

A workout summary page that reads heart rate data from the last hour in HealthKit and displays min, average, and max bpm alongside a sparkline chart

Copy this prompt to try it in FlutterFlow

Troubleshooting

MissingPluginException or empty data in FlutterFlow's Run mode / web preview

Cause: HealthKit is an on-device iOS framework. FlutterFlow's web preview and Run mode execute the app in a browser environment where native iOS plugins cannot run. The Platform.isIOS guard returns false, and the plugin itself is not linked in the browser context.

Solution: This is expected behavior — do not use the web preview to test HealthKit. Build and install on a real iPhone via the exported Xcode project or the GitHub integration. For non-iOS testers, the Platform.isIOS guard returns an empty array gracefully without crashing.

Health permission dialog never appears after calling requestAuthorization

Cause: The HealthKit entitlement is missing from the app target's Signing & Capabilities in Xcode, or NSHealthShareUsageDescription is absent or empty in Info.plist. iOS requires both before HealthKit will display the permission dialog.

Solution: Open the exported Xcode project, select your app target → Signing & Capabilities → + Capability → HealthKit. Confirm that Info.plist contains NSHealthShareUsageDescription with a non-empty string. Rebuild and reinstall on the iPhone.

getHealthDataFromTypes returns an empty list even though Health app has data

Cause: The startDate and endDate passed to the action may not overlap with existing health records, or the user did not grant authorization for the specific HealthDataType being requested. Older iPhones with limited data or simulators with no data also cause this.

Solution: Verify your date range covers days with recorded data. Open the iPhone Health app → Browse → Activity → Steps to confirm data exists in that range. Check iPhone Settings → Privacy & Security → Health → your app to ensure all requested types are authorized. Test on a real device that has been tracking health data actively.

App Store rejection: app requests HealthKit permissions but the purpose is not clear

Cause: Apple reviewers found that NSHealthShareUsageDescription does not clearly explain how the health data is used, or that the app requests more health types than it visibly uses in its UI.

Solution: Update NSHealthShareUsageDescription to specifically name each feature that uses health data. Remove any HealthDataType values from the requestAuthorization list that are not displayed or used. Include screenshots showing health data in context in your App Review Information notes.

Best practices

  • Always guard HealthKit calls with `if (!Platform.isIOS) return;` — the `health` package supports Android Health Connect too, but HealthKit itself is iOS-only and will crash without this guard
  • Request only the minimum set of health types your feature actually needs — Apple reviews each type in your NSHealthShareUsageDescription and authorization list
  • Always page health data by day or week rather than requesting all-time data — heavy Health stores can make all-time reads extremely slow
  • Document the HealthKit entitlement and Info.plist changes in your project README so they are restored correctly after every FlutterFlow re-export
  • Always test on a real iPhone with actual health data — the iOS Simulator has limited Health support and FlutterFlow's web preview cannot run HealthKit at all
  • Show users a brief explanation of why you need each health type before triggering the permission dialog — users who understand the value are far more likely to tap Allow
  • Store the JSON returned by your Custom Action in App State and parse it once per session rather than querying HealthKit on every screen navigation

Alternatives

Frequently asked questions

Can I connect FlutterFlow to HealthKit without exporting the Xcode project?

Not completely. You can write and save the Dart Custom Action within FlutterFlow's interface, but the HealthKit entitlement and NSHealthShareUsageDescription must be set in the native Xcode project. This requires FlutterFlow's Basic plan ($39/mo) for code export, or the GitHub integration to clone and edit the native iOS project files. There is no way to set Xcode entitlements from within FlutterFlow's visual editor.

Does HealthKit work in FlutterFlow's Run mode or web preview?

No. HealthKit is an on-device iOS framework and cannot run in a browser. FlutterFlow's Run mode executes the app in a web context where native iOS plugins are unavailable. Any HealthKit Custom Action will return empty data or throw MissingPluginException in preview. Always test on a real iPhone built from the exported Xcode project or the GitHub integration.

Can I use the same `health` package for both iOS HealthKit and Android Health Connect?

Yes. The `health` pub.dev package is a unified wrapper covering both HealthKit on iOS and Health Connect on Android under a shared API surface. Use Platform.isIOS and Platform.isAndroid guards in your Custom Action to route to the appropriate platform. Android requires Health Connect permission declarations in AndroidManifest.xml rather than Info.plist — see the google-fit page for Android-specific steps.

Do I need a paid Apple Developer account to use HealthKit?

Yes. The HealthKit entitlement requires a paid Apple Developer membership ($99/yr). Free Apple IDs cannot enable HealthKit in Xcode's Signing & Capabilities, and apps without the entitlement will silently fail HealthKit permission requests at runtime. The paid account is also required to distribute on the App Store.

Is it safe to store health data in Firestore or Supabase from the Custom Action?

Yes, but be mindful of privacy: health data is sensitive personal information. If you send HealthKit data to your backend (for example, to sync across devices), ensure your Firestore or Supabase tables have row-level security rules so users can only access their own health records. Only store data the user has explicitly agreed to share, and document the data use clearly in your privacy policy.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire FlutterFlow integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.