2026Solo developer · Personal Project

WHOOP DASHBOARD

Next.jsSupabaseWHOOP APIOAuth 2.0VercelTypeScriptTailwind
View live

What WHOOP doesn't show you

WHOOP tracks recovery, strain, and sleep — but the app buries everything behind taps. There's no 7-day HRV sparkline. No way to overlay strain against sleep debt. No single-screen answer to "should I train today?" without opening three views and doing the math yourself. I wanted a dashboard that treats WHOOP data like a real analytics product — trends at a glance, derived insights, always current.

The dashboard

7-day trend sparklines for recovery, strain, and sleep. Each user connects via WHOOP OAuth. Credentials stored under Supabase row-level security — your data is scoped to your account, period. The rollout is invite-only: admin adds your email, you sign in and authorize WHOOP, dashboard pulls your metrics. Color-coded freshness indicators show how current each data point is.

Training readiness

The dashboard computes a training readiness score from multiple signals: recovery trend direction, HRV deviation from your personal baseline, cumulative sleep debt over the past week, and workout consistency. It's a weighted composite — not a simple average. A single bad night matters less than a three-day downward trend. The score updates as new data arrives from WHOOP.

The OAuth problem

WHOOP's OAuth has quirks. Token refresh timing is inconsistent. The API rate-limits aggressively. The data model changed between API versions. Getting reliable data without hammering their endpoints meant building a caching layer with smart refresh logic. Row-level security in Supabase is straightforward until you need to store per-user OAuth credentials while keeping the admin invite flow clean. More plumbing than expected.

Where it is now

Live at whoop-data.vercel.app. Invite-only. Connect once, get a persistent dashboard showing trends the native app doesn't surface. Every row scoped to its owner.