Whoop
Backlinks: Fitness Tech | Sleep monitor | Wearables > Whoop
Whoop whoop! Super accurate fitness and recovery tracker.
Bicep band is a MUST.
See Whoop Heart Rate Accuracy.
Looks like I've used (on and off) –current, using bands 3 through 5.
Whoop band 3
My first band. Lives in a drawer in the basement.
Habit tracking
Used it consistently for habit tracking for a few years. It's one of those things that you get out of it what you put into it.
The monthly impact reports are pretty great.
Whoop labs
Did this once. Cool experience. Wrote about it on Reddit, I think.
Wore at least two whoops on each wrist and a Polar H10 as a reference. Did some light weightlifting and running.
Code to pull from official API
Two-phase OAuth: build an authorization URL, complete consent in the browser, then exchange the returned code for an access token.
Each python source block is executed by ob-python via the
org-babel-python-command set in the file-local variables at the
bottom of this header uv run --no-project --with requests python -. uv
provisions an ephemeral environment with requests and pipes the block
body in over stdin. No virtualenv setup is required.
Credentials come from 1Password via op read.
Step 1: build the authorization URL
Open the printed URL in a browser, authorize, and copy the code query
parameter from the redirect.
import secrets
import subprocess
import urllib.parse
def op_read(ref):
return subprocess.check_output(['op', 'read', ref], text=True).strip()
client_id = op_read('op://Private/Whoop API/client_id')
auth_endpoint = 'https://api.prod.whoop.com/oauth/oauth2/auth'
query_params = {
'response_type': 'code',
'state': secrets.token_urlsafe(16),
'client_id': client_id,
'scope': 'offline read:recovery read:sleep read:workout',
'redirect_uri': 'http://localhost:8484/callback',
}
url_parts = list(urllib.parse.urlparse(auth_endpoint))
query = dict(urllib.parse.parse_qsl(url_parts[4]))
query.update(query_params)
url_parts[4] = urllib.parse.urlencode(query)
print(urllib.parse.urlunparse(url_parts))
Step 2: exchange the code for an access token
Paste the authorization code into CODE below, then C-c C-c in the
block.
import subprocess
import requests
def op_read(ref):
return subprocess.check_output(['op', 'read', ref], text=True).strip()
client_id = op_read('op://Private/Whoop API/client_id')
client_secret = op_read('op://Private/Whoop API/client_secret')
code = op_read('op://Private/Whoop API/code')
response = requests.post(
'https://api.prod.whoop.com/oauth/oauth2/token',
headers={'Content-Type': 'application/x-www-form-urlencoded'},
data={
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': 'http://localhost:8484/callback',
'client_id': client_id,
'client_secret': client_secret,
},
)
print(response.json())
Step 3: Pull data
import json
import subprocess
import requests
def op_read(ref):
return subprocess.check_output(['op', 'read', ref], text=True).strip()
access_token = op_read('op://Private/Whoop API/access_token')
response = requests.get(
'https://api.prod.whoop.com/developer/v2/recovery',
headers={'Authorization': f'Bearer {access_token}'},
params={'limit': 5},
)
data = response.json()
data.pop('next_token', None)
print(json.dumps(data, indent=2))
FitIQ
Cool add-on analytics company site. $5/mo. I should build something like this. Ran the free trial, the coolest part was the longer-timeframe charts.
Whoomp
Reverse engineering of the whoop band bluetooth interface. Likely illegal.
Repository: https://github.com/jogolden/whoomp Try it out at https://jogolden.github.io/whoomp/
Purchase history
| Date | Invoice/Order ID | Description | Amount |
|---|---|---|---|
| 10/17/2020 | B3083415 | Strap 3.0 + 18-Month Subscription | 321.37 |
| 10/21/2020 | E7B92FA0-0001 | Trial period for Whoop Membership 3.0 | 0.00 |
| 11/02/2020 | W170297 | Core Bicep Band (Thunder L/XL) | 32.99 |
| 12/20/2021 | W389941 | Superknit Bicep Band 4.0 | 61.37 |
| 08/14/2022 | E7B92FA0-0002 | Whoop Membership (monthly) | 31.88 |
| 09/14/2022 | E7B92FA0-0003 | Whoop Membership (monthly) | 31.88 |
| 10/14/2022 | E7B92FA0-0004 | Whoop Membership (monthly) | 31.88 |
| 11/14/2022 | E7B92FA0-0005 | Whoop Membership (monthly) | 31.88 |
| 12/14/2022 | E7B92FA0-0006 | Whoop Membership (monthly) | 31.88 |
| 01/14/2023 | E7B92FA0-0007 | Whoop Membership (monthly) | 31.88 |
| 02/14/2023 | E7B92FA0-0008 | Whoop Membership (monthly) | 31.88 |
| 03/14/2023 | E7B92FA0-0009 | Whoop Membership (monthly) | 31.88 |
| 04/14/2023 | E7B92FA0-0010 | Whoop Membership (monthly) | 31.88 |
| 05/14/2023 | E7B92FA0-0011 | Whoop Membership (monthly) | 31.88 |
| 06/14/2023 | E7B92FA0-0012 | Whoop Membership (monthly) | 31.88 |
| 07/14/2023 | E7B92FA0-0013 | Whoop Membership (monthly) | 31.88 |
| 08/07/2023 | W767432 | Battery Pack 4.0 | 61.05 |
| 08/07/2023 | W767434 | Moss Superknit Bicep Band | 61.37 |
| 08/07/2023 | E7B92FA0-0014 | Trial period for Whoop Membership | 0.00 |
| 08/14/2023 | E7B92FA0-0015 | Whoop Membership (annual) | 253.94 |
| 08/14/2024 | E7B92FA0-0016 | Whoop Membership (annual) | 253.94 |
| 09/28/2024 | W1114938 | Replacement WHOOP 4.0 | 79.69 |
| 05/15/2025 | B44810861 | MG Device + Life 12mo + CoreKnit Band | 442.49 |
| 01/08/2026 | B58015616 | MG SuperKnit Band Glade (free) | 0.00 |
| 11/14/2025 | — | Advanced Labs Subscription | 349.00 |
| Total | 2540.65 |
Whoop band 4
I haven't noticed a big difference from the 3.0, though the health metrics have picked up sickness. Waterproof charger is a plus. I couldn't passed on getting new bands ($$).
I lost the band at one point, and given the remaining time on the plan, it was worth buying a new band. I also think I had to buy one new battery.
Django app to connect with Whoop
I wrote one: https://github.com/andyreagan/django-whoop.
Whoop 5/MG
- Note taken on
Arrived today. Got the MG, excited to try it out. The mixed reaction to needing a full year prepaid to get the device has been interesting. I do think they botched it, but at the same time it's not unreasonable.