Track Oura recovery next to Strava training in one sheet
Every morning, yesterday's sleep, readiness and workout numbers land as one row in your spreadsheet so you can see how training and recovery move together.
Every morning at 7am, append yesterday's recovery and training numbers into a single Google Sheets tracker, so that over time I can see how training load and recovery move together. Use a cron trigger set to 7am daily.
First work out yesterday's date in my local timezone and format it as YYYY-MM-DD. Use that same value as both the start date and the end date on every Oura call, since Oura date parameters expect YYYY-MM-DD.
Pull the recovery side from Oura. Use List Daily Sleep for sleep score, total sleep duration and sleep efficiency. Use List Daily Readiness for readiness score, HRV balance and resting heart rate. Use List Daily Activity for steps and active calories. Use List Workouts to count any workouts Oura recorded that day.
Pull the training side from Strava with List Athlete Activities, filtered to yesterday only. Strava filters activities by epoch seconds, so convert yesterday's local start and end of day into epoch timestamps for the before and after parameters, then discard anything that falls outside yesterday. From each activity capture sport type, moving time, distance and average heart rate.
If there is more than one Strava activity on the day, combine them into the one daily row rather than writing multiple rows: join the distinct sport types with a comma, sum moving time, sum distance, and take the average heart rate weighted by each activity's moving time. Ignore activities with no heart rate data when computing that weighted average.
Write exactly one row per day using Append Values, with the Oura recovery columns and the Strava training columns side by side so a single row tells me what I did and how my body responded. Use this column order: Date, Sleep Score, Total Sleep (hours), Sleep Efficiency (%), Readiness Score, HRV Balance, Resting Heart Rate, Steps, Active Calories, Oura Workout Count, Strava Sport Types, Strava Moving Time (minutes), Strava Distance (km), Strava Average Heart Rate. Convert Oura sleep duration from seconds to hours and Strava distance from meters to kilometers, and round each to one decimal place.
Never skip a date. If Oura returns no data for the day, still write the row with the date filled in and the recovery metric cells left blank rather than omitting the date entirely. Do the same on rest days, where the Strava training cells are blank. The date column has to stay continuous or the charts built on this sheet break.
Two things to handle carefully. Oura collection responses paginate, returning a next_token field, so keep requesting with that token until it comes back null before deciding a day has no data. And Gen3 and Ring 4 users need an active Oura Membership or the API simply returns empty data, so treat an empty Oura response as a legitimate blank row rather than an error, and do not fail the run over it.
If the target sheet is empty, write the header row first using the column names above, then append the day's data row beneath it.
What does this prompt do?
- Adds one row per day to your spreadsheet every morning, covering the day before
- Puts your recovery numbers (sleep score, total sleep, sleep efficiency, readiness, HRV balance, resting heart rate, steps, active calories) side by side with the training you actually did
- Pulls each day's sessions (sport, moving time, distance, average heart rate) so a single row tells you what you did and how your body responded
- Always writes the date, even on days with no ring data or no workout, so your date column stays continuous and charts do not break
What do I need to use this?
- An Oura account with a ring that is syncing. Gen 3 and Ring 4 owners need an active Oura membership for data to come through
- A Strava account with your workouts recorded
- A Google account and a spreadsheet (plus the tab name) where the daily rows should collect
How can I customize it?
- Change the 7am run time to whatever fits your morning, or run it later if your ring syncs late
- Add or drop columns, for example bring in body temperature, stress, or elevation gain
- Point it at a different spreadsheet or tab, or keep separate trackers per training block
FAQs
What happens on a rest day when I do not train?
What if my ring did not sync or I did not wear it overnight?
Will this work if I log more than one workout in a day?
Do I need a paid Oura membership?
Can I point this at a spreadsheet that already has data in it?
Why does it run in the morning instead of at midnight?
Related templates
Every Monday, check every S3 bucket for public exposure, missing encryption and weak backup settings, then get the risks ranked in Slack.
Every weekday at 7am, sign in to the tender portals you track, filter new notices against your bid criteria, and open a deal for the ones worth chasing.
Every weekday at 4pm, spot the threads that went quiet, stage a ready-to-send nudge in your mailbox, and get a ranked Slack recap.
Keep a spreadsheet of your most important senders, and every email from one gets labeled, posted to your team channel, and logged automatically.
The moment an order is fulfilled, we register it with Yotpo so the review request is timed off real delivery, and we log every sync so failures never go unnoticed.
Every night at 11pm we compare the day's Shopify orders with your Zoho Books invoices and payments, and flag only what does not match.
Stop guessing why you felt flat today.
Get your recovery and your training in one row per day, built automatically every morning without you touching a spreadsheet.