---
title: Accessing workout zone data
framework: healthkit
role: article
role_heading: Article
path: healthkit/accessing-workout-zone-data
---

# Accessing workout zone data

Provide training insights to people on your app using workout zone data.

## Overview

Overview Workout zones divide measurements like heart rate and cycling power into ranges that represent training intensities. People configure their preferred zones in Health Settings, where they can choose between system-generated zones based on their health metrics, or manually defined custom ranges. HealthKit calculates the time someone spends in a zone during workouts, and makes the data and other workout statistics available to your app. With permission, your app can use data from workout zones to provide a view of training intensity across all of a person’s workout apps. Ask to read workout data Before you can access someone’s workout zone data, you must ask their permission. Call the requestAuthorization(toShare:read:) method to request permission to read workouts and quantity types: let workoutType = HKObjectType.workoutType() guard let heartRateType = HKQuantityType.quantityType(forIdentifier: .heartRate),       let cyclingPowerType = HKQuantityType.quantityType(forIdentifier: .cyclingPower) else {     return }

try await healthStore.requestAuthorization(     toShare: [],      read: [workoutType, heartRateType, cyclingPowerType] ) Request permission to read the specific quantity types used for zones, such as heart rate to access heart rate zones, and cycling power to for cycling power zones. Add samples for automatic zone calculation When you add heart rate or cycling power samples to an HKWorkoutBuilder or HKLiveWorkoutBuilder, the system automatically calculates the zone the sample falls into, and tracks the duration in each zone. The system calculates the data for live workout sessions and past workouts that you create programmatically. You don’t need to call any additional methods to enable zone calculation. The system uses a person’s preferred zone configuration from Health Settings for the calculations. People can configure custom zones manually or allow the system to generate zones automatically based on their health metrics like age and resting heart rate. For heart rate, the system provides default zones even if the person hasn’t configured preferences. Cycling power requires the person’s configuration. Note: You can provide custom zones for a specific workout by calling setCustomZoneConfiguration(_:for:) before beginning data collection. Retrieve zone data from completed workouts Access zone configurations and durations from saved workouts to display training intensity information. After querying for workouts, access the zoneGroupsByType property to retrieve zone data for each quantity type: if let zoneGroups = workout.zoneGroupsByType {     for (quantityType, zoneGroup) in zoneGroups {         let configuration = zoneGroup.configuration         let durations = zoneGroup.zoneDurations                  // Display zone information.         for zoneDuration in durations {             let zone = zoneDuration.zone             let timeInZone = zoneDuration.duration                          print("Zone \(zone.index): \(timeInZone) seconds")             if let min = zone.minimum {                 print("  Min: \(min)")             }             if let max = zone.maximum {                 print("  Max: \(max)")             }         }     } } The HKWorkoutZoneGroup contains both the configuration that defines the zones and an array of durations showing time spent in each zone. The system orders zones from lowest to highest threshold. For workouts with multiple activities, access zone data at the activity level using zoneGroupsByType to see zone information specific to each activity’s time range. Check zone configuration sources Workouts can use different zone configurations, and comparing time-in-zone across workouts requires planning for those differences. For accuracy, identify the origin and configuration of workout zones, and include it in your interpretation and display of the zone data. Check the source property to determine the origin of the zones: switch zoneGroup.configuration.source { case .system:     // Zones automatically generated by the system based on personal metrics.     print("System-generated zones")      case .user:     // Zones manually configured by the person in Health Settings.     print("User-configured zones")      case .app:     // Zones provided by an app for this specific workout.     print("App-defined zones") } System-generated zones update when the person’s health metrics change, but zones configured by the person remain constant until the person modifies them in Health Settings. App-defined zones apply only to the specific workout in which they were set. Access the person’s preferred workout zones In Health Settings, people can choose automatic zones that the system configures based on their health metrics or configure manual zones by setting custom boundaries themselves. When you need to display zone information outside the context of a specific workout, call the preferredWorkoutZoneConfiguration(for:) method, which returns either the automatic or custom zone configuration, depending on which one is active in Settings: guard let heartRateType = HKQuantityType.quantityType(forIdentifier: .heartRate) else {     return }

if let preferredConfig = try await healthStore.preferredWorkoutZoneConfiguration(for: heartRateType) {     print("Preferred zones for heart rate:")     for zone in preferredConfig.zones {         print("Zone \(zone.index): \(zone.minimum?.description ?? "no min") - \(zone.maximum?.description ?? "no max")")     } } Receive live zone updates during workouts Implement the HKLiveWorkoutBuilderDelegate protocol to receive notifications when someone changes zones during an active workout session. Adopt the delegate protocol and implement the workoutBuilder(_:didUpdateWorkoutZone:) method: extension WorkoutManager: HKLiveWorkoutBuilderDelegate {     func workoutBuilder(         _ workoutBuilder: HKLiveWorkoutBuilder,         didUpdateWorkoutZone zoneUpdate: HKLiveWorkoutBuilder.ZoneUpdate     ) {         // Update the UI to show the person's zone.         if let newZone = zoneUpdate.newZoneDuration {             updateCurrentZone(newZone.zone)         }                  // Access all zone durations.         let allDurations = zoneUpdate.group.zoneDurations         updateZoneDurationsDisplay(allDurations)     } } The HKLiveWorkoutZoneUpdate structure provides the previous zone, the new zone, and the complete set of current zone durations. Use this information to update your interface and provide real-time feedback during workouts. For more information about running workout sessions, see Running workout sessions. Set custom zones for a workout You can configure custom zone boundaries for a workout when your app needs to apply a specific training model or zone scheme. This example illustrates how to create a custom zone configuration and set it on the workout builder before beginning data collection: let builder = HKWorkoutBuilder(     healthStore: healthStore,     configuration: workoutConfiguration,     device: .local() )

guard let heartRateType = HKQuantityType.quantityType(forIdentifier: .heartRate) else {     return }

let heartRateUnit = HKUnit(from: "count/min") let zoneBoundaries = [     HKQuantity(unit: heartRateUnit, doubleValue: 136.8),     HKQuantity(unit: heartRateUnit, doubleValue: 147.6),     HKQuantity(unit: heartRateUnit, doubleValue: 158.4),     HKQuantity(unit: heartRateUnit, doubleValue: 169.2) ]

let customConfiguration = try HKWorkoutZoneConfiguration(     quantityType: heartRateType,     zoneBoundaries: zoneBoundaries )

// Always set the custom zone configuration before beginning collection. try await builder.setCustomZoneConfiguration(customConfiguration, for: heartRateType)

try await builder.beginCollection(at: .now) The boundaries you provide define the upper threshold of each zone. The system creates contiguous zones from these boundaries; the first zone has no lower bound, and the last zone has no upper bound. Custom configurations apply only to the workout created; they don’t modify the person’s preferred zone choices in Health Settings. If you don’t set a custom configuration, the system uses the person’s preferred zones for zone calculations. note: If your app manages custom zones, consider storing zone parameters in your own storage system and recreating the configuration for each workout. The custom zones you set aren’t synced across devices or persisted beyond the specific workout where they’re applied.

## See Also

### Workout zones

- [Tracking heart rate zones for workouts](healthkit/tracking-heart-rate-zones-for-workouts.md)
- [HKWorkoutZone](healthkit/hkworkoutzone.md)
- [HKWorkoutZoneConfiguration](healthkit/hkworkoutzoneconfiguration.md)
- [HKWorkoutZoneDuration](healthkit/hkworkoutzoneduration.md)
- [HKWorkoutZoneGroup](healthkit/hkworkoutzonegroup.md)
