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.

Deterministic Code
OuraStravaGoogle SheetsPersonal ProductivityData SyncDaily Digests
PromptCreate

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?
The row is still written with the date and all of your recovery numbers. The training columns are simply left blank, so you can still chart sleep and readiness across the full period.
What if my ring did not sync or I did not wear it overnight?
The date still gets its own row with blank metric cells rather than being skipped. That keeps the date column unbroken so any charts built on the sheet keep working.
Will this work if I log more than one workout in a day?
Yes. All of that day's sessions are combined into the single daily row, with the sports listed together and the durations and distances totalled.
Do I need a paid Oura membership?
If you have a Gen 3 ring or Ring 4, yes. An active Oura membership is required for your data to be available outside the app. Older rings are not affected.
Can I point this at a spreadsheet that already has data in it?
Yes. New rows are added after the last row already in the sheet, so your existing history stays untouched.
Why does it run in the morning instead of at midnight?
Oura finalises the previous night's sleep and readiness scores after you wake and the ring syncs. Running at 7am gives those numbers time to settle before the row is written.

Related templates

Review desk for portal forms your team still fills in by hand

Stage a batch of filings overnight, then approve each completed form from a screenshot before anything is ever submitted.

Kernel
Google Sheets
Slack Bot
App
Audit what Intercom's Fin AI actually resolved before you pay

Review every conversation Fin closed as resolved, judge which ones actually stuck, and see what the gap is worth against your bill.

Intercom
Google Sheets
Slack Bot
App
Returns and warranty claim desk that follows your policy

Work every return, damage and warranty claim in one queue, with the order, the delivery date and a policy-backed recommendation already on screen.

Kustomer
Shopify
Google Sheets
App
Turn last week's cafe sales into this week's grocery order

See exactly which ingredients next week needs based on what you actually sold, adjust anything by hand, then build a one-click grocery cart.

Instacart
Square
Google Sheets
App
Benchmark your Instagram account against rival brands

See follower growth, posting cadence, format mix and engagement rate for your brand and every competitor you track, side by side on one board.

Instagram
Google Sheets
Google Docs
App
Find the services you're underpricing in your Jobber price book

Open one screen to see how every service in your Jobber price book actually performed: how often it sold, what you charged, and where prices swing.

Jobber
Google Sheets
App

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.