I need to be able to create and store a HeartbeatSeries for a given time-period from an Apple Watch, to then retrieve that data from HealthKit to be processed.
I have working code which allows me to begin a workout session, which is being used to determine how long a session has been running for. I also have working code for retrieving HeartbeatSeries data from HealthKit.
The issue is that no HeartbeatSeries data is being stored into HealthKit as a result of the workout session running. Whether that session is running for as little as 30 seconds or as long as 20 minutes, nothing is stored.
However, when I use the the Apple "Meditation" app (formerly known as "Breathe"), I can query HealthKit afterwards and retrieve a list of individual heartbeat timings during that 2 minute period.
Therefore, it IS possible to store a HeartbeatSeries from within an app on the Apple Watch.
What I would like to know is, how can I use the pulse sensor built-in to the Apple Watch to be able to record a HeartbeatSeries similar to how the Meditation app does it.
HealthKit
RSS for tagAccess and share health and fitness data while maintaining the user’s privacy and control using HealthKit.
Posts under HealthKit tag
109 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi everyone!
I'm trying to get the total sleep time for a given day, but users report that there's a difference between what my app reports and what the Apple Health app reports. In particular, we're off by 2 minutes less on average.
What we're doing is:
Get all the samples that are either core, deep, rem or unspecified
Cut-off time at 3 PM previous day
Merge overlapping intervals
Add all the remaining intervals
For debugging purposes I'm storing and sending all the raw samples to a server, and I have run tests and I don't find anything wrong. It looks like the number we come up with is correct according to our own rules. I wonder, how is Apple adding up all the samples to arrive at a number that's slightly off to our number.
Any insight would be appreciated. Thanks.
This is an ongoing issue that I haven't been able to solve:
I am querying different types of HealthKit data over the past year. While this works fine for HRV, it hangs for some users when I'm trying to get heart rate data.
Here's the relevant query
func initialRead(from startDate: Date) async throws -> [HKSample] {
let endDate = anchorStart
let interval: TimeInterval = .days(7)
var currentStartDate = startDate
var currentEndDate = Date(timeInterval: interval, since: currentStartDate)
var samples: [HKSample] = []
while currentStartDate <= endDate {
let datePredicate = SampleType.datePredicate(start: currentStartDate, end: currentEndDate)
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [datePredicate,HKQuery.predicateForObjects(withMetadataKey: HKMetadataKeyHeartRateMotionContext, allowedValues: [HKHeartRateMotionContext.sedentary])])
do {
let result = try await withCheckedThrowingContinuation { continuation in
let completionQuery = HKSampleQuery(sampleType: HKQuantityType.heartRate, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: [.init(key: HKSampleSortIdentifierStartDate, ascending: true)]) { query, samples, error in
if let samples {
continuation.resume(returning: samples)
} else {
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume(returning: [])
}
}
}
healthStore.execute(completionQuery)
}
samples = samples.merge(from: result)
} catch {
Logger.general.error("Reading failed for dates \(currentStartDate) to \(currentEndDate): \(error)")
}
currentStartDate = currentEndDate
currentEndDate = Date(timeInterval: interval, since: currentStartDate)
}
return samples
}
extension HKSampleType {
static func datePredicate( start:Date?, end:Date?) -> NSPredicate {
HKQuery.predicateForSamples(withStart: start, end:end, options: .strictStartDate)
}
}
For reference, I expect about 1000 sedentary samples per week. Basically what happens for these users is when they start reading the HR data, the app hangs. They start each read manually via a special TestFlight build with buttons for starting the different data type readings.
Any advice on how to proceed with this bug would be great since it only affects some users.
I am able to create test builds for this audience to test different options. One theory is the motion context predicate is screwing something up. If any apple dev can enlighten me how to narrow down the issue, that would be great.
I implemented this to receive updates for specific data types and keep the latest daily information up to date. However, for some reason, it only works for a while before stopping completely.
Background Delivery
internal func backgroundDeliveryForReadTypes(enable: Bool, types: Set<HKQuantityType>) async {
do {
if enable {
try await statusForAuthorizationRequest(toWrite: [], toRead: types)
for type in types {
try await healthStore.enableBackgroundDelivery(for: type, frequency: .daily)
}
} else {
for type in types {
try await healthStore.disableBackgroundDelivery(for: type)
}
}
} catch {
debugPrint("Error enabling background delivery: \(error.localizedDescription)")
}
}
HKQueryAnchor
internal var walkingActivityQueryAnchor: HKQueryAnchor? {
get {
if let anchorData = UserDefaults.standard.data(forKey: "walkingActivityAnchor") {
return try? NSKeyedUnarchiver.unarchivedObject(ofClass: HKQueryAnchor.self, from: anchorData)
}
return nil
}
set {
if let newAnchor = newValue {
let anchorData = try? NSKeyedArchiver.archivedData(withRootObject: newAnchor, requiringSecureCoding: true)
UserDefaults.standard.set(anchorData, forKey: "walkingActivityAnchor")
} else {
UserDefaults.standard.removeObject(forKey: "walkingActivityAnchor")
}
}
}
HKAnchoredObjectQuery
internal func observeWalkingActivityInBackground(
_ start: Bool,
toRead: Set<HKQuantityType>,
completion: @escaping @Sendable (Result<WalkingActivityData?, Error>) -> Void
) {
if start {
guard (walkingActivityQuery == nil) else {
return
}
let predicate = getPredicate(date: Date())
let queryDescriptors = toRead.map {
HKQueryDescriptor(sampleType: $0, predicate: predicate)
}
let handleSamples: @Sendable (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void = { [weak self] _, samples, _, newAnchor, error in
guard let self = self else { return }
if let error = error {
completion(.failure(error))
return
}
guard let samples = samples, !samples.isEmpty else {
completion(.success(nil))
return
}
Task {
self.walkingActivityQueryAnchor = newAnchor
let activity = await self.getWalkingActivity(date: Date())
completion(.success(activity))
}
}
let query = HKAnchoredObjectQuery(
queryDescriptors: queryDescriptors,
anchor: walkingActivityQueryAnchor,
limit: HKObjectQueryNoLimit,
resultsHandler: handleSamples
)
query.updateHandler = handleSamples
healthStore.execute(query)
walkingActivityQuery = query
} else {
if let query = walkingActivityQuery {
healthStore.stop(query)
walkingActivityQuery = nil
}
}
}
WalkingActivityData
private func getWalkingActivity(date: Date) async -> WalkingActivityData {
async let averageHeartRate = try await self.getAverageHeartRate(date: date)
async let steps = try self.getStepCount(date: date)
async let durationMinutes = try self.getTotalDurationInMinutes(date: date)
async let distanceMeters = try self.getDistanceWalkingRunning(date: date, unit: .meter())
async let activeCalories = try self.getActiveEnergyBurned(date: date)
return await WalkingActivityData(
date: date,
steps: try? steps,
activeCalories: try? activeCalories,
distanceMeters: try? distanceMeters,
durationMinutes: try? durationMinutes,
averageHeartRate: try? averageHeartRate
)
}
Example of getAverageHeartRate
func getAverageHeartRate(date: Date) async throws -> Double? {
let type = HKQuantityType(.heartRate)
_ = try checkAuthorizationStatus(for: type)
guard let heartRate = try await getDescriptor(
date: date,
type: type,
options: .discreteAverage
).result(for: healthStore)
.statistics(for: date)?
.averageQuantity()?.doubleValue(for: HKUnit.count().unitDivided(by: HKUnit.minute()))
else {
return nil
}
return Double(String(format: "%.2f", heartRate)) ?? 0.0
}
Descriptor & predicate
internal func getPredicate(startDate: Date, endDate: Date) -> NSCompoundPredicate {
let predicateForSamples = HKQuery.predicateForSamples(withStart: startDate, end: endDate)
let excludeManual = NSPredicate(format: "metadata.%K != YES", HKMetadataKeyWasUserEntered)
return NSCompoundPredicate(andPredicateWithSubpredicates: [predicateForSamples, excludeManual])
}
internal func getDescriptor(startDate: Date, endDate: Date, type: HKQuantityType, options: HKStatisticsOptions) -> HKStatisticsCollectionQueryDescriptor {
let calendar = Calendar(identifier: .gregorian)
let anchorDate = calendar.date(bySetting: .hour, value: 0, of: startDate)!
var interval = DateComponents()
interval.day = 1
return HKStatisticsCollectionQueryDescriptor(
predicate: HKSamplePredicate.quantitySample(type: type, predicate: getPredicate(startDate: startDate, endDate: endDate)),
options: options,
anchorDate: anchorDate,
intervalComponents: interval
)
}
Implementation
public func observeWalkingActivityInBackground(_ start: Bool, toRead: Set<HKQuantityType>, memberID: String) {
observeWalkingActivityInBackground(start, toRead: toRead) { [weak self] result in
guard let self = self else { return }
}
}
I have an App in objective-c that is using Health data (walk/run, cycling) to give advice to users . I do not want/need to write any data in the Healtkit.
If i do (with the 3 values in the plist / .info :
self.healthStore requestAuthorizationToShareTypes:nil readTypes:readDataTypes
My request crashes.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Must request authorization for at least one data type'
*** First throw call stack:
(
0 CoreFoundation 0x00000001804b910c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x0000000180092da8 objc_exception_throw + 72
2 CoreFoundation 0x00000001804b901c -[NSException initWithCoder:] + 0
3 HealthKit 0x000000019da034d4 -[HKHealthStore _validateAuthorizationRequestWithShareTypes:readTypes:] + 92
4 HealthKit 0x000000019da03670 -[HKHealthStore requestAuthorizationToShareTypes:readTypes:shouldPrompt:completion:] + 292
BUT in swift :
healthStore.requestAuthorization(toShare: nil, read: readTypes)
is working, présents only my 2 datas to read... in the same IOS , same phone without crashing. What is the difference ?
Nil object in objective-c and Nil object in swift are not the same ? how do i make readonly requests in objective C ?
I’m trying to associate heart rate (HR) data with a mindfulness session (HKCategoryTypeIdentifier.mindfulSession) in HealthKit, but I can’t find any documentation on how to do this.
I’ve seen third-party apps (like Medito) successfully log HR within Mindful Minutes, even when the session takes place on an iPhone (not an Apple Watch). However, when I try saving HR in the metadata, it does not appear in the Health app's Mindful Minutes section.
Code snippet:
func logMindfulnessSession(start: Bool, heartRate: Double? = nil) {
let mindfulType = HKCategoryType.categoryType(forIdentifier: .mindfulSession)!
let now = Date()
let endTime = now.addingTimeInterval(Double(selectedDuration))
var metadata: [String: Any]? = nil
if let hr = heartRate {
let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
let hrQuantity = HKQuantity(unit: heartRateUnit, doubleValue: hr)
metadata = ["heartRate": hrQuantity] // ❓ Is there a correct key for HR?
}
let sample = HKCategorySample(
type: mindfulType,
value: 0,
start: now,
end: endTime,
metadata: metadata
)
healthStore.save(sample) { success, error in
if let error = error {
print("HealthKit session save error: \(error.localizedDescription)")
} else {
print("Mindfulness session saved successfully.")
if let hr = heartRate {
print("Saved with HR: \(hr) BPM")
}
}
}
}
Questions:
What is the correct metadata key for associating heart rate with a mindful session?
Does HealthKit require a specific format (e.g., HKQuantitySample) for HR?
0 Are there additional permissions needed to allow HR to appear in Mindful Minutes?
Does HR need to be stored separately in HKQuantityTypeIdentifier.heartRate, and if so, how do third-party apps ensure it appears in the same entry as the mindful session?
thank you!
The background deliver works perfectly when the app is in the background or suspended states. However, when the app is killed (terminated state), the background task does not execute
Platform & Version:
iOS Version: 18.3.1
Development Environment: Xcode 16.2, macOS 14.6.1
Description of the Issue:
We're exploring ways to better integrate Apple Fitness+ workouts into our app. We've noticed that some third-party apps, such as Strava and HealthFit, now display Fitness+ workout details, including the title, trainer, and an image.
I’ve been investigating how this is possible, and the only relevant change I’ve found is that HKMetadataKeyAppleFitnessPlusCatalogIdentifier is now being set for Fitness+ workouts. However, I can’t find any public API or official documentation that explains how to use these identifiers to retrieve the associated workout details.
Question:
Is there an official API available to fetch metadata for Fitness+ workouts using these identifiers? Or are these third-party apps potentially accessing private APIs? If no API exists, is the only option to create a manual mapping of these identifiers—something that seems impractical given the constantly evolving Fitness+ workout catalog?
Any guidance on this would be greatly appreciated. Thanks!
Topic:
App & System Services
SubTopic:
Health & Fitness
Tags:
Health and Fitness
HealthKit
WorkoutKit
Apple Watch automatically tracks sleep data and syncs it to the iPhone, making it available through HealthKit for historical analysis. However, there is no way to retrieve real-time data on whether a user has entered sleep, or whether they are in a specific sleep stage at any given moment.
Is it possible to provide an interface for real-time sleep status monitoring
Dear Apple Developer Support,
I am writing to request assistance with an ongoing issue I'm encountering while developing an iOS application that utilizes HealthKit to fetch heart rate data.
My goal is to display near real-time heart rate updates continuously same as displaying in the Apple Watch , I want to show in the iPhone Mobile Application for fitness related. I have implemented the following approaches:
HKSampleQuery with a Timer: I've set up a timer to periodically fetch the latest heart rate data.
Despite these efforts, I'm consistently facing the following problems:
Delayed Updates: The heart rate data displayed in the app often doesn't reflect the current heart rate being measured by the Apple Watch. There seems to be a significant synchronization delay.
Inconsistent Background Updates: Background updates, even with background app refresh enabled, are not reliable. The app often only updates when brought to the foreground or after being killed and relaunched.
Entitlements: The com.apple.developer.healthkit.background-delivery entitlement error is missing.
I have thoroughly reviewed Apple's HealthKit documentation, implemented best practices for HealthKit integration, and verified that all necessary permissions are properly configured.
I understand that HealthKit may not be designed for true real-time data, but the current level of delay and inconsistency is making it difficult to provide a useful user experience.
Could you please provide guidance on whether achieving near real-time heart rate updates continuously in an iOS app using HealthKit is possible? If so, what are the recommended strategies and best practices to overcome these limitations?
I have also tested the application on physical devices with Apple Watch, enabled background app refresh, granted permissions, and referred to HealthKit documentation.
I would appreciate any insights or suggestions you can offer to help resolve this issue.
Thank you for your time and assistance.
Sincerely,
Venu Madhav
I would like to get user's heart rate zones values in my watchOS app, is there any way to get it from HealthKit?
Furthermore, is it possible to display the Apple heart rate zones widget in my watchOS app?
From the date the app was updated, the step count data retrieved from HealthKit was strange. On the other hand, step count data from the date before the update is imported normally.
After deleting and reinstalling the app, the problem did not occur.
Is there anyone who has experienced something like this or knows the cause?
Is it possible to develop the following app? The app will measure heart rate variability five times at 2-minute intervals triggered by an event and output the values.
Hello,
I am building a workout app that has an option to add segments to differentiate different stages of the training session. Segments are added the following way:
func saveSegment(eventType: HKWorkoutEventType, startDate: Date, endDate: Date, inSeg: Int) async throws {
let dateInterval = DateInterval(start: startDate, end: endDate)
let event = HKWorkoutEvent(type: eventType, dateInterval: dateInterval, metadata: metadata)
try await builder?.addWorkoutEvents([event])
}
Inside Health -> Workouts -> Show All Data, the segments appear, but in Fitness app there are no segments. The workout is .paddleSports. I thought that maybe the workout type was the problem, but when I start the sessions from the native workout app, segments are added and shown in the Fitness app:
In other posts I saw suggested to add an event as .marker instead of .segment, but the result is the same, it does not appear.
Is there something I am doing wrong? How can I show the segments into the Fitness app?
Another question, I would like to add stroke rate and stroke count to my paddling session, is there a way to add it? Paddle Sports workout was recently introduced and it would be great to have the option to add those values.
Thank you in advance.
Inaki
In the fitness app under iOS 18, the location of all workouts is displayed on a small map.
For workouts with routes, I can already successfully read out the route and thus also determine the starting point. So that works.
For indoor workouts such as yoga or indoor rowing, the exact location is also displayed in the fitness app. I would now also like to read out this location for these indoor workouts in my app.
Does anyone know how to do this?
I am working on an Apple Watch companion app to an existing live iOS app. I am utilizing the heart rate tracking for an active 'self-care' sauna session. I say self-care in quotes because it's more self-care than a workout activity, but it is closely blurring the lines between the two.
I have come to understand that if a session truly isn't a workout, then you should not use workoutSession.startActivity. However the app needs to function entirely like a workout would. This is not a meditation application. Sauna is actually just one of many activity types supported in the app.
I have tried using extended runtime session, and there have been numerous issues with doing so. It is not nearly as robust for the user. For example, the active session is not prioritized by the watch's CPU. Now playing is no longer functional. Heart rate is far more inconsistent, and this variable is as critical as if it were in a workout.
I have tried using HKWorkoutSession, however I worry the app will be rejected by doing so. This method works most accurately to collect the right data for the user, and prioritizes system resources as expected. The app can be moved to the background as expected and continue to communicate with the iOS app.
What is the best way to move forward here. It almost feels like I am operating in a grey area with no real solution in place. Any assistance is greatly appreciated as we would like to follow all guidelines while producing a high quality experience for our users.
Hello. I am building an app that shows my walk workouts and in the detail view I want to show the route I took while walking, similar to that of the Apple Fitness App. There is a problem though, I cannot seem to understand how to connect the @State property workoutLocations array that would be used to draw the route on the map with what I get from the query. The task does successfully fetches the data but then when I try to use it later in a do-catch block nothing happens. What am I missing here?
import SwiftUI
import MapKit
import HealthKit
struct DetailView: View {
@Environment(HealthKitManager.self) var healthKitManager
let workout: HKWorkout
@State private var workoutLocations: [CLLocation] = []
var body: some View {
ScrollView {
//...
}
.task {
guard let store = self.healthKitManager.healthStore else {
fatalError("healthStore is nil. App is in invalid state.")
}
let walkingObjectQuery = HKQuery.predicateForObjects(from: workout)
let routeQuery = HKAnchoredObjectQueryDescriptor(predicates: [.workoutRoute(walkingObjectQuery)], anchor: nil)
let queryResults = routeQuery.results(for: store)
let task = Task {
var workoutRouteLocations: [CLLocation] = []
for try await result in queryResults {
let routeSamples = result.addedSamples
for routeSample in routeSamples {
let routeQueryDescriptor = HKWorkoutRouteQueryDescriptor(routeSample)
let locations = routeQueryDescriptor.results(for: store)
for try await location in locations {
workoutRouteLocations.append(location)
print(workoutRouteLocations.count) // this prints out the number of locations in the sample.
}
}
}
return workoutRouteLocations
}
do {
print(try await task.value.count) // this prints nothing. Therefore if I try to update workoutLocations array from here it would do nothing as well
// workoutLocations = try await task.value therefore does nothing and the array just doesn't get populated with the results of the task
} catch {
print(error)
}
}
}
}
Hello,
My app syncs workout data from a third-party device and records workouts with HealthKit as follows:
let builder = HKWorkoutBuilder(healthStore: healthStore, configuration: hkConf, device: hkDevice)
try await builder.beginCollection(at: startDate)
try await builder.addSamples(samples)
try await builder.endCollection(at: endDate)
let workout = try await builder.finishWorkout()
let workoutRouteBuilder = HKWorkoutRouteBuilder(healthStore: healthStore, device: hkDevice)
try await workoutRouteBuilder.insertRouteData(filteredLocations)
try await workoutRouteBuilder.finishRoute(with: workout, metadata: nil)
However, I’m encountering two issues:
The workouts appear in Apple Fitness but do not contribute to the activity rings.
The workout includes a route (visible in the raw workout data in Apple Health) but does not display on Apple Fitness.
Is there any way to fix this? I’d appreciate any suggestions you might have.
__
I am working on a Smart Alarm app for Watch OS.
When testing on an Series 10 watch, I am successfully able to read heart rate data in the ExtendedRuntimeSession. However, although the calls succeed, the sleep analysis data is all 0.
The app successfully gets authorization for:
[HKQuantityType(.heartRate), HKObjectType.categoryType(forIdentifier: .sleepAnalysis)!]
I have read that sleep data is not available for less than an hour time period. The Smart Alarm extended session has a 30 minute limit.
Does that mean it is not possible to read sleep analysis data in a Smart Alarm extended session?
Thank you!
Hello,
I am currently working on an app that uses HealthKit to sync health data to a backend server that performs analysis on this data. I am keeping track of the synced data with the HKQueryAnchor I receive for each query I make.
I want to address an edge case: if a user has multiple devices running the app, would it make sense to store the anchor on my backend? This would ensure that other instances of the app do not sync data that has already been synced from another device.
Thank you for your help!