Documentation Index
Fetch the complete documentation index at: https://mintlify.com/kingstinct/react-native-healthkit/llms.txt
Use this file to discover all available pages before exploring further.
Background delivery allows your app to receive notifications when health data changes, even when your app isn’t running. This enables your app to stay up-to-date with the latest health information without requiring users to open your app.
How background delivery works
When you enable background delivery for a data type, HealthKit monitors that data and notifies your app when new samples are added or existing samples are deleted. Your app is launched in the background to process these changes.
Background delivery notifications are not real-time. HealthKit batches notifications to conserve battery life, and the system determines when to deliver them based on various factors.
Update frequencies
You can specify how frequently you want to receive updates:
enum UpdateFrequency {
immediate = 1, // As soon as possible (still not real-time)
hourly = 2, // Once per hour
daily = 3, // Once per day
weekly = 4 // Once per week
}
Enabling background delivery
Before enabling background delivery, you must:
- Request authorization for the data type
- Enable the HealthKit background capability in your app
Basic setup
import {
enableBackgroundDelivery,
UpdateFrequency
} from '@kingstinct/react-native-healthkit';
// First, request authorization
await requestAuthorization({
toRead: ['HKQuantityTypeIdentifierStepCount']
});
// Then enable background delivery
const success = await enableBackgroundDelivery(
'HKQuantityTypeIdentifierStepCount',
UpdateFrequency.immediate
);
if (success) {
console.log('Background delivery enabled');
}
Subscribing to changes
After enabling background delivery, subscribe to changes:
import { subscribeToChanges } from '@kingstinct/react-native-healthkit';
const subscription = subscribeToChanges(
'HKQuantityTypeIdentifierStepCount',
(args) => {
console.log('Step count data changed!');
// Fetch the latest data
fetchLatestSteps();
}
);
// When done, unsubscribe
subscription.remove();
Using the hook
For React components, use useSubscribeToChanges:
import { useSubscribeToChanges, useMostRecentQuantitySample } from '@kingstinct/react-native-healthkit';
function StepsWidget() {
const [refreshKey, setRefreshKey] = useState(0);
// Subscribe to changes
useSubscribeToChanges('HKQuantityTypeIdentifierStepCount', () => {
setRefreshKey(prev => prev + 1);
});
// This will re-fetch when refreshKey changes
const steps = useMostRecentQuantitySample(
'HKQuantityTypeIdentifierStepCount',
{ refreshKey }
);
return <Text>{steps?.quantity} steps</Text>;
}
Background capability
To receive background notifications, you must enable the HealthKit background mode in Xcode:
- Open your project in Xcode
- Select your app target
- Go to “Signing & Capabilities”
- Add “Background Modes” capability
- Check “Background fetch”
Expo configuration
For Expo apps, add this to your app.json:
{
"expo": {
"plugins": [
["@kingstinct/react-native-healthkit", {
"background": true
}]
],
"ios": {
"infoPlist": {
"UIBackgroundModes": ["fetch"]
}
}
}
}
Subscribing to multiple types
You can enable background delivery for multiple data types:
const dataTypes = [
'HKQuantityTypeIdentifierStepCount',
'HKQuantityTypeIdentifierHeartRate',
'HKQuantityTypeIdentifierActiveEnergyBurned'
] as const;
// Enable background delivery for all types
for (const type of dataTypes) {
await enableBackgroundDelivery(type, UpdateFrequency.immediate);
}
// Subscribe to all types
const subscriptions = dataTypes.map(type =>
subscribeToChanges(type, () => {
console.log(`${type} changed`);
// Handle the change
})
);
// Later, unsubscribe from all
subscriptions.forEach(sub => sub.remove());
Handling changes efficiently
When a change notification arrives, fetch only the new data using anchors:
import { queryQuantitySamplesWithAnchor } from '@kingstinct/react-native-healthkit';
let currentAnchor: string | undefined;
subscribeToChanges('HKQuantityTypeIdentifierStepCount', async () => {
const result = await queryQuantitySamplesWithAnchor(
'HKQuantityTypeIdentifierStepCount',
{
anchor: currentAnchor,
limit: 0 // 0 means no limit
}
);
// Process new samples
console.log(`New samples: ${result.samples.length}`);
console.log(`Deleted samples: ${result.deletedSamples.length}`);
// Update anchor for next time
currentAnchor = result.newAnchor;
// Store the anchor persistently
await AsyncStorage.setItem('stepCountAnchor', currentAnchor);
});
Disabling background delivery
When you no longer need background updates:
Disable for a specific type
import { disableBackgroundDelivery } from '@kingstinct/react-native-healthkit';
const success = await disableBackgroundDelivery(
'HKQuantityTypeIdentifierStepCount'
);
Disable all background delivery
import { disableAllBackgroundDelivery } from '@kingstinct/react-native-healthkit';
const success = await disableAllBackgroundDelivery();
Best practices
Clean up subscriptions
Always clean up subscriptions when components unmount:
useEffect(() => {
const subscription = subscribeToChanges(
'HKQuantityTypeIdentifierStepCount',
handleChange
);
return () => {
subscription.remove();
};
}, []);
Use appropriate update frequencies
Choose update frequencies based on your use case:
// Real-time monitoring (e.g., workout apps)
await enableBackgroundDelivery(
'HKQuantityTypeIdentifierHeartRate',
UpdateFrequency.immediate
);
// Daily summaries (e.g., step tracking)
await enableBackgroundDelivery(
'HKQuantityTypeIdentifierStepCount',
UpdateFrequency.daily
);
// Weekly reports (e.g., weight tracking)
await enableBackgroundDelivery(
'HKQuantityTypeIdentifierBodyMass',
UpdateFrequency.weekly
);
Minimize background processing
Keep background work minimal to avoid being throttled:
subscribeToChanges('HKQuantityTypeIdentifierStepCount', async () => {
// Good - quick, focused update
const latest = await getMostRecentQuantitySample('HKQuantityTypeIdentifierStepCount');
await updateLocalCache(latest);
});
// Avoid - too much processing in background
subscribeToChanges('HKQuantityTypeIdentifierStepCount', async () => {
const allData = await queryQuantitySamples('HKQuantityTypeIdentifierStepCount', {
from: new Date(0),
limit: 10000
});
await processAllData(allData); // Too slow!
});
Handle authorization carefully
Background delivery only works with authorized data types:
// Request authorization first
const success = await requestAuthorization({
toRead: ['HKQuantityTypeIdentifierStepCount']
});
if (success) {
// Then enable background delivery
await enableBackgroundDelivery(
'HKQuantityTypeIdentifierStepCount',
UpdateFrequency.immediate
);
} else {
console.log('Authorization denied - background delivery not enabled');
}
Store anchors persistently
Persist anchors so you don’t miss changes between app launches:
import AsyncStorage from '@react-native-async-storage/async-storage';
// On app launch, restore anchor
const storedAnchor = await AsyncStorage.getItem('stepCountAnchor');
let currentAnchor = storedAnchor || undefined;
subscribeToChanges('HKQuantityTypeIdentifierStepCount', async () => {
const result = await queryQuantitySamplesWithAnchor(
'HKQuantityTypeIdentifierStepCount',
{ anchor: currentAnchor, limit: 0 }
);
// Update and persist anchor
currentAnchor = result.newAnchor;
await AsyncStorage.setItem('stepCountAnchor', currentAnchor);
});
Limitations
Background delivery has several important limitations:
- Not real-time - Notifications are batched and may be delayed by minutes or hours
- System discretion - iOS decides when to deliver notifications based on battery, usage patterns, etc.
- App termination - If the user force-quits your app, background delivery stops until the app is launched again
- Power management - Background activity is throttled when battery is low
- Data privacy - Background delivery only works for data types you’re authorized to read
Testing background delivery
Background delivery can be difficult to test. Here are some tips:
-
Use immediate frequency during development:
await enableBackgroundDelivery(type, UpdateFrequency.immediate);
-
Add logging to verify notifications:
subscribeToChanges(type, () => {
console.log('[Background] Data changed:', new Date().toISOString());
});
-
Manually add data in the Health app to trigger notifications
-
Check Xcode console for background launch messages
-
Be patient - it may take several minutes for the first notification
enableBackgroundDelivery() - Enable background delivery for a type
disableBackgroundDelivery() - Disable background delivery for a type
disableAllBackgroundDelivery() - Disable all background delivery
subscribeToChanges() - Subscribe to data changes
useSubscribeToChanges() - Hook for subscribing to changes
queryQuantitySamplesWithAnchor() - Query new data efficiently