Strava API Documentation

STRAVA API — PASCAL WAGENHOFER

Training Data API

This guide explains how to access Pascal’s Strava training data — runs, hikes, ski tours, bike rides — including heart rate, pace, elevation profile, and per-second streams. No Strava account or login required.

1. Access & Authentication

The API is accessible over HTTPS from any browser, curl command, Python script, or tool like Postman. Every request needs the API key added as a URL parameter.

Base URL
https://wagenhofer.ch/me/wp-json/strava/v1
API Key (append to every request)
?key=contact Pascal

Example — paste this directly into a browser to verify it works:

https://wagenhofer.ch/me/wp-json/strava/v1/stats?key=YOUR_KEY
Keep the key private. Do not share it publicly or commit it to code repositories. Contact Pascal if you need the key rotated.

2. Quick Start — 3 URLs to bookmark

🏃 Last 10 runs with HR and pace

https://wagenhofer.ch/me/wp-json/strava/v1/activities?key=YOUR_KEY&limit=10&type=Run

📈 Full lifetime training stats

https://wagenhofer.ch/me/wp-json/strava/v1/stats?key=YOUR_KEY

💕 Per-second HR + elevation for a specific activity

https://wagenhofer.ch/me/wp-json/strava/v1/activity/18781993073/streams?key=YOUR_KEY

Replace 18781993073 with the Strava activity ID (visible in the Strava URL or in the strava_id field of any activity).

3. All Endpoints

GET/stats
Lifetime totals across all activities — total distance, hours, elevation gain, calories, average HR, and breakdown by sport.

Example

https://wagenhofer.ch/me/wp-json/strava/v1/stats?key=YOUR_KEY

Response (excerpt)

“total_activities”: 757,
“total_km”: 8544.9,
“total_moving_h”: 900.1,
“total_elevation_m”: 208192,
“total_calories”: 607014,
“avg_heartrate”: 135.4,
“by_type”: {
“Run”: { “count”: 581, “km”: 6843.2 },
“Hike”: { “count”: 49, “km”: 192.3 },
“AlpineSki”: { “count”: 44, “km”: 846.2 },
“EBikeRide”: { “count”: 34, “km”: 492.3 }
}

GET/activities
List activities, newest first. Filter by sport type and/or date range.

Parameter Required Description
key Yes API key
limit Optional Number of results, 1–200. Default: 10
type Optional Filter by sport. See sport types below.
since Optional Only activities from this date onwards. Format: YYYY-MM-DD

Sport types

RunHikeAlpineSkiEBikeRideRideWorkoutKayaking

Examples

# Last 20 runs
https://wagenhofer.ch/me/wp-json/strava/v1/activities?key=YOUR_KEY&limit=20&type=Run

# All activities since 1 Jan 2026
https://wagenhofer.ch/me/wp-json/strava/v1/activities?key=YOUR_KEY&since=2026-01-01&limit=200

# Last 5 hikes
https://wagenhofer.ch/me/wp-json/strava/v1/activities?key=YOUR_KEY&limit=5&type=Hike

GET/activity/{strava_id}
Full detail for one activity — includes per-km splits, per-lap HR, best efforts, and route polyline.

Parameter Required Description
key Yes API key
streams Optional Set to 1 to also include per-second HR, distance, altitude in the same response

Examples

# Activity detail only
https://wagenhofer.ch/me/wp-json/strava/v1/activity/18781993073?key=YOUR_KEY

# Activity detail + per-second streams in one call
https://wagenhofer.ch/me/wp-json/strava/v1/activity/18781993073?key=YOUR_KEY&streams=1

GET/activity/{strava_id}/streams
Per-second time series: heartrate, distance, and altitude for the full activity. Fetched live from Strava — takes 1–2 seconds to respond.

Example

https://wagenhofer.ch/me/wp-json/strava/v1/activity/18781993073/streams?key=YOUR_KEY

Response

{
“strava_id”: 18781993073,
“resolution”: “high”, // always “high” (1-second resolution)
“data_points”: 3115, // number of seconds recorded
“hr_summary”: {
“min”: 111,
“max”: 184,
“avg”: 159.6
},
“data”: [
{ “t_s”: 78, “dist_m”: 194.1, “alt_m”: 472.0, “hr_bpm”: 141 },
{ “t_s”: 79, “dist_m”: 197.5, “alt_m”: 472.6, “hr_bpm”: 141 },
{ “t_s”: 80, “dist_m”: 200.7, “alt_m”: 472.8, “hr_bpm”: 141 },
// … one entry per second …
]
}

4. Field Reference

Every field returned by /activities and /activity/{id}, explained in plain terms.

Activity summary fields

