Skip to content

Visualize and animate Strava activities on a map over time

Notifications You must be signed in to change notification settings

pqzdev/strava-activity-map

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

85 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Strava Activity Map Visualizer

Visualize and animate your Strava activities on an interactive map. Export beautiful animated GIFs showing your fitness journey over time!

πŸ”’ 100% Privacy-First: Runs entirely in your browser using manual OAuth. No backend server. You use your own Strava API credentials.

🌍 Live Demo: https://strava-gif.pages.dev

⚠️ Disclaimer: This project is not affiliated with, endorsed by, or connected to Strava, Inc. in any way. This is an independent, open-source visualization tool that uses the public Strava API.

Example animation


✨ Features

Core Functionality

  • πŸ—ΊοΈ Interactive Map Visualization - View all your activities on a dynamic map with Leaflet
  • ⏱️ Time-based Animation - Watch your activities appear chronologically over time
  • 🎨 Multi-Color Schemes - Choose from 5 built-in color themes (Strava, Sunset, Ocean, Forest, Monochrome)
  • 🎬 High-Quality GIF Export - Export animations with custom dimensions, FPS, and date ranges
  • πŸ“± Capture Presets - Quick aspect ratios (Square, Vertical/Horizontal phone, Free drag)
  • 🎯 Flexible Capture Box - Visual capture area with shaded overlay for precise framing
  • πŸ”„ Activity Type Filtering - Show/hide specific activity types (Run, Ride, Swim, etc.)
  • πŸ“Š Real-time Stats - Activity count, total distance, and activity type breakdown

Privacy & Security

  • πŸ”’ 100% Client-Side - All processing happens in your browser
  • πŸ” Manual OAuth Flow - Secure authorization without redirect server
  • πŸ’Ύ Session Storage - Credentials and data auto-clear when tab closes
  • 🚫 No Backend - Deploy as static site to any CDN
  • πŸ”“ Open Source - Audit the code yourself

User Experience

  • 🧭 Guided Onboarding - Step-by-step setup wizard
  • πŸ“ Smart Map Positioning - Auto-fits all your activities or restores from URL
  • πŸ’‘ Helpful Instructions - Interactive popup explaining all features
  • ♻️ Refresh Activities - Re-fetch from Strava anytime
  • πŸšͺ Logout Function - Clear all data with one click

πŸš€ Quick Start

For End Users (Using Deployed Site)

  1. Visit https://strava-gif.pages.dev
  2. Create Strava API App (guided in app, takes 1-2 minutes):
  3. Authorize - Follow manual OAuth flow (copy/paste callback URL)
  4. Explore - Your activities appear on the map!
  5. Export GIFs - Customize and download animated GIFs

Everything runs in your browser. Your credentials and data never leave your device.

For Developers (Local Development)

# Clone the repository
git clone https://github.com/pqzdev/strava-activity-map.git
cd strava-activity-map

# Install dependencies
npm install

# Run development server
npm run dev
# Opens at http://localhost:5173

# Build for production
npm run build

# Preview production build
npm run preview

Strava API Setup for Local Dev:

  • Create Strava API app with:
    • Website: http://localhost:9999
    • Callback Domain: localhost:9999

πŸ—οΈ Architecture

System Design

This is a fully static single-page application with no backend server:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  User's Browser β”‚
β”‚                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚sessionStorageβ”‚ ←─ Credentials, tokens, activities
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Leaflet  β”‚  β”‚ ←─ Map rendering
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  gif.js   β”‚  β”‚ ←─ GIF encoding (Web Worker)
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β”‚ HTTPS (direct API calls)
         ↓
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ Strava API  β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Components

Authentication & Data (/src/auth, /src/api):

  • StravaAuth.js - Manual OAuth flow, credential management
  • StravaAPI.js - Strava API client, activity fetching with pagination
  • OnboardingUI.js - Multi-step setup wizard with visual styling

Visualization (/src/animation):

  • AnimationController.js - Time-based activity animation engine
  • Supports play/pause, speed control, timeline scrubbing
  • Real-time date display and progress tracking

