What happens
craft.health.startWorkout({ type }) starts a real HKWorkoutSession with an
HKLiveWorkoutDataSource, which is what makes an Apple Watch sample heart
rate continuously instead of every few minutes. That is the only way to get
live readings, and it works.
Ending it is the problem. endWorkout is the only way out from JavaScript,
and it always saves:
builder.endCollection(withEnd: end) { ...
builder.finishWorkout { workout, finishError inCraftHealth already has the other half — discardActivityWorkout ends the
session and calls builder.discardWorkout() (CraftHealth.swift:1015) — but
it is not exposed. The JS surface is only:
startWorkout: function(options) { return craft._invoke('startHealthWorkout', options || {}); },
endWorkout: function() { return craft._invoke('endHealthWorkout'); }There is also no mindfulness activity type. workoutActivity accepts
running, walking, hiking, cycling, swimming, rowing, elliptical, strength,
hiit, flexibility, yoga and other. HKWorkoutActivityType.mindAndBody is not
among them.
Why this bites
An app that wants live heart rate during something that is not a workout — a guided meditation, a breathing exercise, a recovery scan — has to choose between two wrong outcomes:
- don't start a session, and the watch reports every few minutes, so a live card sits empty for the length of a three minute meditation unless the person opens the Heart Rate app on their watch by hand; or
- start one, and every meditation is written into Health as a yoga workout, which inflates exercise rings and workout history with things that were not workouts.
Craft already has saveMindfulSession, so the intended shape is clearly
reachable — a session for the live data, discarded at the end, with a mindful
session saved instead. The only thing missing is the discard.
What would help
Either of these closes it:
endWorkout({ discard: true }), or adiscardWorkout()beside it, routed to the existingdiscardActivityWorkout.- A mindfulness activity type, so the saved workout is at least honest about what it was. This is the weaker option: it still writes a workout for something that is not one.
The first is a small surface change over code that already exists.
Found on iOS 26 with an Apple Watch, driving a text-guided meditation.