HowsTheWater?: storm overflows, flood warnings and river levels for UK waterways
Posted under: Dev
tl;dr I built HowTheWater?, a free site that shows which storm overflows upstream of a swimming spot have spilled recently, whether any are spilling now, and what the river is doing – current river levels, flood warnings and more. It covers rivers, beaches and lakes across England, Scotland and Wales, all from open data, and it’s live now with the source all available on GitHub.
The full stack and data sources are on the project page.
Why build HowsTheWater?
Living in Yorkshire, we’re spoiled for rivers. Perhaps we are in the UK in general. But over the last few years it’s become more and more public knowledge that the water isn’t always clean. In fact, there are times – probably more often then you think – that unless you fancy a sewage dip, it’s probably somewhat inadvisable to get too close to the water. I don’t want to get too deep into it, there are plenty of sites that can explain it better than me, but that doesn’t mean it doesn’t bother me. And I think that with things like this, the more you can spread the word about what’s happening, the more likely it is that things might change.
From a local perspective though, the annoyance is that the answers to the question “is there sewage near me” are published. The water companies now put out near real-time data from the monitors on their storm overflows, and the Environment Agency publishes river levels every 15 minutes. But the overflow maps show you thousands of dots, and none of them tells you which dots actually matter for the bit of river you’re next to. So, I decided to help try to organise the data spaghetti and help people stay informed.
So what is it?
Pick a spot, and its page tells you whether any overflow upstream is discharging right now, when the last one stopped, and how often they’ve spilled over the last 30 days. Beside that sit the nearest river gauge, the rain over the last day or two, any flood warnings and, where the spot is a designated bathing water, its classification and latest samples. Beaches and lakes get the same, with the overflows within 3 km instead, since the sea doesn’t really have an upstream.

It started with Yorkshire’s rivers and now covers twelve regions, reading the live feeds of eleven water companies: around 18,600 overflows, 620 river spots and over 600 beaches and lakes. The site is built with Laravel and plain server-rendered pages, which makes it cheap to cache at Cloudflare‘s edge, and every page has an RSS feed if you’d rather be told when something starts spilling.
Rivers don’t flow as the crow flies
The obvious way to build this is to draw a circle. Drop a pin at Otley, find every overflow within 5 km, and report what they’re doing.
Except an overflow 400 metres away that sits below you is sending everything away from you. You could swim there all afternoon and never meet a drop of it. Meanwhile an overflow 12 kilometres away, up a little beck that joins the river above you, is sending everything straight down to where you’re standing. A circle gets both of those wrong.
So the site has to follow the water. Every river gets a line from source to mouth, and every spot, overflow and gauge is placed on it as a distance along the river. “Upstream” then just means a smaller number on the same river, plus everything on the tributaries that join above you, worked out recursively up the tree. Distances on the page are distances along the water, not across fields.
Untangling the Ordnance Survey
Those lines come from OS Open Rivers, a free GeoPackage with every named watercourse in Great Britain. I tried OpenStreetMap first, but asking Overpass for a hundred-mile river is a good way to find out how many ways a server can say no.
OS Open Rivers is awesome data. It’s also not a set of rivers. It’s a set of short links, each with a name, and the names repeat everywhere. There are several River Calders and Derwents, Yorkshire has dozens of becks that share a name, and Cumbria has two River Gretas, just to be awkward. So each river is seeded with a rough idea of where it ends, and the reader starts from the links nearest that.
Then the links don’t join up. A river runs into a reservoir and the line stops, then picks up again on the other side. The Tweed comes in dozens of pieces. Pieces within 4 km are joined on, always the nearest first, because otherwise it happily grabs a piece further up and stops short of the bit in between.
And the links all have a flow direction, which is great until you hit a braided reach round an island or a mill cut, where someone has drawn one link the wrong way round. Follow the arrows and you hit a dead end in the middle of a field. The fix was to stop trusting the arrows altogether: find where the flow ends nearest the river’s mouth, find the point furthest from it along the links, and take the shortest path between the two.
That worked nicely. Until it didn’t!
When I added Wessex, the Dorset Frome’s line doubled back on itself for about 5 km. Near Woodsford the river runs alongside a parallel channel that OS gives the same name, and the line had gone down one, come back up the other and carried on down again. The Itchen does the same with its Navigation. The reader now cuts the line back to where the joined piece leaves it, so a line never doubles back on itself, and a migration cleared the lines older versions had got wrong (including the Kennet and the Wey, which had been stopping short of their upper reaches) so the next deploy fetched them again.
All of them except the Thames. Its tidal stretch is split into pieces too far apart to join, and today’s reader would build it backwards from Erith, so there’s a note in the code that its stored line must never be cleared. Every project has one of those.
Feeds with no memory
The live overflow feeds only give each monitor’s latest event. If an overflow spilled for six hours overnight, by breakfast it just says it isn’t discharging. So the site polls every feed every 15 minutes and builds up the history itself, and before that it reads the spill logs the companies publish after the fact, back to 2024. Scottish Water and Welsh Water don’t publish theirs, so their history starts when the site first saw each overflow, and the pages say so rather than drawing quiet days.
No data is not good news
If you read my glucose monitor post, you’ll know I have feelings about stale data. A monitor on a riverbank loses signal, or a feed goes down, and a naive app sees no spills and puts up a cheerful green badge. So the site has one hard rule: missing data never looks like clean water. Offline monitors are counted as offline, anything over six hours old is flagged and greyed out, and if every monitor upstream is offline, the spot says so.
Where Claude came in
I’ve never been shy to admit that I’m fine with leaning on Claude Code when it feels like it can do things better than I can. The simple fact is, and something I’m finding more and more as I work on heavy data driven sites – is while I could spend months analysing data and trying to fix it all by hand, in the real world I’m one guy with a job and a family working on passion projects in my spare time, and this is something that could have taken me weeks – months – to sift through, even if I was working full time on it.
So for this project I decided what the site should do and how it should say it, and sent Claude off to research how I could obtain what I wanted while I spent my time trying to puzzle out what we could do with this data. It did the geometry, the readers for each source and wrote the tests. Eleven water companies that each publish their data slightly differently is a lot of readers.
And the end result? A mostly standardised dataset, and importers that ensure that future incoming data stays standardised.
So what’s next?
One of the things I’m proud of with this project is that I’ve made a site that does nearly everything I wanted (and more) with open data. No need for questionable web page scraping with misleading user agents or copy/pasting data from websites that would usually ask you to pay a license to use. So I would love to make that data accessible to others in it’s standardised form.
There’s already the basis of an API underneath the site that serves the same data, but it’s switched off until I’ve been through the licence for every source and made sure the Government Licenses most carry allow for me to re-share. Northern Ireland is also an obvious data gap currently, and is waiting on NI Water. Tide times for the beaches are waiting a response re: licencing.
A quick word of caution
The site reports what the monitors say, and monitors break, lag and miss things. No spill reported upstream doesn’t mean the water is clean, and a river can carry plenty of other things after heavy rain. Use it as one more thing to check, alongside your own eyes.
Sound useful? Have a look
Find your local spot on howsthewater.uk. The code is on GitHub, and the stack and every data source are on the project page.
If there’s a spot you swim at that isn’t on there, or something looks wrong for a river you know, I’d love to hear about it! Get in touch here.