HealthKit Workouts
Live workout tracking with HKWorkoutSession and HKLiveWorkoutBuilder: collecting sensor data in your own app, saving a finished HKWorkout, and coordinating across Apple Watch and iPhone.
When to Use
Use this skill when you're:
- Building a workout tracking app on watchOS, iOS, or iPadOS
- Deciding between a live session (
HKWorkoutSession) and logging a finished workout after the fact - Implementing pause and resume, multi-activity triathlons, or watch-to-iPhone mirroring
- Recovering an active workout after an app or process termination
- Adopting iOS 26's ability to start sessions on iPhone (previously watch-only)
- Supporting Always On display while a workout is running
- Querying historical
HKWorkoutandHKWorkoutActivitydata - Reading or tracking workout zones, the heart-rate and cycling-power effort bands, live or after the workout (OS 27)
Example Prompts
Questions you can ask your assistant that will draw from this skill:
- "My workout isn't saving when the user taps Done — what's wrong?"
- "How do I recover an active workout session after my app is killed?"
- "What's the right way to transition from swim to bike in a triathlon workout?"
- "How do I mirror a watch workout to the iPhone companion app?"
- "How do I keep the workout view updating during Always On without draining the battery?"
- "How do I show time in each heart-rate zone after a run?" (OS 27)
What This Skill Provides
Session Lifecycle
- The six
HKWorkoutSessionStatevalues and what each means - Why
.stoppedis not.ended— the most common bug - The canonical end sequence:
stopActivity→.stopped→endCollection→finishWorkout→end prepare()vs.startActivity(with:)for a fast start with warm sensors
Setup and Data Collection
- Canonical
HKWorkoutSessionandHKLiveWorkoutBuildersetup for watchOS and iOS 26+ - Configuring
HKLiveWorkoutDataSource(default types per activity,enableCollection,disableCollection) - Delegate isolation: mark methods
nonisolatedand hop to@MainActorinside them - Logging a past workout (from a server or manual entry) with a non-live
HKWorkoutBuilder, not the deprecatedHKWorkoutinitializers
Recovery and Multi-Device
recoverActiveWorkoutSessionon watchOS and iOS 26+, each with its own entry point- Watch-to-iPhone mirroring with
startMirroringToCompanionDevice - The 10-second iPhone wake budget, and why you register
workoutSessionMirroringStartHandlerat app launch - Multi-activity workouts (triathlons) with
beginNewActivityand.transitionsegments - Reading per-activity statistics with
HKWorkoutActivity.statistics(for:)
Always On and Background
- The 1 Hz maximum refresh rate when the watch is locked
- Branching on
TimelineView'smode == .lowFrequencyto show a simpler view - The
workout-processingbackground mode required on watchOS
Workout Zones (OS 27)
- Zone breakdowns attached to every finished workout (
HKWorkoutZoneGroup,HKWorkout.zoneGroupsByType), readable on every platform - Live zone-change callbacks (
didUpdateWorkoutZone, delivering anHKLiveWorkoutZoneUpdate) on iOS and watchOS - Preferred vs. custom zone configuration with
HKWorkoutZoneConfiguration - Custom-zone gotchas: set them before
beginCollection, and save them yourself, because HealthKit doesn't persist them
Key Pattern
The end sequence is the single most load-bearing pattern in this skill. Calling session.end() too early loses the workout:
// 1. UI event finishes the workout:
session.stopActivity(with: .now)
// 2. Session delegate reacts to .stopped:
func workoutSession(_ session: HKWorkoutSession,
didChangeTo toState: HKWorkoutSessionState,
from fromState: HKWorkoutSessionState,
date: Date) {
guard toState == .stopped, let builder = self.builder else { return }
Task {
try await builder.endCollection(at: date)
let finishedWorkout = try await builder.finishWorkout()
session.end()
}
}.stopped means "activity halted, builder still needs to finish". .ended is the terminal state.
Documentation Scope
This page documents the workouts skill (in the axiom-health suite). The skill also holds the platform availability table, the full setup and recovery code, and a common-mistakes table.
Related
- Fundamentals –
HKHealthStoresetup and the HealthKit type hierarchy - WorkoutKit – The complementary API for planned and scheduled workouts that run in the Workout app instead of your own
- Authorization and Privacy – The read and write permissions workouts require, and their
Info.plistpurpose strings - Queries – Reading completed
HKWorkoutsamples after the session ends - watchOS Platform Basics – Watch-specific presentation (Always On, Smart Stack, background modes)
- Swift 6 Concurrency – Actor isolation rules for session and builder delegate callbacks
Resources
WWDC: 2021-10009 (Build a workout app for Apple Watch), 2022-10005 (What's new in HealthKit), 2023-10023 (Build a multi-device workout app), 2025-322 (Track workouts with HealthKit on iOS and iPadOS), 2026-207 (Deliver workout insights with HealthKit workout zones)
Docs: /healthkit/workouts-and-activity-rings, /healthkit/running-workout-sessions, /healthkit/hkworkoutsession, /healthkit/hkliveworkoutbuilder, /healthkit/hkliveworkoutbuilderdelegate, /healthkit/hkliveworkoutdatasource, /healthkit/hkworkoutconfiguration, /healthkit/hkworkout, /healthkit/hkworkoutactivity, /healthkit/hkhealthstore/recoveractiveworkoutsession(completion:), /healthkit/build-a-workout-app-for-apple-watch, /healthkit/building-a-workout-app-for-iphone-and-ipad, /healthkit/accessing-workout-zone-data, /healthkit/hkworkoutzonegroup, /healthkit/hkworkoutzoneconfiguration