EPA ECHO CWA Facilities Scraper — State Rosters
Pricing
Pay per event
EPA ECHO CWA Facilities Scraper — State Rosters
Search EPA ECHO's Clean Water Act facility registry by US state and export flat rows — name, address, registry/source IDs, county, EPA region, permit status. Keyless federal API. Built for ESG analysts, environmental compliance teams and site-diligence buyers.
Pricing
Pay per event
Rating
0.0
(0)
Developer
DevilScrapes
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
9 hours ago
Last modified
Categories
Share
Quick answer: This Actor pulls EPA ECHO's Clean Water Act facility registry for any US state and returns every regulated facility — name, address, registry ID, county, EPA region, and permit status — as flat JSON/CSV rows. No API key needed; you pay only for the facility rows that land in your dataset.
🎯 What this scrapes
EPA's ECHO (Enforcement and Compliance History Online) publishes every Clean Water Act–regulated facility, but pulling a full state roster means correctly handling ECHO's undocumented two-call protocol — a JSON search call that returns a query ID, then a single CSV download call that streams the entire result set at once with no server-side pagination. This Actor runs both calls, branches correctly on a match, a zero-match, or a rejected search, and flattens every facility — name, address, registry ID, county, EPA region, permit status — into one billable row.
🔥 What we handle for you
- 🧭 The two-call protocol, done right — one JSON search call, one CSV download call, exactly as ECHO expects. No guessed query params.
- 🧱 Zero matches is a clean success, not a failure — a narrow state/name combination finishes SUCCEEDED with a status message, never a false FAILED run.
- 🛡️ We rotate browser fingerprints (curl-cffi impersonation — Chrome/Firefox/Safari) on every request.
- 🔁 Retries with exponential backoff on
429 / 5xx, honouringRetry-After— up to 5 attempts per call. - 🧊 Clean, typed dataset rows — Pydantic-validated, one malformed CSV row skipped and logged, never an aborted run.
- 💰 Pay-Per-Event pricing — you only pay for results that hit your dataset.
💡 Use cases
- ESG and environmental due diligence — pull every CWA-regulated facility in a state before a site acquisition or portfolio review.
- Compliance monitoring — track permit status (e.g.
Effective,Administratively Continued) across a jurisdiction. - Market research — size the number of regulated dischargers by state or county.
- Lead generation for environmental consultancies and permit-renewal services.
⚙️ How to use it
- Click Try for free at the top of the page.
- Set a 2-letter
state(defaults toRI); optionally narrow withfacilityName. - Click Start. Output streams into the run's dataset.
- Export from Storage → Dataset as JSON, CSV, or Excel — or fetch via the API.
📥 Input
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
state | string | yes | RI | 2-letter US state code. ECHO rejects an unfiltered query, so a state is mandatory. |
facilityName | string | no | — | Optional substring match against the facility name, e.g. hospital. |
maxResults | integer | no | 500 | Caps rows pushed after CSV parsing. Each row is one billed result event. |
proxyConfiguration | object | no | {"useApifyProxy": false} | EPA ECHO is a public keyless federal API. Leave off unless your account requires egress through Apify Proxy. |
Example input
{"state": "RI","maxResults": 500,"proxyConfiguration": {"useApifyProxy": false}}
📤 Output
Every row is one dataset item.
| Field | Type | Notes |
|---|---|---|
facility_name | string | Facility name, e.g. ACME MANUFACTURING CO. |
source_id | string | State-issued source ID, e.g. RI0001234. |
street_address | string | Facility street address. |
city | string | Facility city. |
state | string | 2-letter state code. |
registry_id | string | EPA Facility Registry Service (FRS) registry ID. |
epa_system | string | EPA regulatory system, e.g. CWA. |
statute | string | Governing statute/program, e.g. NPDES. |
county | string | Facility county. |
epa_region | string | EPA region number, e.g. 01. |
permit_status_desc | string | Current permit status description, e.g. Effective. |
scraped_at | string | ISO 8601 UTC timestamp when the row was scraped. |
Example output
{"facility_name": "ACME MANUFACTURING CO","source_id": "RI0001234","street_address": "123 INDUSTRIAL DR","city": "PROVIDENCE","state": "RI","registry_id": "110000123456","epa_system": "CWA","statute": "NPDES","county": "PROVIDENCE","epa_region": "01","permit_status_desc": "Effective","scraped_at": "2026-08-25T12:00:00+00:00"}
💰 Pricing
Pay-Per-Event — you pay only when these events fire:
| Event | USD | What it is |
|---|---|---|
actor-start | $0.20 | One-off warm-up charge per run |
result | $0.003 | Per dataset item |
Example: 1 000 results at the rates above ≈ $3.20. No subscription, no minimum, no card to start — Apify gives every new account $5 of free credit.
🚧 Limitations
- Clean Water Act (CWA) facilities only — Air (CAA), RCRA, and Safe Drinking Water Act programs are separate ECHO products, out of scope for v1.
- No violation/inspection/penalty history — this Actor returns current facility and permit status, not enforcement records.
- No county-level query filter — ECHO silently no-ops unrecognized filter params, so county narrowing isn't offered;
countyremains in the output. - Large states (e.g. California, ~30,000+ rows) return a correspondingly large CSV in one response — use
maxResultsandfacilityNameto narrow.
❓ FAQ
Do I need an API key?
No. EPA ECHO's CWA REST service is public and keyless — no auth, no account required.
Why is state required?
ECHO rejects a completely unfiltered query. A 2-letter state code is the minimum viable filter and keeps result sets to a sane size.
What happens if my filters match nothing?
The run finishes successfully with zero rows and a status message describing what was searched — a narrow state/name combination legitimately returning no facilities is not an error.
Is this current or historical data?
ECHO serves current-state data only. There is no point-in-time snapshot or historical query in v1.
💬 Your feedback
Spotted a bug, hit a weird edge case, or need a new field? Open an issue on the Actor's Issues tab on Apify Console — we ship fixes weekly and we read every report.