# UK Storm Overflow & River Pollution Live Monitor (`hllerdgn80/uk-storm-overflow-monitor`) Actor

Near-real-time UK sewage storm-overflow tracker: aggregates every major English water company official live feed, cross-checks active discharges against Environment Agency rainfall data, and flags new discharge starts/stops vs the previous run.

- **URL**: https://apify.com/hllerdgn80/uk-storm-overflow-monitor.md
- **Developed by:** [Halil Erdogan](https://apify.com/hllerdgn80) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## UK Storm Overflow & River Pollution Live Monitor

Near-real-time tracker for sewage storm-overflow discharges across nine
major English water companies, built entirely on official, public,
keyless data - no scraping, no browser, no login.

### What it does

Every English water company now publishes its own live "Event Duration
Monitoring" (EDM) feed showing, outfall by outfall, whether a storm
overflow is currently discharging into a river, lake or the sea. These are
the same official feeds that back the water industry's own near-real-time
"National Storm Overflow Hub" (streamwaterdata.co.uk, backed by Water UK,
the Environment Agency, Defra and Ofwat).

This Actor:

1. **Aggregates nine companies into one feed** - Anglian Water, Northumbrian
   Water, South West Water, Severn Trent Water, Yorkshire Water, Wessex
   Water, Thames Water, United Utilities and Southern Water - by resolving
   each company's live ArcGIS Feature Service from its stable item id and
   querying only the outfalls whose status changed inside your lookback
   window.
2. **Tracks changes, not just a snapshot** - every run compares the current
   status of each outfall against what the Actor saw last time (stored in
   its own key-value store) and labels each row `new_discharge_start`,
   `ongoing_discharging`, `discharge_stopped`, or first-seen. Nothing else
   public turns the raw company feeds into a change/watchlist feed like
   this.
3. **Cross-checks against rainfall** - for every currently-discharging
   outfall, it looks up the nearest Environment Agency rain gauge and its
   rainfall total over the last 24 hours (Environment Agency real-time
   Rainfall API, also free and keyless) and sets `dry_spell_flag: true`
   when a discharge is happening with under 1mm of rain nearby in the last
   day - the first question anyone checking a discharge asks: was this the
   weather, or not?
4. **Lets you narrow the watchlist** - by water company, by watercourse
   name (e.g. "Thames", "Trent"), or by a radius around a point (a bathing
   spot, a fishing stretch, a stretch you swim or paddle).

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `lookbackHours` | integer | 48 | How far back to look for status changes (6-168h). |
| `company` | string | - | Exact water company name to filter to. |
| `watercourseContains` | string | - | Case-insensitive substring match on the receiving watercourse. |
| `nearLatitude` / `nearLongitude` | number | - | Centre point for a radius filter. |
| `nearRadiusKm` | integer | 25 | Radius used only when both `nearLatitude`/`nearLongitude` are set. |
| `includeRainfallContext` | boolean | true | Attach nearest-gauge 24h rainfall to active discharges. |
| `onlyChangedEvents` | boolean | false | Drop rows with no change since the last run. |

### Output (one row per outfall event)

```json
{
  "site_id": "AWS00608",
  "company": "Anglian Water",
  "status": "stopped",
  "status_code": 0,
  "event_type": "discharge_stopped",
  "watercourse": "Kirby Brook",
  "latitude": 51.838603,
  "longitude": 1.217465,
  "distance_km": null,
  "status_start_ms": 1790516771000,
  "latest_event_start_ms": 1790516476000,
  "latest_event_end_ms": 1790516755000,
  "last_updated_ms": 1790520400309,
  "rainfall_context": null
}
```

`rainfall_context` (only populated for currently-discharging outfalls):

```json
{
  "available": true,
  "station_name": "Rainfall station",
  "station_ref": "E24874",
  "distance_note": "nearest Environment Agency tipping-bucket rain gauge within 15km",
  "rainfall_last_24h_mm": 0.0,
  "dry_spell_flag": true
}
```

### Data sources (all official, public, keyless)

- Each water company's own public ArcGIS Feature Service EDM feed (the
  same layers behind streamwaterdata.co.uk's National Storm Overflow Hub).
- Environment Agency real-time flood-monitoring Rainfall API
  (`environment.data.gov.uk/flood-monitoring`), Open Government Licence,
  no registration.

Nothing is scraped from a rendered web page and no terms of service are
bypassed: every request is a documented JSON `query`/`readings` call
against a service the publisher itself intends for machine consumption.

### Notes

- A company's feed being briefly unreachable does not fail the run; it is
  recorded per-company in the run's key-value store (`RUN_STATS`) and the
  other companies still report normally.
- The Actor resolves each company's current ArcGIS service URL from its
  stable item id on every run, so a company changing its underlying
  service URL (which has happened before) does not silently break this
  Actor.

# Actor input Schema

## `lookbackHours` (type: `integer`):

How far back to look for outfalls whose discharge status has changed, across every covered water company's live feed. Wider windows catch discharges that started and stopped between runs.

## `company` (type: `string`):

Only return outfalls run by this water company, e.g. "Thames Water" or "Severn Trent Water". Leave blank to check all nine covered companies.

## `watercourseContains` (type: `string`):

Only return outfalls whose receiving watercourse name contains this text, e.g. "Thames" or "Trent". Case-insensitive, matched against the company's own watercourse name.

## `nearLatitude` (type: `number`):

Optional: combined with 'Near longitude' and 'Search radius', only return outfalls within that radius of this point (e.g. a specific bathing spot or fishing stretch).

## `nearLongitude` (type: `number`):

Optional: paired with 'Near latitude'.

## `nearRadiusKm` (type: `integer`):

Radius in kilometres used only when 'Near latitude'/'Near longitude' are both set.

## `includeRainfallContext` (type: `boolean`):

For every currently-discharging outfall, look up the nearest Environment Agency rain gauge and its rainfall total over the last 24 hours, and flag a 'dry\_spell\_flag' when a discharge is happening with very little recent rain nearby.

## `onlyChangedEvents` (type: `boolean`):

If enabled, skip outfalls whose status has not changed since the Actor's last run (and any outfall seen for the very first time with no prior state to compare). Use this for a lean day-to-day watchlist; leave off for a full picture on the first run.

## Actor input object example

```json
{
  "lookbackHours": 48,
  "nearRadiusKm": 25,
  "includeRainfallContext": true,
  "onlyChangedEvents": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("hllerdgn80/uk-storm-overflow-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("hllerdgn80/uk-storm-overflow-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call hllerdgn80/uk-storm-overflow-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hllerdgn80/uk-storm-overflow-monitor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/bN4ZDGDpK4UOEq2Oh/builds/YoOUVqpiYpdBWCfWB/openapi.json
