WHOOP·DECODE

device link · architecture

← datastore dashboard
how we get data off the strap

A one-way radio link, drained in order, on a schedule.

The WHOOP 4.0 strap has no display and no internet. It quietly records your body about once a second into a two-week memory — even with no phone nearby. Everything below is how our app reaches across Bluetooth, pulls that history off, and turns it into the charts on the dashboard. No phone, no problem; the strap just keeps a buffer until we catch up.

01 · the link 02 · connect 03 · what we get 04 · the offload 05 · cadence 06 · data path
02

THE CONNECT HANDSHAKE

Every time the phone reaches the strap, it runs the same short opening sequence — exactly once per connection — to wake the link, agree on the time, and line up the history transfer. It mirrors what WHOOP’s own app does. Running it more than once (an early bug) jams the strap, so it’s strictly one pass, then the data flows.

1
Discover & connectfind the strap’s radio and open the BLE link.
2
Bonda confirmed handshake write — proves the secure pairing and unlocks the private channels.
3
Subscribetell the strap we want to listen on the responses, events, and bulk-data channels.
4
Say helloa small identity exchange the strap expects before it’ll cooperate.
5
Set the clockpush the current time so every record the strap logs is stamped correctly.
6
Quiet the firehoseturn off the raw high-rate research stream so it doesn’t hog the radio.
7
Read the rangeask how much unsynced history is waiting in the strap’s memory.
Begin offloadstream the stored history across — see section 04.handshake runs once · then data flows
03

WHAT WE GET

Two kinds of information come off the strap. Live readings are streamed in the moment (only when you ask for them). The stored history — the real prize — is a two-week, roughly one-per-second log of your biometrics that the strap keeps whether or not a phone is around. Plus housekeeping: events, battery, and firmware info.

The 14-day biometric store  ·  primary source

The strap records ~1 sample/second into a rolling two-week memory, on-wrist, offline. On every sync we offload this log. It’s the backbone of everything on the dashboard. Each record carries:

Heart rate Heart-rate variability Blood oxygen (SpO₂) Skin temperature Respiratory rate Motion / gravity
logged continuously · ~1 Hz · retained ~14 days

Live heart rate

Real-time beats-per-minute plus beat-to-beat timing, streamed as it happens.

opt-in · on demand

Events

The strap announces moments: boot, clock set, wrist on/off, and other state changes.

pushed when they happen

Battery & firmware

Charge level, charging state, and the strap’s hardware / firmware version.

read on connect

Derived on the server

Sleep, recovery, strain and daily summaries are computed from the stored signals after they land.

computed after sync
04

THE OFFLOAD — READ IN ORDER

The history transfer is a strict, in-order drain. We ask once; the strap streams its log oldest-first in chunks. The crucial detail: the strap only lets go of a chunk once we acknowledge it, and that acknowledgement moves a one-way read cursor forward — records behind it are considered delivered and can’t be served again. So the golden rule is save first, acknowledge second.

HISTORY START records CHUNK END records CHUNK END COMPLETE
A
Requestone “send history” command kicks it off.
B
Streamthe strap pours records down the bulk channel, closing a chunk every so often.
C
Decode & savethe phone unpacks each chunk and writes it to local storage.
D
Acknowledge → trimonly now do we ack — which advances the strap’s read cursor past that chunk.
E
Repeat → COMPLETEloop until the strap signals it’s caught up.
save → then
acknowledge

The cursor is one-way: once a chunk is acked, the strap drops it for good. We never ack a chunk we haven’t durably stored.

Break that order and the cursor races past data that was never kept — a permanent gap. Keeping it is what makes the sync lossless.
05

CADENCE & SCHEDULING

We don’t sync constantly — that would drain both batteries. Instead a sync is triggered by a few events, each rate-limited by a cooldown so bursts don’t pile up. The strap keeps logging the whole time, so whenever the next sync fires, the two-week buffer has us covered.

On connect

Each time the phone (re)reaches the strap, it offloads whatever piled up.

first connect always runs

Periodic timer

While connected, a background timer kicks a routine catch-up.

~15 min floor

App foreground

Opening the app nudges a fresh sync so you see current data.

~90 s cooldown

Strap event

The strap can prompt its own sync by pushing an event.

~90 s cooldown

Manual “sync now”

A tap forces an immediate offload, no cooldown.

on demand

Live HR

Real-time streaming runs only while you explicitly keep it on.

opt-in only
◉ always-on The strap logs ~1 sample/second to its 14-day memory regardless of the phone — uploads to the server then happen opportunistically and on a timer during each session. Miss a day? The next sync simply drains the backlog in order.
06

END-TO-END DATA PATH

Following a single reading from your wrist to this dashboard:

STRAP
logs to 14-day flash, ~1 Hz, offline
📶BLE OFFLOAD
chunked & acked, in order
PHONE
decodes + saves to local store
SERVER
uploaded to the datastore
DASHBOARD
charts + derived insights
WHOOP·DECODE — independent reverse-engineered client · device link architecture  ·  back to the datastore →