strava_id
Unique Strava activity ID. Use this to fetch detail or streams for a specific session.
name
Activity title as Pascal set it in Strava.
type / sport_type
Sport category (e.g. Run) and sub-type (e.g. TrailRun).
date / start_time
Date and local start time of the activity (Switzerland timezone).
distance_km
Total distance in kilometres.
moving_time
Net moving time (HH:MM:SS) — excludes pauses.
elapsed_time
Total clock time including all pauses.
pace_per_km
Average pace in M:SS per kilometre (runs/hikes).
elevation_m
Total elevation gain in metres.
elev_high_m / elev_low_m
Highest and lowest GPS altitude during the activity.
avg_hr
Average heart rate in bpm for the whole activity.
max_hr
Peak heart rate in bpm.
cadence
Average step cadence in steps per minute (running).
calories
Estimated kcal burned.
suffer_score
Strava Suffer Score — a measure of training load based on HR zones.
avg_watts / w_avg_watts
Average and weighted-average running power (Garmin Running Power, if recorded).
kilojoules
Total work done in kJ (power-based activities).
device
Recording device, e.g. Garmin fēnix 8.
prs
Number of segment personal records set in this activity.
strava_url
Direct link to the activity on Strava.com.

Detail fields (single activity only)

splits_metric[]
Per-kilometre breakdown: distance, moving time, elevation change, avg HR, avg speed. One entry per km split.
laps[]
Per-lap breakdown (usually auto-lapped every km): avg HR, max HR, cadence, watts, pace zone.
best_efforts[]
Strava’s best effort times for standard distances (400m, 1km, 1 mile, 5km, 10km…) with PR rank.
map_polyline
Encoded route polyline. Paste into Google’s decoder to visualise the GPS track.
start_latlng / end_latlng
GPS coordinates of start and finish points.
segment_count
Number of named Strava segments matched during the activity.

5. Heart Rate & Elevation Streams (per-second)

The /streams endpoint goes beyond averages and gives you the complete second-by-second recording. Every row in the data array represents one second of the activity:

t_s
Elapsed seconds from activity start. Use this as your X-axis when charting.
dist_m
Cumulative distance in metres at that moment. Convert to km by dividing by 1000.
alt_m
GPS altitude in metres. Plot this to get the elevation profile.
hr_bpm
Heart rate in beats per minute at that second. Plot this to see cardiac response to terrain.
What you can do with stream data: plot HR over time to identify cardiac drift, overlay elevation and HR to see how Pascal responds to climbs, calculate time-in-zone, detect steady-state vs. surges, or export to any analysis tool.

How to find a Strava activity ID

Two ways:

  • From the /activities endpoint: look for the strava_id field in any activity.
  • From Strava.com: the number in the URL, e.g. strava.com/activities/18781993073

6. Coach Use Cases

Reviewing the last training block

https://wagenhofer.ch/me/wp-json/strava/v1/activities?key=YOUR_KEY&since=2026-05-01&limit=200

Returns every activity since 1 May 2026 with distance, HR, pace, elevation, and calories. Load into Excel or Google Sheets by pasting the URL into the JSON import tool.

Analysing a specific long run

https://wagenhofer.ch/me/wp-json/strava/v1/activity/18781993073?key=YOUR_KEY

Returns per-km splits and per-lap HR. Look at splits_metric[].avg_hr to see if HR was drifting upward (cardiac decoupling) or stable across the run.

Seeing exactly where HR spiked on a climb

https://wagenhofer.ch/me/wp-json/strava/v1/activity/18781993073/streams?key=YOUR_KEY

The full second-by-second log. Plot alt_m and hr_bpm against t_s on the same chart to correlate climbs with cardiac response.

Checking Google Sheets import

In Google Sheets, use Extensions → Apps Script and paste:

function importStrava() {
var url = “https://wagenhofer.ch/me/wp-json/strava/v1/activities?key=YOUR_KEY&limit=50&type=Run”;
var data = JSON.parse(UrlFetchApp.fetch(url).getContentText()).activities;
var sheet = SpreadsheetApp.getActiveSheet();
var headers = [“date”,”name”,”distance_km”,”moving_time”,”pace_per_km”,”avg_hr”,”max_hr”,”elevation_m”,”calories”,”suffer_score”,”strava_url”];
sheet.getRange(1,1,1,headers.length).setValues([headers]);
data.forEach(function(a, i) {
sheet.getRange(i+2,1,1,headers.length).setValues([[
a.date, a.name, a.distance_km, a.moving_time, a.pace_per_km,
a.avg_hr, a.max_hr, a.elevation_m, a.calories, a.suffer_score, a.strava_url
]]);
});
}

Run the function once to pull the last 50 runs into a spreadsheet. Change limit=50 or add &since=YYYY-MM-DD to adjust the range.

7. Tips & Limits

  • Data freshness: Activities sync automatically from Strava via webhook. New activities appear within a few minutes of Pascal finishing a session.
  • Streams are live: The /streams endpoint calls Strava’s API in real time. It takes 1–3 seconds to respond and requires an active internet connection on the server. If Strava is down, it will return an error.
  • Max results: The limit parameter goes up to 200. For larger exports, use since to paginate by date range.
  • HR not always present: Some activities (e.g. indoor workouts without a chest strap) may have no avg_hr. These fields will simply be absent from the response.
  • Streams resolution: Strava records at “high” resolution (1-second intervals during movement). Pauses in the activity are excluded from the stream — the t_s counter may jump.
  • Activity IDs never change: Once a Strava activity ID is noted, it always refers to the same activity. Safe to bookmark or store.
Questions or issues? Contact Pascal Wagenhofer directly — pascal@wagenhofer.ch. The API key can be rotated at any time if needed.

Strava Training Data API · wagenhofer.ch · Updated June 2026