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
- πΊοΈ 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
- π 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
- π§ 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
- Visit https://strava-gif.pages.dev
- Create Strava API App (guided in app, takes 1-2 minutes):
- Go to Strava API Settings
- Fill in form with provided values
- Get your Client ID and Secret
- Authorize - Follow manual OAuth flow (copy/paste callback URL)
- Explore - Your activities appear on the map!
- Export GIFs - Customize and download animated GIFs
Everything runs in your browser. Your credentials and data never leave your device.
# 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 previewStrava API Setup for Local Dev:
- Create Strava API app with:
- Website:
http://localhost:9999 - Callback Domain:
localhost:9999
- Website:
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 β
βββββββββββββββ
Authentication & Data (/src/auth, /src/api):
StravaAuth.js- Manual OAuth flow, credential managementStravaAPI.js- Strava API client, activity fetching with paginationOnboardingUI.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)
- Vite - Build tool & dev server (fast HMR)
- Leaflet - Interactive maps
- CARTO - Map tiles (light gray style)
- gif.js - Client-side GIF encoding
- html2canvas - DOM-to-Canvas rendering
- Font Awesome - Icons
Users need their own Strava API application. The app guides them through this:
- Visit Strava API Settings
- Scroll to "My API Application"
- 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
- Application Name:
- Click Create
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.
The app uses manual OAuth flow:
- Click "Open Strava Authorization" (opens new tab)
- 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
- Click "Authorize" on Strava's page
- Browser shows error page - this is expected!
- Copy the entire URL from address bar
- Paste into the app - it extracts the authorization code automatically
- App exchanges code for access token
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
Deploy as a static website to any CDN. No server configuration needed!
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 distDeploy via Dashboard:
- Push to GitHub
- Go to Cloudflare Dashboard
- Pages β Create project β Connect to Git
- Select repository
- Build settings:
- Build command:
npm run build - Build output:
dist
- Build command:
- 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.
# Install gh-pages
npm install --save-dev gh-pages
# Build and deploy
npm run build
npx gh-pages -d distYour site: https://yourusername.github.io/strava-activity-map
Configure Strava API:
- Website:
https://yourusername.github.io - Callback:
yourusername.github.io
# Install Netlify CLI
npm install -g netlify-cli
# Deploy
npm run build
netlify deploy --prod --dir=distOr connect your GitHub repo in Netlify dashboard for auto-deploys.
# Install Vercel CLI
npm install -g vercel
# Deploy
vercelOr import from GitHub in Vercel dashboard.
Build and upload dist folder to:
- AWS S3 + CloudFront
- Google Cloud Storage
- Azure Static Web Apps
- Surge.sh
- Render
- Firebase Hosting
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)
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
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
Choose from 5 professionally designed themes:
- Strava - Official Strava colors (orange, blue, cyan, green, brown)
- Sunset - Warm palette (orange, yellow, red, coral)
- Ocean - Cool palette (blues, teals, navy)
- Forest - Nature palette (greens, browns, earth tones)
- Monochrome - Grayscale (black, grays, for minimalist look)
Each scheme has activity type-specific colors that maintain visual distinction.
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
- 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
- "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
- 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
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
# 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)None required! The app uses manual OAuth, so no environment variables or .env files are needed.
- β Chrome/Edge 90+
- β Firefox 88+
- β Safari 14+
- β Opera 76+
Required browser features:
- ES2020+ JavaScript
- Web Workers
- Canvas API
- Fetch API
- sessionStorage
"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
"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
"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)
"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
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
- Strava API - Activity data
- OpenStreetMap - Map data
- CARTO - Map tile rendering
- Leaflet - Map library by Vladimir Agafonkin
- gif.js - GIF encoding by Johan Nordberg
- html2canvas - DOM capture by Niklas von Hertzen
- Vite - Build tool by Evan You
- Font Awesome - Icons
- Built with Claude Code - Anthropic's AI-powered coding assistant
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.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - 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
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Strava API Docs: developers.strava.com
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.
