Strava Calendar

Turns a year of Strava workouts into one shareable heatmap image.

2023– · Solo: design, frontend, backend, deployment · Angular, Python (FastAPI), MongoDB Atlas, Strava API v3, Vercel

The Strava Calendar app: settings for sport and units on the left, and on the right a generated heatmap of three years of runs, one row per year, with darker pink squares for longer days and Copy and Download buttons above it.

Why

As a road runner who logs everything on Strava, I wanted a picture of a whole year of training that I could post. Strava's calendar view is for paying members only, and its look is fixed. Strava Calendar gives any athlete, free or paid, a GitHub-style heatmap of their workouts, in seven color schemes.

How it works

Strava Calendar architecture The Angular app on Vercel calls the Python FastAPI service on Vercel. The API exchanges and refreshes OAuth tokens with Strava API v3, stores only tokens in MongoDB Atlas, fetches activities, and returns the heatmap as a PNG. Angular app Vercel FastAPI service draws the PNG Strava API v3 OAuth, activities MongoDB Atlas tokens only Strava Calendar architecture The Angular app calls the FastAPI service, which talks to Strava API v3 and MongoDB Atlas and returns the heatmap. Angular appVercel FastAPI servicedraws the PNG Strava APIOAuth, activities MongoDBtokens only
The browser only talks to my API; the API holds the Strava tokens and draws the image.

Decisions

Keep Strava behind the API

The Angular app never calls Strava. After "Connect with Strava", the API exchanges the OAuth code for tokens, stores them, and hands the browser only an opaque user id. Tokens never reach the client, and changes to Strava's API stay in one place.

Store tokens, not people

The database keeps a short-lived access token, a refresh token and the expiry time. Nothing else: no names, no activities. Before each request the API checks the expiry and refreshes the token if it needs to. Activities are fetched, summarized and drawn on demand, then dropped.

Draw on the server

The heatmap is rendered in Python and returned as a PNG, or as base64 to preview every theme at once. That keeps the frontend small and makes the image identical everywhere it's shared.

Filters that match how athletes think

The API filters by sport type (run, ride, swim, hike and more) and by units (metric or imperial). So a runner can share just their runs, in the units they race in.

Screens

A heatmap of three years of runs in shades of green, one row of squares per year from 2022 to 2024, with each year's activity count, miles and elevation above it.
The same years in the "Forest" color scheme.
The app before connecting: the Strava Calendar Generator logo and an orange Connect with Strava button above the sport and unit settings.
Before connecting: one button starts Strava's OAuth flow.

What I'd do next