v0.9.25 — WHOOP 5 / MG (experimental)
Pre-releaseExperimental — WHOOP 5.0 / MG. This line exists so 5.0/MG owners can test gen5 support before it lands on the stable channel. WHOOP 4.0 users should stay on v0.9.24.
The headline is not a gen5 feature. It is that this build is no longer stale.
feat/multiband-whoop5 forked from main back in July and never came back. Both previous experimentals — 0.9.22 and 0.9.23 — were cut from that same fork point, so for a month WHOOP 5 testers have been running a build missing everything the stable line fixed. That is over: main is merged in, and this release carries all of v0.9.24 plus the four PRs after it.
If you are on 0.9.23, most of what changed for you below has nothing to do with your band being a 5.0.
WHOOP 5 / MG
Since 0.9.23, from @Brackyt in #188, #194 and #195.
Sleep and HRV on 5.0 (#185). The v18 record decoder was rejecting real hardware captures outright, so a night produced no staging and no HRV — the "I never slept and was awake the whole time" report. Decoding is lenient about the fields real straps actually send, samples persist to decoded_onehz so the derive engine can see them, and the unix gate is aligned. SET_CLOCK also sends the correct revision byte, without which the strap's clock frame never latches.
Wake alarm (#186). WHOOP 5 requires alarm slot index 1 — index 0 is rejected outright with arm info is invalid, error 0xb, which is why a scheduled alarm silently never buzzed. The short 7-byte time-only form is ACKed by the strap but never fires, so it is not used. Arming now SET_CLOCKs first, as the official app does, and shifts the target into the strap's own RTC frame: the strap fires on its own clock, so a raw wall-clock epoch lands decades ahead of a strap clock near its factory epoch and never fires at all. That is why an immediate test buzz worked while a scheduled alarm did not.
Steps (#192). Maverick live IMU is now armed and decoded, so step calibration has something to calibrate against. Absent gravity no longer reads back as perfect stillness — which had made a still strap and a strap sending nothing indistinguishable.
Decode robustness. An unparseable raw hex frame no longer discards a perfectly good decoded sample, and an R10-lite frame is rejected before it can short-circuit a preferred one.
Still open on gen5: @Brackyt notes gaps in the continuous HR stream (#191) are improved but not fully resolved. Please keep reporting.
Everything the experimental line was missing
All of this shipped on stable in v0.9.24 or the four PRs after it, and reaches WHOOP 5 testers for the first time here.
Connection and battery
- Android held an ~11.25 ms connection interval 24/7 on a connection that is permanent by design — roughly 22% of an S22's battery in a day. The link now steps down when idle or backgrounded and rises only for an offload or a live consumer (#200). The battery poll also came off the 30 s keep-alive tick, which was 2,880 radio round-trips a day by itself.
- Reconnect was edge-triggered inside one try/catch, so a single throw ended reconnection for the lifetime of the process — a strap taken off or carried out of range would never come back without a re-pair (#208).
- A HISTORY_END trim is refused when gate drops leave the buffer empty, instead of trimming flash for records that were never persisted (#198, also @Brackyt).
Crashes (#212, from what Crashlytics has collected since 0.9.14)
- Opening Journey could throw and blank the whole timeline chart, repeating on every repaint — the most-hit issue on the list. Five other charts had the same clamp bug where the upper bound can fall below the lower one on a narrow layout.
- Sharing a data export died on iOS 26 with
sharePositionOrigin: argument must be set. - Respiratory rate on the day curve re-estimated once per heartbeat instead of once every five minutes, burning minutes of CPU inside an isolate with a ninety-second budget. The all-day HRV curve had the same shape.
Apple Health / Health Connect
- Strength workouts never reached Apple Health at all: HealthKit has no bare
STRENGTH_TRAINING, every write was rejected, and the error went to adebugPrint(#184). Swims had the mirror-image bug on Android. - Health Connect sleep sessions no longer fragment (#196, from @FlixiDoe).
Workouts
- Strain was tallied in memory by the foreground app, so a workout you backgrounded came back scored 0.0 (#206). Sessions are now rescored from the band's own 1 Hz record on read and after each sync, so previously-broken workouts fix themselves.
- Completed workouts can be logged and retimed after the fact (#189).
Steps
- Steps come from a real pedometer only, and movement minutes from measured evidence (#182).
- With phone steps on, the band's live count was added on top of the phone's count of the same walk; the toggle didn't re-derive when switched on; and a live workout showed "0 STEPS" when nothing was measured, rather than a dash (#183).
- The live count never reset at local midnight, so at 00:01 the tile carried the whole of yesterday and kept climbing (#216).
Sleep
- One nap detector with today-scoped inputs and disclosed adjustments (#204), and a detected nap is actually visible on the Sleep screen (#205, from @egoran2). A nap-only day no longer reports "no sleep".
- The sleep profile folded on every derive pass instead of once per night (#174).
Imports
- A WHOOP export is a zip of CSVs and a
.noopbakis a zip around noop's SQLite database; both were being fed straight into a UTF-8 decoder, henceFormatException: Unexpected extension byte(#199, #160). WHOOP exports now unpack and import. - A
.noopbakimports for real (#213) — the same 1 Hz channels the band records, re-derived day by day rather than importing noop's own scores. On a real 13-day backup that is 14 days and 4.6 M rows in about two minutes. On iOS this is the only export noop offers, so this is the only migration path 5.0 users on iPhone have. - NOOP CSV imports recover the band step counter across noop's schema drift (#176).
Other
- Replayed
chargingOnevents no longer re-notify (#180). - The AI key no longer disappears after the phone sleeps (#213).
- A small dot beside the wordmark breathes while records are landing, so a quiet sync is distinguishable from a broken one (#216).
Notes
- Scores recompute on first launch.
kAlgoVersiongoes from 51 to 60, so every historical day is re-derived once. On a large database that takes a while, and readiness/strain can read differently afterwards — that is the nine algorithm revisions since 0.9.23 landing, not a regression. - Version numbering. The experimental line takes 0.9.25 as 0.9.22 and 0.9.23 did before it, so the next stable release is 0.9.26.
- Dependency pins. WHOOP 5 support is now on
protocolmain (367d22b, protocol#16 merged) rather than a side branch. - Android: install the
.apkbelow. iOS: the.ipais unsigned for sideloading (AltStore / Sideloadly) — re-signing with a free Apple account changes the team id, so the home widget and Live Activity may not work and there is no OTA auto-update. TestFlight is the better path if you are in the WHOOP 5 beta group.
Expect breakage, and please file what you find.