2025
WeatherToRun
A weather app that turns hourly conditions into run scores, clothing guidance, and clear decisions.
Case study
2025
A weather app that turns hourly conditions into run scores, clothing guidance, and clear decisions.
Runners often ask two questions: when should I run, and what should I wear?
Most weather apps show temperature, humidity, and wind speed. They do not turn these values into a clear decision.
I compared the values in my head before each run. Sometimes, I wore too much, felt cold, or did not expect the rain.
WeatherToRun does this comparison for me. It gives each hour a score from 0 to 100 and labels the result as Bad, OK, or Good.
The score combines five main factors:
The formula uses research as an input, but the weights and thresholds are product decisions. Weather condition codes add penalties for hazards such as thunderstorms, freezing rain, and snow.
Strong wind can also set a maximum score. Air quality remains separate, so a late air quality response does not change a visible score.
The app can adjust the score for climate acclimation. Separate preferences adjust the clothing list for runners who want more or fewer layers.
I first used pen and paper to define the interface. The score and clothing guidance had to appear before the detailed forecast.
These sketches helped me set that order before I worked on implementation details.



Initial sketches of the main view, component structure, and user flow.
The web app uses a Node.js API route. It uses Apple WeatherKit by default, with Open-Meteo available as a configured alternative.
The route rounds coordinates to two decimal places. This groups nearby requests under one cache entry.
The response permits five minutes of browser caching. It also permits one hour of CDN caching and one hour of background revalidation.
TanStack Query treats client data as fresh for one hour. This reduces repeat requests when a runner returns to the same forecast.
Location pages use static page shells and request current scores from the client API. The current app does not use a scheduled cache invalidation endpoint.
WeatherToRun is an installable Progressive Web App (PWA). Its manifest uses standalone display when the platform supports it.
The service worker applies three cache rules:
If navigation fails, the service worker shows a saved offline page. It does not provide a full offline forecast.
This boundary prevents old forecast data from appearing as current data. It also makes the offline state clear.
The server retries eligible weather provider failures. The client makes one retry for an eligible route failure.
Air quality uses a separate request with a three-second time limit. If that request fails, the forecast and run score remain available.
Sentry records the operation, caller, error code, status, and rounded coordinates for a weather request failure. This context helps me diagnose production problems.
The app does not hide all failures. It returns a specific status for a timeout, network problem, or invalid provider response.
Synthesis is more useful than more data. The score turns several weather values into one decision that a runner can use.
Research does not remove product judgment. Sources can guide the formula, but thresholds and weights still need tests and clear limits.
Each data type needs the correct cache rule. Static assets can remain saved. Forecast navigation must favor current data.
Offline support must have an exact meaning. A clear fallback page is useful, but it is not the same as an offline forecast.
Small preferences can provide useful personalization. Climate and clothing controls change the result without a large settings system.