Why does this exist? Gear-shifting data has been a long-standing feature request in the Strava community — cyclists with electronic groupsets (Shimano Di2, SRAM AXS, Campagnolo EPS) upload FIT files that contain every shift event, yet Strava doesn't surface any of it. The request didn't seem to be moving, so I built my own tool. You may find it useful or, at the very least, interesting.
Visualize your Shimano Di2 electronic gear shift data on Strava — see exactly what gear you were in at every point on the elevation profile, with interactive gear statistics, an animated drivetrain replay, and real-time shifting analysis.
Di2va browser extension injected on a Strava activity page — shifting quality score, gear usage cards, gear-colored elevation profile with drag-to-zoom, animated drivetrain replay with real-time shifting analysis.
Now available on Firefox Add-ons — install with one click, auto-updates included.
The extension injects Di2va directly into Strava activity pages — no separate web app, no OAuth setup. It uses your existing Strava browser session to fetch streams and FIT data.
- No OAuth setup — Uses your existing Strava session (no API keys needed)
- Elevation Chart with Gear-Colored Segments — Full-width elevation profile below the Strava map, color-coded by gear
- Drag-to-Zoom — Select a section of the elevation chart to zoom in with section scores
- Animated Drivetrain Replay — SVG transmission animation plays back your ride with cadence-driven crank rotation
- Real-Time Shifting Analysis — Live tick/cross feedback on cadence efficiency, cross-chain avoidance, and gradient matching as playback progresses
- Coasting & Stopped Detection — Distinguishes between pedalling, coasting, and stopped states
- Playback Controls — Play/pause, speed (1×–20×), scrubber, and time display
- Dark Mode — Automatic detection of Strava/Sauce dark themes
- Unit Detection — Reads your Strava unit preferences (metric/imperial)
- Firefox & Chrome — MV3 WebExtension compatible with both browsers
One click, auto-updates included. Requires Firefox 140+.
- Clone and build the extension:
git clone https://github.com/vinfnet/Di2va.git
cd Di2va/extension
npm install
npm run build- Open
about:debugging#/runtime/this-firefoxin Firefox - Click Load Temporary Add-on...
- Select any file inside the
extension/dist/folder (e.g.manifest.json) - Navigate to any Strava activity page — Di2va appears below the map
Note: Temporary add-ons are removed when Firefox restarts. Once the AMO review is complete, the extension will auto-update from the Firefox Add-ons site.
git clone https://github.com/vinfnet/Di2va.git
cd Di2va/extension
npm install
npm run build- Open
chrome://extensions/ - Enable Developer mode (top-right toggle)
- Click Load unpacked
- Select the
extension/dist/folder - Navigate to any Strava activity page — Di2va appears below the map
- The content script runs on
https://www.strava.com/activities/* - It extracts the activity ID from the URL and fetches stream data using Strava's internal API endpoints (authenticated via your session cookies)
- It attempts to download the original FIT file from Strava's export endpoint for actual Di2 gear shift data
- If no FIT file is available, gears are estimated from cadence + speed
- A collapsible panel is injected below the Strava map with the elevation chart, gear analysis, drivetrain animation, and shifting analysis
Di2va in action on a Strava activity page (dark mode) — detected groupset and chainring/cassette range in the blue box, gear-usage cards, shift-quality score, gear-coloured elevation profile, and the playback controls (1× → 100×). The Debug button in the header toggles the floating bottom-left panel that hosts the Override groupset dropdown and Re-analyse button.
Tested groupsets: Di2va has been successfully tested end-to-end with Shimano Di2 and SRAM AXS FIT files. Campagnolo EPS and FSA WE detection logic is in place but has not yet been verified against real-world rides — feedback and sample FIT files welcome.
When a FIT file is available, Di2va tries to identify the groupset (Shimano Di2, SRAM AXS, Campagnolo EPS, FSA WE) so the analysis uses sensible defaults. Detection is a weighted score combining two signals:
- Device metadata in the FIT file — manufacturer ID,
product_nameanddevice_namestrings ondevice_inforecords are matched against vendor keywords (shimano,di2,dura-ace,sram,axs,etap,campagnolo,eps,fsa we, …). Strong matches (e.g. Shimano manufacturer ID41) score highest. - Observed gear signature — the set of chainring and cassette teeth actually used during the ride. A 10T smallest cog is treated as a strong SRAM AXS indicator; the
11-12-13-14-15-17-19-21-24-27-30-34cassette pattern points to Shimano 12-speed; common pairings like48/35(SRAM) or50/34(Shimano compact) add weight to the corresponding vendor.
The highest-scoring vendor wins. If nothing scores, the panel shows Unknown groupset but the chainring/cassette range pulled from the ride still drives the analysis.
Auto-detection only sees what the ride contains. It can be incomplete or misleading when:
- The FIT file has no device metadata (older head units, third-party recorders).
- You didn't use every chainring or sprocket on the ride, so the inferred range is narrower than your actual cassette.
- Two vendors share a teeth signature (e.g. an 11-28 11-speed cassette is identical between Shimano and SRAM mechanical groupsets).
- A bike-computer firmware reports a generic
electronicdevice rather than a vendor-specific one.
If the detected groupset looks wrong, you can pick the right one yourself without touching the options page:
- On the Strava activity page, click the Debug button in the Di2va panel header. The floating debug panel appears in the bottom-left corner.
- In the Override groupset dropdown, choose one of the popular presets (Shimano 2×11/2×12, SRAM AXS 2×12, SRAM XPLR 1×12/1×13, Shimano GRX 1×11, etc.).
- Click Re-analyse.
The shift score, gear-usage stats, cross-chain detection, optimal-gear suggestions and any zoomed section scores are recomputed against the chosen drivetrain. Selecting Detected from ride data reverts to the auto-detected configuration.
For a permanent override (applies to every ride), set explicit chainring and cassette teeth on the extension's options page; user-configured drivetrains always take precedence over auto-detection.
All data processing happens locally in your browser. The extension communicates only with Strava's own servers (to fetch your activity data) using your existing session. No data is sent to any third-party service — including the Shifting Analysis, which is a local rules engine, not a cloud AI service.
extension/
├── manifest.json # MV3 WebExtension manifest (Firefox + Chrome)
├── webpack.config.js # Webpack 5 build config
├── src/
│ ├── content/
│ │ ├── main.js # Content script entry — panel injection, data pipeline
│ │ ├── elevation-chart.js # Chart.js elevation with gear colors, drag-to-zoom
│ │ ├── playback.js # Ride replay engine, drivetrain sync, AI analysis
│ │ ├── drivetrain.js # SVG drivetrain renderer (chainrings, cassette, chain)
│ │ ├── units.js # Strava unit detection (metric/imperial)
│ │ ├── safe-html.js # Safe DOM manipulation (DOMParser-based innerHTML replacement)
│ │ └── styles.css # Panel styles, dark mode support
│ ├── gear-estimator.js # Gear estimation from cadence + speed
│ ├── gear-parser.js # FIT file Di2 event parser
│ ├── gear-colors.js # Gear → color mapping
│ ├── shift-analyzer.js # Shifting quality analysis engine
│ ├── fit-worker.js # Web Worker for FIT parsing + decompression
│ └── background.js # Service worker (cookie forwarding)
├── popup/ # Extension popup UI
├── options/ # Extension options page (drivetrain config)
└── dist/ # Built output (load this in browser)
cd extension
npm install
npm run build # Production build → dist/
npm run build:dev # Development build with source maps
npm run watch # Auto-rebuild on changes
npm run package:firefox # Build + create Firefox .zip
⚠️ Deprecated. The standalone web app is no longer actively developed. All active development, bug fixes, and new features are happening in the browser extension only. The code is kept here for reference and for users who want a full-screen activity browser, but it may lag behind the extension in features and groupset support.
The standalone web app is the original Di2va interface. It requires Strava OAuth credentials but provides a full activity browser with map overlay and route coloring. All the extension features are available here too, plus additional capabilities.
Standalone web app — map colored by gear, elevation profile with gear/gradient overlay, hover panel showing live data, and gear usage summary with clickable statistics.
Detailed elevation analysis — zoom in to compare elevation against cadence (green) with gear shift markers (▲ upshift, ▼ downshift). Hover over any point to see gear, speed, cadence, power, and gradient.
AI Shifting Analysis — scores your shifting quality across your last 10 rides with a 1–5 star rating, component breakdown, per-ride table, and actionable text feedback. See the full AI Analysis documentation for how the scoring works.
- Strava OAuth — Securely connect your Strava account (credentials stored locally, never committed)
- Activity Browser — Browse your rides, filtered to cycling only
- Map Overlay — Route colored by gear selection (front/rear combo)
- Elevation Profile — Interactive Chart.js elevation chart with gear & gradient overlay, chart magnifier on hover
- Auto-Download FIT Files — Automatically fetches the original FIT file from Strava's export endpoint
- FIT Library Matching — Optionally point at a folder of FIT files to auto-match by timestamp
- Interactive Gear Popup — Click any gear to see an animated SVG drivetrain visualization with the full Dura-Ace 9200 cassette and chainrings
- Arrow Key Gear Cycling — Use left/right arrow keys to step through all gears used in the ride, or click the nav bar chips
- Optimal Gear Overlay — Toggle a dashed gold line on the elevation chart showing the recommended gear ratio at each point
- Units Switcher — Toggle between metric and imperial
- Node.js 18+ and npm
- A Strava API Application (free)
- Go to https://www.strava.com/settings/api
- Create a new application:
- Application Name: Di2va (or anything you like)
- Category: Visualizer
- Authorization Callback Domain:
localhost
- Note your Client ID and Client Secret
On first run the application will prompt to connect to your Strava account and store the API keys on your device — ensure the .env file is secure, it contains credentials to your Strava account.
cp .env.example .envEdit .env and fill in your Strava credentials:
STRAVA_CLIENT_ID=12345
STRAVA_CLIENT_SECRET=abc123...
SESSION_SECRET=any-random-string-herenpm install
npm startOpen http://localhost:3000 in your browser.
npm run devUses nodemon for auto-restart on file changes.
See the full setup guide with screenshots for step-by-step instructions on connecting to the Strava API, including details of where your data is processed and what is sent where.
The standalone web app processes everything locally on your machine at localhost:3000. The only network traffic is between your machine and Strava's API (to fetch your activity data) and CARTO's tile CDN (for map tiles). No data is sent to any other third-party service. See the setup guide for a full data flow diagram and the AI analysis docs for details.
- Strava API Streams — GPS coordinates, elevation, cadence, speed, power, gradient
- Gear Estimation — Uses cadence and speed to mathematically estimate which gear combination is in use (assumes standard road bike gearing)
- FIT File Upload — For actual Di2 data, upload the
.FITfile from your bike computer (e.g. Garmin, Wahoo). This contains the real gear change events recorded by the Di2 system
When no FIT file is available, the app estimates gears using:
gear_ratio = speed / (cadence × wheel_circumference)
It then matches this against known chainring/cassette combinations:
- Chainrings: 34/50 (compact) or 39/53 (standard)
- Cassette: 11-28 (11-speed)
The confidence of each estimate is classified as high/medium/low based on how close the match is.
Gears are colored from red (easiest) → blue/purple (hardest) based on the rear cassette position:
- 🔴 Large cog (easier gears) — warm colors
- 🔵 Small cog (harder gears) — cool colors
di2va/
├── LICENSE # MIT License
├── server.js # Express server, Strava OAuth, API proxy, FIT parser
├── .env # Environment variables (not in git)
├── .env.example # Template for .env
├── package.json
├── public/
│ ├── index.html # Single-page app shell
│ ├── styles.css # Dark theme UI
│ └── app.js # Frontend: map, chart, gear logic
└── extension/ # Browser extension (Firefox + Chrome)
├── manifest.json # MV3 WebExtension manifest
├── webpack.config.js # Build config
├── src/ # Source modules
└── dist/ # Built output (load in browser)
- Backend: Node.js, Express, express-session, axios, multer, fit-file-parser
- Frontend: Vanilla JS (no framework), Leaflet.js (maps), Chart.js (elevation), CARTO dark tiles
- APIs: Strava V3 API
If your bike uses different gearing (e.g. 1x, different cassette), edit the constants in:
server.js→POST /api/estimate-gears—CHAINRINGSandCASSETTEarrayspublic/app.js→getGearColor()—CASSETTEreference array
| Issue | Solution |
|---|---|
| "Not authenticated" error | Make sure your Strava API callback domain is set to localhost |
| No gear data shown | Upload a .FIT file, or ensure the activity has cadence data for estimation |
| FIT file parsing fails | Ensure the file is a valid .FIT file from a compatible device |
| Activities not loading | Check that the Strava API scope includes activity:read_all |
I'm a keen cyclist — nothing serious, very much an amateur — but I'm genuinely interested in the tech side of riding. I run a Shimano Di2 electronic groupset on my bike and became increasingly frustrated that Strava still does not include Di2 electronic shifter data in its ride analysis. The gear data is right there in the FIT file uploaded by my bike computer, but Strava just ignores it.
Understanding how I use my gears is really useful to me. Am I cross-chaining? Am I spending all my time in one gear when I could be shifting more? On a long climb, did I run out of gears or was I pacing my shifting well?
I was inspired by Di2Stats.com — a great service that does something similar. Check it out. Di2va takes a different approach: it runs entirely on your own machine and connects directly to your Strava account via the API.
Inspired by Sauce for Strava — an excellent browser extension that enhances Strava with advanced analytics. Di2va takes a similar approach but focuses specifically on Di2 electronic gear shift data.
MIT — free for personal and commercial use.
This code is AI-generated. Built using Visual Studio Code with GitHub Copilot powered by the Claude Opus 4.6 model by Anthropic.
Download VS Code: https://code.visualstudio.com/download
Author: vinfnet — This is a personal project and is not affiliated with, endorsed by, or connected to my employer in any way. I do not endorse any of the technologies, products, or services mentioned (Strava, Shimano, Di2, Garmin, etc.) — I simply find this a useful way to experiment with cycling data and AI-assisted development.




