Skip to main content

Overview

The Health Monitor feature provides real-time streaming of heart rate, RR intervals, and other physiological data from the Whoop 4.0. This is the same data stream shown in the “Health Monitor” section of the Whoop app.

Health Monitor Commands

Health Monitor is toggled using commands to CMD_TO_STRAP:
aa0800a823 05 03 00 e44e25be  # Health Monitor off
aa0800a823 06 03 01 2bc064cb  # Health Monitor on
aa0800a823 66 74 01 3ae4cde3  # Alternate on command

Packet Structure

OffsetSizeFieldDescription
0x005 bytesHeaderAlways aa0800a823
0x051 bytePacket CountIncrements with each packet
0x061 byteCategory0x03 for health monitor
0x071 byteState0x00 = Off, 0x01 = On
0x084 bytesChecksumCRC-32 with custom parameters

Enabling Health Monitor

Using gatttool

# Turn ON health monitor
sudo gatttool -i hci0 -t random -b XX:XX:XX:XX:XX:XX \
  --char-write -a 0x0010 -n aa0800a82306030 12bc064cb

# Turn OFF health monitor
sudo gatttool -i hci0 -t random -b XX:XX:XX:XX:XX:XX \
  --char-write -a 0x0010 -n aa0800a82305030 0e44e25be

Using Python

Listen for health monitor data on DATA_FROM_STRAP:
python3 enable_notifications.py --address XX:XX:XX:XX:XX:XX \
  61080005-8d6d-82b8-614a-1c8cb0f8dcc6

Health Monitor Data Format

When Health Monitor is active, the device sends 24-byte packets on DATA_FROM_STRAP every second:
Header          Unix        S       HR  RR  RR data                 Checksum
aa1800ff2802    ad896566    f065    42  01  67060000000000000101    3ba00d4d
aa1800ff2802    ae896566    f860    43  00  00000000000000000101    5025f793
aa1800ff2802    af896566    085c    42  00  00000000000000000101    add7df13
aa1800ff2802    b0896566    1057    42  00  00000000000000000101    24b22179
aa1800ff2802    b1896566    1852    42  00  00000000000000000101    e0a905b8
aa1800ff2802    b2896566    284d    42  00  00000000000000000101    d943226a
aa1800ff2802    b3896566    3848    43  00  00000000000000000101    28364865
aa1800ff2802    b4896566    4043    43  00  00000000000000000101    9c2e99ba
aa1800ff2802    b5896566    503e    43  00  00000000000000000101    ebb8a1ce
aa1800ff2802    b6896566    5039    43  00  00000000000000000101    d1635459
aa1800ff2802    b7896566    6834    43  00  00000000000000000101    ccefa569
aa1800ff2802    b8896566    702f    43  00  00000000000000000101    8770ff99
aa1800ff2802    b9896566    802a    43  00  00000000000000000101    d2299e02
aa1800ff2802    ba896566    8825    44  00  00000000000000000101    3cd6a988
aa1800ff2802    bb896566    9020    44  00  00000000000000000101    94f13f2f
aa1800ff2802    bc896566    a01b    44  00  00000000000000000101    c8ed7785
aa1800ff2802    bd896566    b016    44  00  00000000000000000101    3b07bb4b

Packet Structure

OffsetSizeFieldDescription
0x005 bytesHeaderAlways aa1800ff2802
0x054 bytesUnix TimeLittle-endian timestamp
0x092 bytesUnknownPurpose unclear
0x0B1 byteHeart RateBPM value
0x0C1 byteRR CountNumber of RR intervals
0x0D8 bytesRR DataRR interval values
0x153 bytesUnknownPurpose unclear
0x184 bytesChecksumCRC-32

Example: Parsing Heart Rate

From the first packet:
aa1800ff2802 ad896566 f065 42 01 67060000000000000101 3ba00d4d
  • Heart Rate (byte 0x0B): 0x42 = 66 BPM
  • RR Count (byte 0x0C): 0x01 = 1 RR interval
  • RR Data (bytes 0x0D-0x14): 67060000000000000101

Heart Rate Progression

Looking at the sequence:
TimeHR ByteHeart Rate (BPM)
ad8965664266
ae8965664367
af8965664266
b08965664266
b18965664266
b28965664266
b38965664367
b48965664367
b58965664367
b68965664367
b78965664367
b88965664367
b98965664367
ba8965664468
bb8965664468
bc8965664468
bd8965664468
The heart rate is increasing from 66 to 68 BPM over this period.

Data vs. Activity Tracking

Health Monitor data uses the exact same packet format as Activity Tracking data. Both features stream to DATA_FROM_STRAP with identical structure.
The only difference is the control command:
  • Activity Tracking: Category 0x03, various start/stop commands
  • Health Monitor: Category 0x03 or 0x74, on/off toggle

Characteristics Used

CMD_TO_STRAP (Control)

  • UUID: 61080002-8d6d-82b8-614a-1c8cb0f8dcc6
  • Handle: 0x0010
  • Properties: Write only
  • Purpose: Send on/off commands

DATA_FROM_STRAP (Health Data)

  • UUID: 61080005-8d6d-82b8-614a-1c8cb0f8dcc6
  • Handle: 0x0018
  • Properties: Notify
  • Purpose: Receive real-time health metrics
  • Update Rate: ~1 second

Stopping Health Monitor

Send the off command to stop the data stream:
sudo gatttool -i hci0 -t random -b XX:XX:XX:XX:XX:XX \
  --char-write -a 0x0010 -n aa0800a82305030 0e44e25be
Notifications on DATA_FROM_STRAP will stop immediately.

RR Interval Data

The 8 bytes of RR data (bytes 0x0D-0x14) contain RR interval information:
  • RR Count indicates how many RR intervals are included
  • When count is 0x00, RR data bytes are all zeros
  • When count is 0x01 or higher, RR values are encoded in the data
The exact encoding format for RR intervals is not fully documented. The values may be compressed or require scaling to convert to standard millisecond intervals.

Example RR Data

RR Count: 01, RR Data: 67060000000000000101
RR Count: 00, RR Data: 00000000000000000101
RR Count: 02, RR Data: b802b90200000000
Notice that:
  • Count 0x01 has data in first bytes: 6706
  • Count 0x00 has all zeros in RR section
  • Count 0x02 has two values: b802 and b902

Use Cases

  • Real-time HR monitoring: Display live heart rate in custom apps
  • HRV analysis: Extract RR intervals for heart rate variability calculations
  • Biofeedback: Use live data for meditation, breathing exercises, or training
  • Research: Collect raw physiological data for studies
  • Third-party integrations: Stream Whoop data to other platforms
For broadcasting heart rate to standard BLE Heart Rate Service, see Heart Rate Broadcast. For starting activities that also stream similar data, see Activity Tracking.

Build docs developers (and LLMs) love