Version: 2.0 Date: December 2025 Author: Benoit Boucher
Python tool to fetch and analyze your Strava activities via the official API. Export your data to multiple formats: JSON, CSV, and Markdown.
- Prerequisites
- Installation
- Configuration
- Usage
- Output Formats
- Available Scripts
- Project Structure
- Troubleshooting
Python
- Version: Python 3.7 or higher
- Check:
python --version
Required Python Modules
requests: HTTP requests to Strava APIpython-dotenv: Environment variables management
These modules will be installed automatically via requirements.txt.
- Have an active Strava account
- Have activities recorded on Strava
- Required to communicate with Strava API
- Local port 8000 available (for OAuth callback)
Place the activexport/ directory wherever you want.
activexport/
βββ .env.example # Configuration file template
βββ .gitignore # Files to ignore (Git)
βββ requirements.txt # Python dependencies
βββ activexport_auth.py # Authentication script
βββ activexport_fetch_activities.py # Fetch activities
βββ activexport_get_activity_details.py # Activity details
βββ README.md # This documentation
cd activexport
pip install -r requirements.txtVerification:
python -c "import requests; import dotenv; print('OK')"If "OK" is displayed, the modules are properly installed.
1. Access the developer portal
Go to: https://www.strava.com/settings/api
You must be logged into your Strava account.
2. Create the application
Click on "Create an App" and fill in:
| Field | Recommended Value |
|---|---|
| Application Name | Running Analysis Tool (or your name) |
| Category | Data Importer or Visualizer |
| Club | Leave empty (or your club) |
| Website | http://localhost |
| Application Description | Personal running data analysis |
| Authorization Callback Domain | localhost |
localhost (without http://, without port).
3. Accept the terms
- Check "I agree to Strava API Agreement"
- Click on "Create"
4. Retrieve your Credentials
After creation, Strava displays:
Client ID: [a number, e.g.: 123456]
Client Secret: [an alphanumeric string]
- Note these 2 values carefully
- NEVER share them publicly
- They are personal and confidential
1. Create the .env file
In the activexport/ directory, create a file named .env (without extension).
On Windows:
copy NUL .envOn Linux/Mac:
touch .env2. Edit the .env file
Open .env with a text editor and add:
# Strava API Credentials
# β οΈ NEVER COMMIT THIS FILE TO GIT
STRAVA_CLIENT_ID=YOUR_CLIENT_ID
STRAVA_CLIENT_SECRET=YOUR_CLIENT_SECRET
# Tokens will be added automatically after first authentication
STRAVA_ACCESS_TOKEN=
STRAVA_REFRESH_TOKEN=
STRAVA_TOKEN_EXPIRES_AT=Replace:
YOUR_CLIENT_IDwith the Client ID provided by StravaYOUR_CLIENT_SECRETwith the Client Secret provided by Strava
Example (fictional values):
STRAVA_CLIENT_ID=123456
STRAVA_CLIENT_SECRET=abc123def456ghi789jkl012mno345pqr678stu903. Save
The .env file is automatically protected by .gitignore.
1. Run the authentication script
python activexport_auth.py2. What will happen?
The script will:
- Open your browser automatically
- Redirect you to Strava to authorize the application
- Start a local server (http://localhost:8000)
- Wait for you to accept the authorization on Strava
3. On the Strava page
- Check the requested permissions:
read: Read your public dataactivity:read_all: Read all your activitiesprofile:read_all: Read your complete profile
- Click on "Authorize"
4. Success
The browser will display:
Strava authentication successful!
You can close this window and return to the terminal.
In the terminal:
============================================================
AUTHENTICATION SUCCESSFUL!
============================================================
Athlete: [Your Name]
Token expires at: [Date]
Tokens saved to: activexport_tokens.json
5. Created files
A activexport_tokens.json file has been created automatically. It contains your access tokens.
.gitignore).
python activexport_auth.py testExpected result:
============================================================
STRAVA API CONNECTION TEST
============================================================
API connection successful!
Athlete Profile:
Name: [Your Name]
City: [Your City]
Country: France
Weight: [Your Weight] kg
...
API ready to fetch your activities!
β If this message is displayed, the API is configured!
Display help for any script:
python activexport_fetch_activities.py --help
python activexport_get_activity_details.py --helppython activexport_fetch_activities.pyWhat the script does:
- Fetches ALL your activities since the creation of your Strava account
- Displays global statistics on screen
- No files created (stdout only)
Example output:
============================================================
FETCHING STRAVA ACTIVITIES
============================================================
[Page 1] Fetching max 200 activities...
-> 200 activities fetched
...
TOTAL: 1527 activities fetched
============================================================
ACTIVITY ANALYSIS
============================================================
Distribution by sport type:
Run : 786 activities
TrailRun : 132 activities
...
Global statistics:
Total distance: 15540.1 km
Total elevation: 174412 m
Total time: 1629.4 hours
Export to JSON:
python activexport_fetch_activities.py -f jsonCreates: ./output/activexport_activities_YYYYMMDD_HHMMSS.json
Export to CSV:
python activexport_fetch_activities.py -f csvCreates: ./output/activexport_activities_YYYYMMDD_HHMMSS.csv
Export to Markdown:
python activexport_fetch_activities.py -f mdCreates: ./output/activexport_activities_YYYYMMDD_HHMMSS.md
Export to multiple formats:
python activexport_fetch_activities.py -f json -f csv -f mdCreates all 3 files simultaneously.
python activexport_fetch_activities.py -f json -o ./my_exports/Saves the JSON file to ./my_exports/ instead of ./output/.
python activexport_fetch_activities.py "search term"Examples:
# Find all "Sancy" trails
python activexport_fetch_activities.py "sancy"
# Find all "Team RM" outings
python activexport_fetch_activities.py "Team RM"
# Find and export to JSON
python activexport_fetch_activities.py "maines" -f jsonExample output:
3 activity(ies) found containing 'sancy':
[24/09/2022] Trail du Sancy
33.15 km - 2029 m elevation
ID: 7812345678
...
When using -f, only the matching activities are exported.
python activexport_get_activity_details.py <activity_id>Example:
python activexport_get_activity_details.py 6018412458Output:
============================================================
ACTIVITY DETAILS
============================================================
Name: Trail de la Digue
Date: 25/09/2021 10:00
Type: TrailRun
ID: 6018412458
METRICS:
Distance: 51.00 km
Elevation gain: 0 m D+
Time: 06h04'20"
Average pace: 7'08"/km
EQUIPMENT:
HOKA Challenger ATR 5 (1041.5 km)
Export to JSON:
python activexport_get_activity_details.py 6018412458 -f jsonCreates: ./output/activity_6018412458.json
Export to Markdown:
python activexport_get_activity_details.py 6018412458 -f mdCreates: ./output/activity_6018412458.md
Export to both:
python activexport_get_activity_details.py 6018412458 -f json -f mdCustom output directory:
python activexport_get_activity_details.py 6018412458 -f json -o ./my_data/Structure for activities:
{
"metadata": {
"export_date": "2025-12-05T19:30:00",
"total_activities": 1527,
"source": "Strava API v3"
},
"activities": [
{
"id": 6018412458,
"name": "Trail de la Digue",
"sport_type": "TrailRun",
"distance": 51000,
"total_elevation_gain": 0,
"moving_time": 21860,
...
}
]
}Use cases:
- Data analysis with Python/R
- Import into databases
- Machine learning datasets
- Programmatic processing
Columns:
date,name,type,distance_km,elevation_m,moving_time,elapsed_time,avg_pace,avg_hr,max_hr
2025-12-05,Morning Run,Run,10.5,120,3600,3720,5'43",145,165
2025-12-04,Trail,TrailRun,17.0,300,7920,8100,7'46",142,170Use cases:
- Open in Excel/LibreOffice Calc
- Import into Google Sheets
- Quick data visualization
- Pivot tables and charts
Example for activities list:
# Strava Activities Export
**Generated:** 2025-12-05 19:30:00
**Total Activities:** 1527
## Summary Statistics
- **Total Distance:** 15,540.1 km
- **Total Elevation:** 174,412 m
- **Total Time:** 1,629.4 hours
## Activities by Sport Type
| Sport Type | Count |
|------------|-------|
| Run | 786 |
| TrailRun | 132 |
## Recent Activities
| Date | Name | Type | Distance | Elevation | Time |
|------|------|------|----------|-----------|------|
| 2025-12-05 | Morning Run | Run | 10.5 km | 120 m | 1h00' |Example for activity details:
# Activity Details: Trail de la Digue
**ID:** 6018412458
**Date:** 2021-09-25 10:00
**Type:** TrailRun
## Metrics
- **Distance:** 51.00 km
- **Elevation gain:** 0 m D+
- **Time:** 06h04'20"
- **Average pace:** 7'08"/kmUse cases:
- Documentation
- Blog posts
- GitHub READMEs
- Easy to read and share
Function: OAuth2 authentication management
Commands:
python activexport_auth.py # Initial authentication
python activexport_auth.py test # Test the connectionFeatures:
- Opens browser for Strava authorization
- Exchanges authorization code for tokens
- Automatically refreshes expired tokens
- Saves tokens to
activexport_tokens.json
Function: Fetch all activities and export to multiple formats
Usage:
python activexport_fetch_activities.py [OPTIONS] [SEARCH]Options:
-h, --help: Show help message-f, --format FORMAT: Output format (json, csv, md). Can be used multiple times-o, --output DIR: Output directory (default:./output)
Examples:
# Display only (no export)
python activexport_fetch_activities.py
# Export to JSON
python activexport_fetch_activities.py -f json
# Export to all formats
python activexport_fetch_activities.py -f json -f csv -f md
# Search and export
python activexport_fetch_activities.py "trail" -f json
# Custom output directory
python activexport_fetch_activities.py -f json -o ./my_exports/Features:
- Automatic pagination (200 activities/page)
- API limits management (automatic pause)
- Multiple export formats: JSON, CSV, Markdown
- Analysis by sport type
- Global statistics (distance, elevation, time)
- Search by activity name
- Customizable output directory
Function: Complete details of a specific activity
Usage:
python activexport_get_activity_details.py ACTIVITY_ID [OPTIONS]Options:
-h, --help: Show help message-f, --format FORMAT: Output format (json, md). Can be used multiple times-o, --output DIR: Output directory (default:./output)
Examples:
# Display only
python activexport_get_activity_details.py 6018412458
# Export to JSON
python activexport_get_activity_details.py 6018412458 -f json
# Export to JSON and Markdown
python activexport_get_activity_details.py 6018412458 -f json -f md
# Custom output directory
python activexport_get_activity_details.py 6018412458 -f json -o ./data/Extracted data:
- Name, date, type, ID
- Distance, elevation, time
- Average pace
- Average/max HR (if available)
- Min/max altitude
- Cadence
- Equipment used
- Description/comments
activexport/
βββ .env # β οΈ Credentials (DO NOT COMMIT)
βββ .env.example # .env template
βββ .gitignore # Sensitive files protection
βββ requirements.txt # Python dependencies
βββ activexport_tokens.json # β οΈ OAuth2 tokens (DO NOT COMMIT)
βββ activexport_auth.py # OAuth2 authentication
βββ activexport_fetch_activities.py # Fetch activities
βββ activexport_get_activity_details.py # Activity details
βββ README.md # Documentation
output/ # Default output directory
βββ activexport_activities_YYYYMMDD_HHMMSS.json
βββ activexport_activities_YYYYMMDD_HHMMSS.csv
βββ activexport_activities_YYYYMMDD_HHMMSS.md
βββ activity_XXXXXXXXX.json
βββ activity_XXXXXXXXX.md
.env: Your API credentialsactivexport_tokens.json: Your access tokensoutput/: Your personal activity data
These files are automatically protected by .gitignore.
Strava tokens expire every 6 hours.
β Good news: Refresh is AUTOMATIC!
The activexport_auth.py script contains the get_valid_access_token() function which:
- Checks if the token is expired
- Refreshes it automatically if necessary
- Saves the new token
You don't have to do anything!
If you want to revoke application access:
- Go to https://www.strava.com/settings/apps
- Find your application
- Click on "Revoke Access"
To reactivate, simply run again:
python activexport_auth.pyCause: Python dependencies not installed
Solution:
pip install -r requirements.txtCause: Initial authentication not performed
Solution:
python activexport_auth.pyCause: Invalid or revoked token
Solution:
# Delete the tokens file
rm activexport_tokens.json # Linux/Mac
del activexport_tokens.json # Windows
# Re-authenticate
python activexport_auth.pyCause: Strava API limit reached
Limits:
- 100 requests / 15 minutes (read)
- 1000 requests / day (read)
Solution: Wait 15 minutes (automatic handling in scripts)
Cause: Automatic browser opening issue
Manual solution:
- Copy the URL displayed in the terminal
- Open it manually in your browser
- Authorize the application
- You will be redirected to localhost:8000
Cause: Port 8000 already in use
Solution:
# Find process using port 8000
# Windows
netstat -ano | findstr :8000
# Linux/Mac
lsof -i :8000
# Stop the process or change portSymptom: Special characters display incorrectly in Excel
Cause: Excel doesn't automatically detect UTF-8
Solution:
- Open Excel
- Data β Get Data β From Text/CSV
- Select encoding: UTF-8
- Import
Or open directly in Google Sheets (automatic UTF-8 detection).
| Type | Limit | Period |
|---|---|---|
| Read | 100 requests | 15 minutes |
| Read | 1000 requests | 24 hours |
| Global | 200 requests | 15 minutes |
| Global | 2000 requests | 24 hours |
β Accessible via API:
- All activities (complete history)
- Activity details (distance, time, HR, etc.)
- Athlete profile
- Equipment/shoes
- Crossed segments
- Photos
β Not accessible:
- Private activities of other athletes
- High-frequency stream data (requires additional scope)
Files to NEVER share/commit:
.env: Your credentialsactivexport_tokens.json: Your access tokensoutput/: Your personal activity data
The .gitignore file automatically protects these files if you use Git.
The application only requests:
read: Read public dataactivity:read_all: Read all your activities (even private)profile:read_all: Read your complete profile
No write or modification permissions.
- API Reference: https://developers.strava.com/docs/reference/
- OAuth Guide: https://developers.strava.com/docs/authentication/
- Playground: https://developers.strava.com/playground/
- Python Documentation: https://docs.python.org/3/
- Requests Documentation: https://requests.readthedocs.io/
New Features:
- β Multi-format export: JSON, CSV, Markdown
- β Customizable output directory
- β
--helpoption for all scripts - β Multiple formats in single export
- β Improved command-line interface
Previous Features (v1.0):
- β Complete OAuth2 authentication
- β Fetch all activities
- β Search by name
- β Activity details
- β Automatic token refresh
- β API limits management
Document created on: December 5, 2025 Last updated: December 5, 2025 Author: Benoit Boucher
First use:
- Install dependencies (
pip install -r requirements.txt) - Create Strava application
- Configure
.env - Authenticate (
python activexport_auth.py) - Test (
python activexport_auth.py test) - Fetch activities (
python activexport_fetch_activities.py)
Daily usage:
# Display activities
python activexport_fetch_activities.py
# Export to JSON and CSV
python activexport_fetch_activities.py -f json -f csv
# Search and export
python activexport_fetch_activities.py "trail" -f json
# Get activity details
python activexport_get_activity_details.py 6018412458 -f mdMaintenance:
- Tokens refresh automatically
- No action required except manual revocation
Happy running! πββοΈ
