WHOOP Central - OAuth + scripts to fetch WHOOP data (sleep, recovery, strain, workouts). Use when user asks about their sleep, recovery score, HRV, strain, or workout data.
59
71%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./public/skills/4xiomdev/whoop-central/SKILL.mdAccess sleep, recovery, strain, and workout data from WHOOP via the v2 API.
# 1) One-time setup (writes ~/.clawdbot/whoop/credentials.json)
node src/setup.js
# 2) Recommended: Get tokens via Postman (see Auth section), then verify
node src/verify.js
node src/verify.js --refresh
# Prompt-friendly snapshot (includes last workout)
node src/today.js
# Daily summary (all metrics)
node src/summary.js
# Individual metrics
node src/recovery.js
node src/sleep.js
node src/strain.js
node src/workouts.js
# Bulk import to ~/clawd/health/logs/whoop/*
node src/import-historical.js| Metric | Data Points |
|---|---|
| Recovery | Score (0-100%), HRV, resting HR, SpO2, skin temp |
| Sleep | Duration, stages (REM/deep/light), efficiency, performance |
| Strain | Daily strain (0-21), calories, avg/max HR |
| Workouts | Activity type, duration, strain, calories, HR |
openssl (only needed for the optional auth.js flow when using https://localhost; Postman auth does not need it)https://oauth.pstmn.io/v1/browser-callbackauth.js):
https://localhost:3000/callbackTeam note: this skill does not ship any client credentials. Each user can create their own WHOOP app,
or (if you trust each other) a team can share one app's client_id/client_secret and let multiple WHOOP
accounts authorize it.
Run:
node src/setup.jsThis writes ~/.clawdbot/whoop/credentials.json (and optionally token.json if you paste tokens).
Postman is the most reliable bootstrap for many accounts because WHOOP may block browser-like traffic to the OAuth endpoints (or behave differently depending on headers).
Postman checklist (don’t skip these):
https://oauth.pstmn.io/v1/browser-callbackoffline (or you won’t get a refresh_token)client_secret_post)https://oauth.pstmn.io/v1/browser-callbackClientId = your WHOOP client idClientSecret = your WHOOP client secrethttps://api.prod.whoop.com/oauth/oauth2/authhttps://api.prod.whoop.com/oauth/oauth2/token{{ClientId}}{{ClientSecret}}offline plus any read scopes you need, e.g.:
offline read:profile read:sleep read:recovery read:workout read:cycles read:body_measurementloomingState)Click "Get New Access Token", sign in to WHOOP, and click "Grant".
In Postman’s "Manage Access Tokens" modal:
access_tokenrefresh_token
Postman often does not retain the refresh token for you later.~/.clawdbot/whoop/token.json:token.example.json as a templateobtained_at to current time in millisecondsredirect_uri to:
https://oauth.pstmn.io/v1/browser-callbacknode src/verify.js
node src/verify.js --refreshauth.js (may fail on some accounts)If you prefer a fully local OAuth loop (and WHOOP allows it), you can use auth.js.
Pre-req: add this redirect URI in WHOOP dashboard:
https://localhost:3000/callbackRun:
WHOOP_REDIRECT_URI='https://localhost:3000/callback' node src/auth.jsIf you need to do it from a phone/remote device:
WHOOP_REDIRECT_URI='https://localhost:3000/callback' node src/auth.js --manualNote: for localhost HTTPS, the script generates a self-signed cert and your browser will show a TLS warning. You must proceed past the warning so the redirect can complete.
node src/verify.js
node src/summary.jsNotAuthorizedException before the login pageThis is a WHOOP-side block on browser User-Agents hitting api.prod.whoop.com OAuth endpoints.
node src/auth.js which bootstraps the login URL and sends your browser directly to id.whoop.com.node src/auth.js --manual and open the printed URL.https://oauth.pstmn.io/v1/browser-callbackauth.js locally, also add:
https://localhost:3000/callbackTokens auto-refresh on demand (no cron needed). If issues persist:
rm ~/.clawdbot/whoop/token.json
node src/auth.jsThis usually means your access token is stale/invalidated (common if you re-auth or refresh tokens elsewhere; WHOOP refresh tokens rotate).
node src/auth.js, oraccess_token + refresh_token from Postman into ~/.clawdbot/whoop/token.json and update obtained_at.Use manual mode:
node src/auth.js --manualOpen the URL on any device, authorize, then copy the code from the callback URL.
error=request_forbidden / "The request is not allowed"This is WHOOP rejecting the authorization request after login/consent. Common causes:
https:// or whoop:// redirect URIs)If you suspect redirect URI policy, use an HTTPS tunnel:
# 1) Get a public HTTPS URL that forwards to localhost:3000 (example)
ngrok http 3000
# 2) Add the ngrok HTTPS URL + /callback to WHOOP dashboard Redirect URIs, then run:
WHOOP_REDIRECT_URI=https://YOUR-NGROK-DOMAIN.ngrok-free.app/callback node src/auth.jsIf you suspect scope restrictions, try a minimal scope set:
WHOOP_SCOPES="read:profile" node src/auth.jshttps://localhost:3000/callbackThis changes how the local callback server must run: it must be HTTPS (not HTTP).
The script supports this. Run:
WHOOP_REDIRECT_URI=https://localhost:3000/callback node src/auth.jsIt will generate a self-signed cert locally and your browser will likely show a warning for https://localhost.
Proceed past the warning so the redirect can complete.
These commands support:
--json (single JSON blob)--jsonl (one JSON object per line; useful for piping)--limit N (where supported)--days N, --since 7d / 12h, --start ISO, --end ISOnode src/summary.js --json
node src/recovery.js --json --limit 1
node src/sleep.js --json --limit 1
node src/strain.js --json --limit 1
node src/workouts.js --json --limit 1
# Examples with filters
node src/sleep.js --json --days 7
node src/workouts.js --jsonl --since 30d
node src/recovery.js --json --start 2026-01-01T00:00:00Z --end 2026-02-01T00:00:00Zf45fcb5
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.