Export (/src/export):

  • GifExporter.js - Browser-based GIF generation
  • Uses html2canvas for map capture
  • gif.js Web Worker for encoding (doesn't block UI)
  • Custom dimensions, FPS, duration, date ranges

Utilities (/src/utils):

  • polyline.js - Google Polyline decoding (Strava's format)

Technology Stack


πŸ“‹ Strava API Setup (Step-by-Step)

Users need their own Strava API application. The app guides them through this:

Step 1: Create API Application

  1. Visit Strava API Settings
  2. Scroll to "My API Application"
  3. Fill in the form:
    • Application Name: My Activity Map (or any name)
    • Category: Visualizer (recommended)
    • Club: Leave blank
    • Website: http://localhost:9999 (for manual OAuth)
    • Authorization Callback Domain: localhost:9999
  4. Click Create

Step 2: Get Credentials

After creation, you'll see:

  • Client ID: A number (e.g., 123456)
  • Client Secret: A long string (e.g., abc123def456...)

Copy these - you'll enter them in the app.

Step 3: Authorize

The app uses manual OAuth flow:

  1. Click "Open Strava Authorization" (opens new tab)
  2. IMPORTANT: You must grant "View data about your private activities" permission
    • Strava requires this to access ANY activities (public or private)
    • You can control visibility in the app later
  3. Click "Authorize" on Strava's page
  4. Browser shows error page - this is expected!
  5. Copy the entire URL from address bar
  6. Paste into the app - it extracts the authorization code automatically
  7. App exchanges code for access token

Step 4: Fetch Activities

Click "Fetch Activities from Strava":

  • Fetches all your activities via API
  • Shows progress (activities fetched so far)
  • Caches in sessionStorage (clears on tab close)
  • Typically takes 10-60 seconds depending on activity count

πŸš€ Deployment

Deploy as a static website to any CDN. No server configuration needed!

Cloudflare Pages (Recommended - Production)

This repository is deployed to Cloudflare Pages at https://strava-gif.pages.dev

Deploy via CLI:

# Install Wrangler
npm install -g wrangler

# Login to Cloudflare
wrangler login

# Deploy
npm run deploy
# or: wrangler pages deploy dist

Deploy via Dashboard:

  1. Push to GitHub
  2. Go to Cloudflare Dashboard
  3. Pages β†’ Create project β†’ Connect to Git
  4. Select repository
  5. Build settings:
    • Build command: npm run build
    • Build output: dist
  6. Deploy!

Benefits:

  • βœ… Free tier: Unlimited requests, 500 builds/month
  • βœ… Global CDN with 300+ locations
  • βœ… Automatic HTTPS
  • βœ… Instant cache invalidation
  • βœ… Git integration (auto-deploy on push)

See CLOUDFLARE_DEPLOYMENT.md for detailed guide.

GitHub Pages

# Install gh-pages
npm install --save-dev gh-pages

# Build and deploy
npm run build
npx gh-pages -d dist

Your site: https://yourusername.github.io/strava-activity-map

Configure Strava API:

  • Website: https://yourusername.github.io
  • Callback: yourusername.github.io

Netlify

# Install Netlify CLI
npm install -g netlify-cli

# Deploy
npm run build
netlify deploy --prod --dir=dist

Or connect your GitHub repo in Netlify dashboard for auto-deploys.

Vercel

# Install Vercel CLI
npm install -g vercel

# Deploy
vercel

Or import from GitHub in Vercel dashboard.

Any Static Host

Build and upload dist folder to:

  • AWS S3 + CloudFront
  • Google Cloud Storage
  • Azure Static Web Apps
  • Surge.sh
  • Render
  • Firebase Hosting

πŸ”’ Privacy & Security

Data Storage (Client-Side Only)

Stored in sessionStorage (auto-cleared when tab closes):

  • Strava Client ID & Client Secret
  • OAuth access token & refresh token
  • Athlete profile (name, ID)
  • Fetched activities data (polylines, timestamps, metadata)

Never stored:

  • ❌ No permanent storage (localStorage is not used)
  • ❌ No cookies
  • ❌ No server-side storage
  • ❌ No analytics or tracking (by default)

Data Flow

1. User creates Strava API app β†’ Gets credentials
2. User enters credentials β†’ Stored in sessionStorage
3. User authorizes β†’ Manual OAuth (copy/paste URL)
4. App exchanges code β†’ Gets access token from Strava
5. App fetches activities β†’ Direct from Strava API to browser
6. App renders map β†’ Client-side with Leaflet.js
7. User exports GIF β†’ Generated in-browser with gif.js
8. User closes tab β†’ All sessionStorage cleared automatically

Security Best Practices

What the app does:

  • βœ… Uses HTTPS for all API calls
  • βœ… Never sends credentials to any server (there is no server!)
  • βœ… Clears sensitive data on logout
  • βœ… Uses sessionStorage (not localStorage)
  • βœ… Open source (audit the code)

What users should know:

  • πŸ” Your Client Secret is sensitive - don't share it
  • πŸ” Anyone with your credentials can access your Strava data
  • πŸ” Strava rate limits: 100 requests/15min, 1000 requests/day
  • πŸ” Refresh tokens expire after 6 hours (Strava limitation)
  • πŸ” App does NOT store or transmit your data anywhere

🎨 Features In Detail

Color Schemes

Choose from 5 professionally designed themes:

  1. Strava - Official Strava colors (orange, blue, cyan, green, brown)
  2. Sunset - Warm palette (orange, yellow, red, coral)
  3. Ocean - Cool palette (blues, teals, navy)
  4. Forest - Nature palette (greens, browns, earth tones)
  5. Monochrome - Grayscale (black, grays, for minimalist look)

Each scheme has activity type-specific colors that maintain visual distinction.

Capture Box

Visual framing for GIF exports:

  • Aspect Ratio Presets:

    • Max - Entire visible map
    • Square - 1:1 (Instagram posts)
    • Vertical - 9:16 (Instagram stories, TikTok)
    • Horizontal - 16:9 (YouTube, presentations)
    • Free - Drag to any size/ratio
  • Visual Overlay: Shades area outside capture box for precise framing

  • Handles: Drag corners to resize in Free mode

Animation Controls

  • Play/Pause: Watch activities appear chronologically
  • Timeline Slider: Scrub to any point in time
  • Speed Control: 1-100 days per second (adjustable while playing)
  • Date Display: Shows current date in animation
  • Reset: Jump back to start

Activity Filtering

  • "All" Toggle: Select/deselect all activity types
  • Individual Types: Click pills to show/hide (Run, Ride, Swim, Walk, etc.)
  • Visual Feedback: Selected pills highlighted in Strava orange
  • Real-time Updates: Map and stats update immediately

GIF Export

  • Date Range: Export specific time periods (start/end date pickers)
  • Custom Dimensions: Width 400-3840px, Height 300-2160px
  • Frame Rate: 10/15/20/30 FPS (higher = smoother but larger file)
  • Duration: 1-60 seconds
  • Size Estimate: Real-time file size prediction
  • Progress Bar: Visual feedback during generation
  • Download Link: Direct download when complete

πŸ“¦ Development

Project Structure

strava-activity-map/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ auth/
β”‚   β”‚   └── StravaAuth.js          # OAuth & session management
β”‚   β”œβ”€β”€ api/
β”‚   β”‚   └── StravaAPI.js           # Strava API client
β”‚   β”œβ”€β”€ ui/
β”‚   β”‚   └── OnboardingUI.js        # Setup wizard (5 steps)
β”‚   β”œβ”€β”€ animation/
β”‚   β”‚   └── AnimationController.js # Time-based animation engine
β”‚   β”œβ”€β”€ export/
β”‚   β”‚   └── GifExporter.js         # GIF generation with gif.js
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   └── polyline.js            # Polyline decoding utility
β”‚   └── main.js                    # App initialization & UI logic
β”œβ”€β”€ public/
β”‚   └── gif.worker.js              # GIF encoder Web Worker
β”œβ”€β”€ experiments/
β”‚   β”œβ”€β”€ gif-size-estimation.md     # GIF size experiment protocol
β”‚   └── run-gif-size-tests.js      # Automated testing script
β”œβ”€β”€ index.html                     # Single page app
β”œβ”€β”€ vite.config.js                 # Vite build configuration
β”œβ”€β”€ package.json                   # Dependencies & scripts
β”œβ”€β”€ CLOUDFLARE_DEPLOYMENT.md       # Cloudflare Pages guide
└── README.md                      # This file

npm Scripts

# Development
npm run dev          # Start dev server (localhost:5173)
npm run build        # Build for production (outputs to dist/)
npm run preview      # Preview production build locally

# Deployment
npm run deploy       # Deploy to Cloudflare Pages (requires wrangler)

# Legacy scripts (not used in browser app)
npm run auth         # CLI authentication (creates .tokens file)
npm run fetch        # CLI activity fetch (creates activities.json)

Environment Variables

None required! The app uses manual OAuth, so no environment variables or .env files are needed.

Browser Compatibility

  • βœ… Chrome/Edge 90+
  • βœ… Firefox 88+
  • βœ… Safari 14+
  • βœ… Opera 76+

Required browser features:

  • ES2020+ JavaScript
  • Web Workers
  • Canvas API
  • Fetch API
  • sessionStorage

πŸ› Troubleshooting

OAuth / Authorization Issues

"You need to grant access to view activities"

  • Strava requires "View data about your private activities" permission to access ANY activities
  • This is a Strava API requirement, not an app choice
  • You can control which activities appear on the map using in-app filters
  • The app runs entirely in your browser - data stays with you

"Authorization Error" or "Failed to exchange code"

  • βœ… Verify Client ID and Secret are correct (no spaces)
  • βœ… Check that you copied the ENTIRE callback URL
  • βœ… Make sure callback domain matches (for deployed sites)
  • βœ… Try generating a new Client Secret on Strava

Activity Fetching Issues

"Failed to fetch activities"

  • βœ… Check browser console (F12) for detailed error
  • βœ… Verify authorization succeeded (check sessionStorage in DevTools)
  • βœ… Check Strava rate limits: 100 requests/15min, 1000/day
  • βœ… Try again in 15 minutes if rate limited

"No activities appear on map"

  • βœ… Make sure you have GPS activities (with polylines)
  • βœ… Virtual activities (Zwift, treadmill) don't have GPS data
  • βœ… Check activity type filters - may be hidden
  • βœ… Try refreshing activities

GIF Export Issues

"Export failed" or slow generation

  • βœ… Reduce dimensions (try 800Γ—600)
  • βœ… Lower FPS (try 10 FPS)
  • βœ… Shorter duration (try 5 seconds)
  • βœ… Use Chrome/Edge (best Canvas performance)
  • βœ… Close other tabs to free memory
  • βœ… Don't interact with page during export

"Out of memory" error

  • βœ… Too many activities in date range (reduce range)
  • βœ… Dimensions too large (max 1920Γ—1080 recommended)
  • βœ… Duration too long (max 15s recommended)
  • βœ… Try incognito mode (no extensions)

Storage Issues

"sessionStorage full"

  • βœ… Rare but possible with 10,000+ activities
  • βœ… Try exporting smaller date ranges
  • βœ… Refresh page to clear and re-fetch
  • βœ… App will try to compress data if needed

🎯 Future Ideas

Potential features for contributions:

  • Import from GPX/FIT files (no Strava account needed)
  • Heatmap mode (highlight most-traveled routes)
  • 3D terrain visualization
  • Video export (WebM/MP4)
  • Custom map styles (satellite, terrain)
  • Activity type statistics (charts, graphs)
  • Route comparison tool
  • Share links (save map state in URL)
  • Multiple athlete comparison
  • Kudos/comments overlay

πŸ™ Credits & Attributions


πŸ“„ License

MIT License - see LICENSE file

Copyright (c) 2024

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software.


🀝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Before submitting:

  • Test locally with npm run dev
  • Build without errors (npm run build)
  • Follow existing code style
  • Update README if adding features

πŸ’¬ Support


⭐ Star this repo if you find it useful!

Found a bug? Open an issue. Have a feature idea? Open a discussion. Want to contribute? PRs welcome!


Made with ❀️ by developers who love running, cycling, and open source.

About

Visualize and animate Strava activities on a map over time

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •