How to monitor heart rate in background without affecting Activity Rings?

I'm developing a watchOS nap app that detects when the user falls asleep by monitoring heart rate changes.

== Technical Implementation ==

  • HKWorkoutSession (.mindAndBody) for background execution
  • HKAnchoredObjectQuery for real-time heart rate data
  • CoreMotion for movement detection

== Battery Considerations ==

  • Heart rate monitoring ONLY active when user explicitly starts a session
  • Monitoring continues until user is awakened OR 60-minute limit is reached
  • If no sleep detected within 60 minutes, session auto-ends (user may have abandoned or forgotten to stop)
  • App displays clear UI indicating monitoring is active
  • Typical session: 15-30 minutes, keeping battery usage minimal

== The Problem ==

HKWorkoutSession affects Activity Rings during the session. Users receive "Exercise goal reached" notifications while resting — confusing.

== What I've Tried ==

  1. Not using HKLiveWorkoutBuilder → Activity Rings still affected

  2. Using builder but not calling finishWorkout() (per https://developer.apple.com/forums/thread/780220) → Activity Rings still affected

  3. WKExtendedRuntimeSession (self-care type) (per https://developer.apple.com/forums/thread/721077) → Only ~10 min runtime, need up to 60 min

  4. HKObserverQuery + enableBackgroundDelivery (per https://developer.apple.com/forums/thread/779101) → ~4 updates/hour, too slow for real-time detection

  5. Audio background session for continuous processing (suggested in https://developer.apple.com/forums/thread/130287) → Concerned about App Store rejection for non-audio app; if official approves this technical route, I can implement in this direction

  6. Some online resources mention "Health Monitoring Entitlement" from WWDC 2019 Session 251, but I could not find any official documentation for this entitlement. Apple Developer Support also confirmed they cannot locate it?

== My Question ==

Is there any supported way to:

  • Monitor heart rate in background for up to 60 minutes
  • WITHOUT affecting Activity Rings or creating workout records?

If this requires a special entitlement or API access, please advise on the application process. Or allow me to submit a code-level support request.

Any guidance would be greatly appreciated. Thank you!

Answered by DTS Engineer in 877731022

Just see this thread thanks to @simonfromhelix for reviving it. The orginal post was published on Dec ’25. I guess folks were probably on vacation at that time, and hence didn't pick it up.

@Michaellee524: Regarding continuous background monitoring, please start with this post, which covers what I have to say on the topic.

Given that you only need to keep your app running for one hour, you might test if running your app in the frontmost mode allows your app to sample heart rate in the way fitting your case, and if yes, consider asking your users to change the default setting to one hour, as described in Taking advantage of frontmost app state. I'm super curious if that works for you.

I don't see any way that can run an active workout session (HKWorkoutSession) without moving the rings. If the activity notifications are the problem, user-level features, like muting the notifications of the Activity app, or pausing the rings may be something to consider.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Just seen this post. I feel given the detailed write up it's a shame no one's otherwise picked it up with at least some response.

Ultimately I think there's no solution here with the current APIs.

There are background observer HealthKit APIs for HR data but they don't work to your requirements and potentially with WatchOS 26 they don't work well at all! (see here)

I wasn't aware of the entitlement you mention for Health Monitoring, it caused me to write this post.

One other "solution" I'm aware of if your app includes a complication on the watch face -> If you use the legacy ClockKit APIs rather than the newer WidgetKit ones to create this complication, you'll get app waking calls to update this. If you've migrated to WidgetKit this only wakes up the Widget extension which is not so useful. This will still likely not give you the frequency you require.

Beyond that I think it's still a waiting game for better APIs.

Just see this thread thanks to @simonfromhelix for reviving it. The orginal post was published on Dec ’25. I guess folks were probably on vacation at that time, and hence didn't pick it up.

@Michaellee524: Regarding continuous background monitoring, please start with this post, which covers what I have to say on the topic.

Given that you only need to keep your app running for one hour, you might test if running your app in the frontmost mode allows your app to sample heart rate in the way fitting your case, and if yes, consider asking your users to change the default setting to one hour, as described in Taking advantage of frontmost app state. I'm super curious if that works for you.

I don't see any way that can run an active workout session (HKWorkoutSession) without moving the rings. If the activity notifications are the problem, user-level features, like muting the notifications of the Activity app, or pausing the rings may be something to consider.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Hi @Ziqiao Chen and everyone,

Thank you @simonfromhelix for reviving this thread.

@Ziqiao Chen — I tested the frontmost app state approach as you suggested. Sharing the full results here in case they're useful.

== Test Setup ==

  • Disabled HKWorkoutSession entirely (no workout session started)
  • Used only HKAnchoredObjectQuery for heart rate sampling
  • Set Return to Clock → PowerNap (per-app Custom) → "After 1 Hour"
  • Ran the app, then lowered my wrist to simulate a real nap scenario

== Results ==

  1. With Xcode debugger attached:

    • HR sampling worked great (~5 second intervals), continuous and stable
    • This initially gave me hope!
  2. Without Xcode debugger (real-world scenario):

    • The app was terminated by the system within ~10 minutes, even with Return to Clock set to 1 hour for this specific app
    • After lowering my wrist, the screen turned off and the app was suspended/killed shortly after
    • Zero heart rate samples were collected
    • The Xcode debugger appears to elevate the app's priority, masking the real behavior
  3. Digital Crown:

    • Pressing the Crown navigates away and HR sampling stops immediately
    • For a sleep app, users will inevitably press this accidentally while napping
  4. Activity Rings (positive!):

    • Confirmed: no workout record created, Activity Rings unaffected
    • This is exactly what we'd want — if only the app could stay alive

I hope the test results above are also helpful for anyone with similar requirements.

== Where this leaves me ==

@Ziqiao Chen — given that frontmost doesn't survive real sleep conditions, and there's no way to avoid Activity Rings with HKWorkoutSession (as you confirmed), I'd love your guidance:

What would be the recommended technical approach for an app that needs real-time heart rate sampling (every few seconds) during user-initiated sessions of 15-60 minutes?

I've filed FB22115959 requesting an API for this use case, and I'm happy to provide additional technical details through whichever channel you'd recommend.

Thank you again for your time. This thread has been incredibly valuable, and I hope the test data above helps other developers in similar situations.

Thanks for sharing the result of your tests. To comment:

With Xcode debugger attached: HR sampling worked great (~5 second intervals), continuous and stable

This is as-designed: In the case where your app is attached to the Xcode debugger, the debugger will keep the attached app alive to maintain the debugging session. I am glad that you called this out, which gives me a chance to clarify.

Pressing the Crown navigates away and HR sampling stops immediately For a sleep app, users will inevitably press this accidentally while napping

This behavior is as-designed as well, and is documented in Taking advantage of frontmost app state. To quote:

"If a person explicitly closes the app by pressing the digital crown or covering the screen, the app doesn’t become the frontmost app and doesn’t remain in the inactive state, but transitions quickly to the background instead."

(The app will then become suspended after transitions to the background.)

The app was terminated by the system within ~10 minutes, even with Return to Clock set to 1 hour for this specific app After lowering my wrist, the screen turned off and the app was suspended/killed shortly after

This doesn't seem consistent with what is documented in the above article, which describes that a frontmost app can perform some tasks, including receiving "up to four background app refresh tasks per hour."

You mentioned that the screen turned off after you lowering your wrist, and so it seems that you were testing with an Apple Watch Series 4 and earlier. Is it possible for you to try with a newer model + the latest public release watchOS?

Also, I am curious how you observed that the app was terminated within ~10 minutes.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Hi @Ziqiao Chen and everyone,

Thank you for the follow-up. You were right to push for more precise testing — it led me to discover an issue with my original test setup and reach a much clearer understanding of the problem.

== Correction: Original Test Setup ==

My initial frontmost test had a build configuration error: the test build still had an active HKWorkoutSession running in the background. This means the results I would have reported (~10 minutes before termination) did not reflect pure frontmost app state behavior.

I've since corrected this and re-tested with precise instrumentation.

== Hardware & Software ==

  • Apple Watch Series 8 (45mm) — not Series 4
  • watchOS 11.6.1 (latest stable)
  • Build: Debug, standalone watch app
  • Xcode debugger disconnected before all tests (to avoid priority elevation)

== Methodology ==

I added a 30-second heartbeat timer that logs:

  • Sequential counter and elapsed seconds
  • Current heart rate value and time since last HR sample (hr_age_sec)
  • App lifecycle transitions (ScenePhase changes)

I also ran a comparison test with HKWorkoutSession enabled (Release build) as a control group.

Settings: Return to Clock → per-app Custom → After 1 Hour

== Finding 1: App Process Alive, But Timers Stop ==

With frontmost mode (no HKWorkoutSession), the app process remained alive for the full 65 minutes (matching the 1-hour Return to Clock setting). ScenePhase callbacks (active/inactive oscillation) continued throughout the entire 65 minutes at varying intervals (ranging from a few seconds to several hundred seconds) — the system kept delivering lifecycle events to the app.

However, Timer.scheduledTimer stopped firing within minutes:

  • Heartbeat timer (30s interval): stopped after 1.5 to 6.5 minutes across different sessions — despite ScenePhase callbacks continuing for the remainder of the hour
  • ScenePhase: active/inactive oscillation continued from T+13s through T+3903s (65 min), at varying intervals (seconds to hundreds of seconds)
  • This suggests the app process receives system-delivered events, but the run loop stops processing scheduled timers after ~7 minutes

In other words: the app can "hear" the system, but cannot "do work" on its own schedule.

== Finding 2: No High-Frequency Heart Rate Without HKWorkoutSession ==

This is the critical finding. Without HKWorkoutSession, the heart rate sensor does not perform high-frequency sampling for the app. In our testing, HKAnchoredObjectQuery received virtually no data in frontmost mode.

  • After a full watch reboot, I started 5 separate frontmost sessions. None of them received any heart rate data from HKAnchoredObjectQuery.
  • A longer session (65 minutes) also received no new heart rate samples throughout its entire duration.

== Finding 3: HKWorkoutSession Comparison (Control Group) ==

For comparison, I ran the same app with HKWorkoutSession enabled (.mindAndBody activity type):

  • HR check: passed immediately
  • Heart rate: updating in real-time throughout the session
  • App survival: 10+ minutes with continuous execution (no suspension)

This confirms that HKWorkoutSession is the mechanism that triggers high-frequency heart rate sampling, not just background execution.

== Summary ==

AspectFrontmost OnlyHKWorkoutSession
App process alive65 min (full hour)Indefinite
System callbacksThroughout (65 min)Continuous
Scheduled timersStopped within minutesContinuous
Heart rate samplingVirtually noneHigh-freq (1-5s)
Activity RingsNot affectedAffected
Viable for sleepNoYes
detection?

Frontmost app state solves the "app staying alive" part of the problem, but it cannot solve the "real-time heart rate sampling" part. The heart rate sensor simply does not provide high-frequency data without an active HKWorkoutSession.

For my use case (detecting sleep onset via real-time heart rate trends during 15-60 minute nap sessions), HKWorkoutSession remains the only viable mechanism. Is there any other API or session type that triggers high-frequency heart rate sampling besides HKWorkoutSession?

I've filed FB22115959 for this. If there's a better channel to discuss the specifics of my use case, I'm happy to follow up there.

Thanks for doing the thorough test, and sharing your test result, which is very well-written. The details unveiled in the result is definitely very helpful.

Just to confirm that, other than an active HKWorkoutSession, there is no API that can trigger high-frequency heart rate sampling.

Also, thanks for filing the feedback report.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

How to monitor heart rate in background without affecting Activity Rings?
 
 
Q