Flow Forecast
A time-series forecasting API that predicts river flow rates using historical gauge data. Built as an experimental feature for GaugeWatcher, this service helps paddlers anticipate river conditions days in advance.
The Problem
River flow rates are notoriously difficult to predict. They depend on snowpack, precipitation, dam releases, and seasonal patterns that vary by watershed. Paddlers often check gauge readings the morning of a trip, but by then it may be too late to adjust plans if conditions aren’t ideal.
What if you could see a forecast for river levels the same way you check a weather forecast?
Technical Approach
Why Prophet?
Facebook Prophet is designed for time-series forecasting with strong seasonal patterns—exactly what river flow data exhibits. Key advantages:
- Handles seasonality well — river flows follow annual snowmelt cycles and weekly dam release patterns
- Robust to missing data — gauge stations occasionally go offline; Prophet handles gaps gracefully
- Fast enough for real-time — forecasts generate in seconds, suitable for API responses
Architecture
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ GaugeWatcher │────▶│ Flow Forecast │────▶│ Prophet │
│ iOS/macOS │ │ FastAPI │ │ Model │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ USGS API │
│ (Historical) │
└─────────────────┘
The API:
- Receives a gauge station ID and forecast horizon from the client
- Fetches historical data from USGS (typically 2+ years for seasonality)
- Fits a Prophet model to the historical data
- Returns forecasted values with confidence intervals
API Design
@app.get("/forecast/{gauge_id}")
async def get_forecast(
gauge_id: str,
days: int = 7,
include_history: bool = False
) -> ForecastResponse:
"""Generate flow forecast for a USGS gauge station."""
The API is documented with OpenAPI spec, enabling automatic client generation. The GaugeWatcher Swift client is generated from this spec using openapi-generator.
Current Status
| Feature | Status |
|---|
| USGS gauge forecasting | Complete |
| Dockerized deployment | Complete |
| OpenAPI documentation | Complete |
| Swift client generation | Complete |
| Colorado DWR support | Planned |
| Canadian gauge support | Planned |
Learnings
- Data quality matters more than model complexity — Prophet works well out of the box, but garbage in = garbage out. Cleaning historical data (removing sensor errors, handling unit changes) had more impact than tuning model parameters.
- Forecasting is humbling — rivers are chaotic systems. The model provides useful directional guidance but shouldn’t be treated as ground truth. Confidence intervals are essential.
- API-first design pays off — generating the Swift client from OpenAPI eliminated an entire class of integration bugs between the Python backend and iOS app.