Strava is pretty jazzy, and has essentially cornered the market on the more serious side of fitness tracking. For those of us with a penchant for data hoarding and shiny UIs however it leaves some itches un-scratched:
- I’ve been using this internet thing for a while, and I’d rather avoid the desperate 11th hour scramble to get my data back out when you inevitably shut down
- It’s really hard to find routes again once you’ve traveled them. You can view everywhere you’ve been in heatmap form, but there’s no way to go from here back to individual activities
- It’s not possible to get an overview of all activities grouped by some property of them - e.g., sport, year, etc.
Back in 2016 I built a simple app that uses the strava API and mapbox to extract and visualize the data and have been using it ever since - check it out on github!
Fetching the data
Back when I wrote this, I was very much #TeamRuby
, and as a result the
project uses a dockerized chunk of ruby
to pull all the activities for a particular strava account. The code is not
particularly elegant but has been battle-hardened over the years of continuous
use pulling my activities out, and I see no need to rewrite it. The least pleasant bit is probably the
coarse-grained backoff to deal with Strava’s API limits, but the ruby syntax for
retrying on exceptions makes it concise at least:
To paraphrase a Western Australian entrepreneur - it’s not fancy, but it’s cheap. Data is cut up into three different formats:
- Raw strava activity data, with all the different “streams” included - heartrate, power, and so on
- GeoJSON
- A mbtiles vector tileset containing everything
In this fashion we’ve got the entire set of our strava data backed up locally, plus a nice vector-tiled representation to drop into our maps.
Mapping the data
The frontend is a simple static webapp and the code is available here.
I’m a big fan of Mapbox GL JS and the great job they’ve done popularising client-side vector rendering of web maps and used it in this project. If I was to start again today i’d probably use maplibre, if only because it’s easier to reckon about the billing, but MapboxGL maintains a big enough free-tier to easily personally host this.
To wrap the thing up, I use a create-react-app’d react app, material UI, and Typescript. This is wonderfully unexciting, and has been my “let’s quickly build a webapp!” stack for some years now.
Hosting the thing
The fetcher and the frontend are published to Docker as part of the Github build process, and can be deployed easily wherever docker runs. I’ve written a simple Kubernetes manifest to make things easy if you have a Kubernetes cluster around, but it’s not necessary; there are also scripts to run the fetcher and the frontend with Docker itself. The containers share a volume so that the tiles generated by the fetcher can be accessed by the frontend.
Wrapping Up
Check out the repository readme and try it out!