Phase I ESA Environmental Database Search — EPA by Address
Pricing
from $5.50 / 1,000 results
Phase I ESA Environmental Database Search — EPA by Address
Environmental database report for any US address: EPA Superfund/NPL, RCRA CORRACTS/TSD/generators, TRI, UST, LUST, Brownfields, NPDES, AIR, TSCA, RMP — scored against ASTM E1527-21 search distances, plus on-site Superfund and institutional-control (AUL) boundary checks. No API key.
Pricing
from $5.50 / 1,000 results
Rating
0.0
(0)
Developer
Kyle Maloney
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Phase I ESA Environmental Database Search — EPA Records by Address
Run an environmental database report on any US address or coordinate: ten EPA regulatory databases screened by distance, scored against the ASTM E1527-21 standard search distances, returned as structured rows. This is the multi-database regulatory records review at the core of a Phase I Environmental Site Assessment. Built for Phase I ESA consultants, CRE buyers and lenders, environmental attorneys and underwriters who need to triage a property or a whole portfolio before ordering the full report. No API key.
Environmental database report by address
Give it an address (or lat/lon) and a radius; get one row per nearby regulated site, each tagged with its program, its distance, its EPA status, and a direct link to the EPA source record.
program | EPA database | Source |
|---|---|---|
SUPERFUND | NPL / Superfund (SEMS) + FRS SEMS points | EPA Envirofacts ENVIROFACTS_SITE + EPA FRS FRS_INTERESTS_SEMS / _SEMS_NPL |
RCRA | Hazardous-waste handlers, classified into CORRACTS / TSD / generator | EPA ECHO echo_rest_services + rcra_rest_services |
TRI | Toxics Release Inventory reporters | EPA ECHO |
UST | Underground storage tank facilities | EPA UST Finder (2018-2021 vintage) |
LUST | Leaking underground storage tank releases | EPA UST Finder |
BROWNFIELD | Brownfields / ACRES | EPA FRS ACRES |
NPDES (opt-in) | Clean Water Act discharge permits (ICIS-NPDES) | EPA ECHO |
AIR (opt-in) | Clean Air Act permitted stationary sources | EPA ECHO |
TSCA (opt-in) | TSCA-regulated facilities incl. PCB handlers | EPA ECHO |
RMP (opt-in) | Risk Management Plan chemical-accident facilities | EPA ECHO |
Addresses are geocoded with the free US Census geocoder. Leave programs empty to screen the original six; name the opt-in four to include them (they come from the same EPA ECHO response, so they cost no extra upstream call).
ASTM E1527-21 standard environmental record sources and search distances
Set astmMode: true and each asset gets one extra astm_summary row scoring the databases against the ASTM E1527-21 Sec. 8.2.1 search-distance table — delivered as flat, CSV-safe columns (astm_npl_flag, astm_rcra_corracts_nearest_mi, ...) plus a nested object.
| ASTM line item | Required radius | Column prefix |
|---|---|---|
| NPL (Superfund, Final) | 1.0 mi | astm_npl_* |
| Delisted NPL / SEMS-CERCLIS (non-NPL) | 0.5 mi | astm_cerclis_* |
| RCRA CORRACTS (corrective action) | 1.0 mi | astm_rcra_corracts_* |
| RCRA TSD (treatment/storage/disposal) | 0.5 mi | astm_rcra_tsd_* |
| RCRA generators (LQG/SQG/VSQG) | 0.25 mi | astm_rcra_generators_* |
| LUST | 0.5 mi | astm_lust_* |
| UST (registered) | 0.25 mi | astm_ust_* |
| Brownfields | 0.5 mi | astm_brownfield_* |
TRI is not an ASTM standard record source and never gets an entry. radiusMiles accepts fractional miles (0.1–50) so you can screen at 0.25 or 0.5 mi directly.
RCRA CORRACTS, TSD and LQG/SQG generator search
Earlier versions applied the widest 1.0-mile CORRACTS radius to every RCRA facility, because echo_rest_services does not expose the distinction. rcra_rest_services does — via RCRAUniverse, Tsdf and CleanupActionFlag — so each RCRA hit now carries rcra_astm_class (CORRACTS / TSD / GENERATOR / OTHER), rcra_corracts, rcra_universe and rcra_tsd_types, and is scored at its correct ASTM radius.
rcra_astm_class is a single, mutually exclusive class resolved in precedence order CORRACTS → TSD → GENERATOR → OTHER, so a facility that is both a corrective-action site and a TSD is reported once, as CORRACTS. Its raw rcra_tsd_types still shows the TSD designation — BRODERICK WOOD PRODUCTS CO carries Land Disposal (L) while classing as CORRACTS. This is why astm_rcra_tsd_count can be lower than the raw count of TSD-designated facilities in range: each facility is scored at one ASTM line item, not several.
Measured live at 39.8037, -104.9986 (Denver) within 1 mile: EPA lists 96–97 RCRA facilities, of which exactly 2 carry a corrective action (CORRACTS) — BRODERICK WOOD PRODUCTS CO and KOPPERS INC (DENVER CO) — and 3 carry a TSD designation. Scoring all of them at the 1.0 mi CORRACTS radius, as earlier versions did, over-flags by roughly 48x. (EPA's RCRRows count at this point drifts by a facility or two between refreshes; it read 96 on 2026-07-26.)
Recognized Environmental Condition (REC) screening — is the property ON a site?
With includeBoundaries: true (default) each asset also gets a true point-in-polygon test, not a distance-to-centroid guess:
on_superfund_site,superfund_site_name,superfund_epa_id,superfund_epa_url,superfund_site_description— is the property inside a published EPA NPL Superfund site boundary? (2,114 polygons nationally.)institutional_control_flag,institutional_control_site_name,institutional_control_description,institutional_control_area_acres— is it inside a published EPA Superfund institutional control boundary?
A boundary match also sets superfund_npl_status (a readable label such as Final NPL). Verified live 2026-07-26: 39.686641, -105.003564 returns DENVER RADIUM SITE; 39.793679, -104.982364 returns ASARCO, INC. (GLOBE PLANT) plus the institutional control OU4 - Environmental Covenant.
Institutional controls and activity and use limitations (AULs)
The IC layer answers the ASTM E1527-21 AUL record-source question where EPA has published a boundary. Coverage is thin and stated plainly: EPA publishes ~165 IC boundary polygons nationally. A false result means "not inside a published federal Superfund IC", not "no AUL exists on this property". A null means the layer was not consulted or failed — never read null as a clean result.
Business Environmental Risk — enforcement, penalties and compliance history
Every ECHO-derived hit now carries the facility's regulatory track record, which is what ASTM E1527-21 Business Environmental Risk is about: compliance_status, significant_noncompliance, inspection_count, last_inspection_date, formal_action_count, total_penalties_usd, last_penalty_date, plus sic_codes / naics_codes (an industry pre-screen: 7216 dry cleaner, 5541 gasoline station, 2491 wood preserving) and cross-program IDs (npdes_ids, air_ids, rcra_ids, sems_ids, tri_ids, tsca_ids, rmp_ids).
Every hit also carries dfr_url — a direct link to the facility's EPA Detailed Facility Report, the citable source for a report appendix.
Radius report alternative — a structured, on-demand records search
A commercial radius report is a PDF you wait for. This is the same federal database layer as JSON/CSV/Excel, on demand, per address, at Pay-Per-Result pricing, callable from an API or an AI agent. It does not include the state/tribal databases, historical fire-insurance maps, city-directory research or the Environmental Professional's opinion that a commercial report and a real Phase I include — see the caveats below.
Environmental due diligence API for commercial real estate
Screen a whole portfolio in one call: pass as many items as you like in assets; each nearby site is one row. Every row carries the per-asset rollup, so you can sort a hundred properties by phase1_esa_flag and astm_refined_verdict before anyone opens a file.
Two modes
assets mode (default) — screen your properties. Each asset item is either { "address": "...", "label": "..." } or { "lat": <n>, "lon": <n>, "label": "..." }. state is now optional with lat/lon — Superfund is screened spatially against the EPA FRS SEMS point layers, which need no state; supplying state additionally pulls that state's full Envirofacts SEMS roster for wider non-NPL coverage.
{"mode": "assets","assets": [{ "lat": 39.8037, "lon": -104.9986, "state": "CO", "label": "Denver warehouse" },{ "address": "5980 Lipan St, Denver, CO 80221", "label": "Denver warehouse (by address)" }],"radiusMiles": 1,"programs": ["SUPERFUND", "RCRA", "TRI", "UST", "LUST", "BROWNFIELD", "NPDES", "AIR", "TSCA", "RMP"],"maxHitsPerProgram": 50,"astmMode": true,"includeBoundaries": true}
inventory mode — list the raw EPA SEMS/Superfund roster for the states you name.
{ "mode": "inventory", "states": ["CO", "NJ"], "onlyNpl": true }
Key output fields (assets mode)
result_type—listing(a hit),clear(screened, nothing within radius), orerror.program,list— the EPA program and its readable database name.site_name,site_address,site_city,site_state,site_zip,site_county;site_id,registry_id.distance_miles— great-circle distance from the asset to the site.coordinate_source/positional_accuracy_m/coordinate_method— how the site was located (state-supplied survey point vs. address geocode). This qualifies every distance in the row.status,status_detail,on_npl,phase1_flag.- UST/LUST:
ust_open_tanks,ust_closed_tanks,ust_temporarily_out_of_service,lust_substance,lust_reported_date,lust_case_open. - UST tank counts, unrounded:
ust_open_tanks_reported,ust_closed_tanks_reported,ust_tos_tanks_reportedandust_tank_counts_unreported. EPA publishes no tank count for a slice of UST Finder — measured 2026-08-01,Closed_USTsis null on 15,221 of 742,855 facilities andTOS_USTson 15,235. The three original fields report0there and always have, so they are unchanged; these four say plainly whether that0is a measurement or an absence. On this actor's own five published example runs, 23 of 243 UST rows (9.5%) carried a count EPA never published. - Receptors:
population_within_1500ft,private_wells_within_1500ft,in_source_water_protection_area,in_wellhead_protection_area,in_100yr_floodplain,land_use. asset_*,radius_miles,checked_at,error,disclaimer,source_url.
Did the databases actually answer? (data_complete)
Every row carries a data-completeness ledger, because a screening result that quietly means "we could not reach EPA" is worse than no result at all:
programs_requested,programs_screened,programs_failed,programs_failed_detaildata_complete— true only when every requested database answeredtruncated_programs— programs whose upstream result hit a hard record cap, or whose retrieved record count did not match the upstream's own exact countsems_roster_complete,sems_roster_expected,sems_roster_retrieved— the Superfund/SEMS state roster is now reconciled against EPA Envirofacts' own.../COUNT/JSONendpoint, queried with exactly the filter used to fetch it. If paging stopped early the row says so instead of ranking NPL proximity over a partial roster.
A clear result is only ever emitted when at least one requested database actually answered. If all of them failed for an asset, the row is result_type: "error" and says so — it never claims the property is clean. If every database fails for every asset, the run fails and nothing is billed. As of v1.3.4 that sentence is literally true: rows are held back until at least one asset has been screened by at least one live database, so on a total outage the run fails having pushed nothing at all. Before v1.3.4 one row per asset had already been written when the failure fired.
Live upstream drift assertions
Every EPA read is checked at runtime against what that service returned when this actor was baselined, because the expensive failure is not an outage — it is a source that quietly changes shape, keeps answering 200, and lets the screen return a confident wrong answer. Thirty assertions run on a full screen:
- Column contracts. Every column the actor reads is checked on the payload that arrived. A column it needs to identify or locate a site going missing (
FacLat,Latitude,primary_latitude_decimal_val,RCRAFlag, …) is treated as fatal: the run stops before anything is pushed, because listings would otherwise be silently missed. A column it only reads for enrichment going missing is a warning and the matching field goes null. - Record-count canaries. Each layer's national record count must sit inside a band measured live on the baseline date — UST Finder 742,855 facilities, LUST 531,310, FRS ACRES 44,235, FRS SEMS 14,970 (+1,837 NPL), Superfund boundaries 2,114, institutional-control boundaries 165, Envirofacts SEMS 55,588 sites. Bands are roughly a third of the measured value, so ordinary growth or a data-cycle refresh cannot trip them; only a layer being replaced by a subset can.
- Retrieval completeness. Every paged ArcGIS read is reconciled against
returnCountOnly, and every SEMS state roster against efserviceCOUNT/JSON. Both counts are issued with exactly the filter used to fetch, never through a chained join. - Parser completeness. EPA ECHO states its row count before sending the CSV, so a row dropped in parsing is caught for free.
- Coordinate coverage. A latitude column that is present but entirely empty is invisible to a column check and would make every asset read
clear; a roster of 500+ records with zero geocoded records fails the assertion.
The outcome is on every row: drift_status (ok / warning), drift_checks_run, drift_checks_failed, drift_warnings, programs_degraded, drift_baseline_date. A degraded source reports null for its derived answers, never false — including the Superfund and institutional-control boundary flags, which are skipped entirely rather than answered from a layer that failed its canary.
NPL/Superfund proximity rollup (per asset)
nearest_npl_site_name, nearest_npl_distance_miles, nearest_npl_status, npl_sites_within_radius, phase1_esa_flag, phase1_summary. Computed against the union of the state SEMS roster and the fully-geocoded FRS SEMS points, and not bounded by radiusMiles — a Phase I report conventionally states the nearest NPL site even when it falls outside the search radius. The NPL life-cycle now includes EPA's pre-proposal status, used for sites already under remedial enforcement; it surfaces as a readable label in nearest_npl_status (and, on a Superfund boundary match, superfund_npl_status) rather than as a raw status code.
Was that "clear" actually verified? (v1.3.4)
Three companion fields state, per row, whether a negative was checked or merely
not checked. null means NOT CHECKED; false means checked and negative.
phase1_screen_performed- true when the asset was actually screened (coordinates resolved AND at least one requested database answered). False on an unresolvable address and on an asset where every requested database failed.phase1_esa_flag_verified- true whenever a database actually returned a listing (a positive is self-verifying).falseonly when every requested program answered and none matched.nullwhen the negative was never verified.npl_sites_within_radius_verified- the same count asnpl_sites_within_radius, but only when the Superfund/SEMS roster actually answered for this asset;nullwhen SUPERFUND was not requested, failed, or the asset was never screened.
The original phase1_esa_flag and npl_sites_within_radius are unchanged and
always will be: they have been live since v1.2 and pipelines are keyed to them.
If a false clear would carry liability for you, filter on the _verified
columns instead, which are blank rather than false / 0 when the check was
never run.
Fields that are often empty, and why
Some columns are legitimately null on most rows because EPA does not carry the data, not because the actor failed to read it. Rather than hide them, here is the measured fill rate for each (2026-07-26) and an input that does populate it.
| Field | Why it is usually null | Measured fill | An input that populates it |
|---|---|---|---|
ust_last_inspection_date | EPA barely populates Date_of_Last_Inspection in UST Finder | 1,445 of 742,855 (0.19%) nationally; 17 of 11,330 in CO | {"lat":37.15785,"lon":-107.605833} (BIA Warehouse #40, CO) |
lust_substance | State-reported; most states file no substance | ~19% nationally; MI 17,398, KS 6,058, CA 9, TX 0, OH 0, CO 0 | {"lat":42.44684,"lon":-83.10325} (Detroit, MI) |
rcra_open_violation_since | Only exists for a facility with an open violation | 0 of 97 within 1 mi of Denver; 26 of 3,238 within 10 mi of Houston | {"lat":29.66984,"lon":-95.23289} |
rcra_land_release_chemicals | Only exists where EPA has a land-release record | 0 of 97 at Denver; 7 of 3,238 at Houston | {"lat":29.71247,"lon":-95.22496} |
institutional_control_* | EPA publishes very few IC boundary polygons | ~165 polygons nationally | {"lat":39.793679,"lon":-104.982364} (ASARCO Globe Plant) |
truncated_programs | Null is the healthy value — nothing was truncated | fills only at large radii in dense metros | radiusMiles: 25 in a major metro |
error | Null on every successful row | fills on error rows only | an asset with neither address nor coordinates |
drift_checks_failed, drift_warnings, programs_degraded | Null is the healthy value — every live upstream assertion passed | 0 of 1,457 rows on the 2026-08-01 audit across the prefill and all five example runs | fills only when an EPA service changes shape or a layer collapses |
name, epa_id, address, city, state, zip, county, npl_status_code, npl_status_name, non_npl_status_name, is_superfund, federal_facility, archived, archived_date, lat, lon | Inventory-mode columns; structurally absent from an assets-mode row | 50 of 50 rows in inventory mode | {"mode":"inventory","states":["CO"],"onlyNpl":false,"onlyWithCoords":true,"maxResults":50} |
A null in these columns is a fact about EPA's records, not a gap in the screen. Where a field means something stronger — on_superfund_site, institutional_control_flag, data_complete — null and false are deliberately different: false means checked-and-negative, null means not checked.
Field availability also depends on which programs a row came from: dfr_url, sic_codes, compliance_status, total_penalties_usd and the rcra_* block exist only on EPA ECHO-derived rows (RCRA/TRI/NPDES/AIR/TSCA/RMP); coordinate_source, receptor counts and the ust_*/lust_* blocks only on UST/LUST rows; sems_coord_source only on Superfund rows.
Caveats worth knowing
- This is a screening aid, not a Phase I ESA. It does not replace a licensed Environmental Professional's records search, and it does not by itself satisfy ASTM E1527-21 or the AAI rule. Use it to triage, then order the real report on anything flagged.
- Federal databases only. State and tribal registries, historical aerials, fire-insurance maps and city directories are not included. Pair it with the companion State UST, LUST & Spill Registry Screener for state-level coverage.
- SEMS/Superfund geocoding varies sharply by state. Measured 2026-07: 3% of Texas SEMS records carry coordinates, 16% California, 48% Colorado, 60% New Jersey, 77% New York. NPL-track records, however, are ~96–100% geocoded everywhere, and the FRS SEMS point layers (100% geocoded, ~14,967 non-NPL + 1,837 NPL points) are unioned in to close much of the remaining gap. A
clearresult still means "no listed, geocoded record within radius", not a guarantee of no history. distance_milesis measured to a database point, not a property boundary — checkcoordinate_sourcebefore relying on a tight distance. Theon_superfund_sitepolygon test is exact.- Institutional-control coverage is thin (~165 national polygons). See the AUL section above.
- An EPA service that changes shape now stops the run rather than answering wrongly. If a source drops a column the screen depends on to identify or locate a site, the run fails with a message naming the column, before any row is emitted and before anything is billed. That is deliberate: on a Phase I screen, a red run you can retry is far cheaper than a
clearrow that missed a listing. Outages behave as they always did — the affected program is marked failed on the row, and the run only fails if every database fails for every asset.
Use as an MCP tool
This Actor is callable directly by any MCP-compatible AI agent through Apify's hosted MCP server. There is no server to run and no integration code to write - the tool schema an agent sees is generated from this Actor's own input and dataset schemas.
Endpoint
https://mcp.apify.com?tools=malonestar/epa-contaminated-site-screener
Claude Desktop, Claude Code or Cursor - add to claude_desktop_config.json,
.mcp.json or .cursor/mcp.json respectively:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=malonestar/epa-contaminated-site-screener","headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }}}}
Get a token at https://console.apify.com/settings/integrations. Claude Desktop can
also authenticate interactively via OAuth against https://mcp.apify.com with no
headers block. Full reference: https://docs.apify.com/platform/integrations/mcp
Try asking your agent
Screen 1200 Broadway, Denver CO for environmental risk under ASTM E1527-21 and tell me which findings are within the standard's search distance.
Chains well with - expose these alongside it by comma-separating the tools
parameter, and the agent can carry results from one into the next:
malonestar/parcel-owner-lookupmalonestar/site-due-diligence-bundlemalonestar/fws-wetlands-proximity-screener
https://mcp.apify.com?tools=malonestar/epa-contaminated-site-screener,malonestar/parcel-owner-lookup,malonestar/site-due-diligence-bundle,malonestar/fws-wetlands-proximity-screener
Billing is unchanged when called as an MCP tool: this Actor is Pay-Per-Event and an agent pays the same per-result price a human does. A run that cannot answer fails without billing rather than returning an unverified negative.
Use in n8n
This Actor is published as an n8n community node, so it can be dropped into a workflow without writing an HTTP request by hand.
- npm: https://www.npmjs.com/package/n8n-nodes-epa-contaminated-site-screener
- source: https://github.com/malonestar/n8n-nodes-epa-contaminated-site-screener
Install from Settings > Community Nodes > Install in any self-hosted n8n
instance, enter n8n-nodes-epa-contaminated-site-screener, then add your Apify API key as an
Apify API credential. The node calls this Actor through the Apify API, so there
is no extra infrastructure to run and billing is identical to a normal run.
Use in n8n
This Actor is published as an n8n community node, so it can be dropped into a workflow without writing an HTTP request by hand.
- npm: https://www.npmjs.com/package/n8n-nodes-epa-contaminated-site-screener
- source: https://github.com/malonestar/n8n-nodes-epa-contaminated-site-screener
Install from Settings > Community Nodes > Install in any self-hosted n8n
instance, enter n8n-nodes-epa-contaminated-site-screener, then add your Apify API key as an
Apify API credential. The node calls this Actor through the Apify API, so there
is no extra infrastructure to run and billing is identical to a normal run.
FAQ
Which databases does it search? Superfund/NPL, RCRA (split into CORRACTS/TSD/generators), TRI, UST, LUST and Brownfields by default; NPDES, AIR, TSCA and RMP on request.
Does this replace a Phase I ESA? No. It is a pre-screen; order a licensed Phase I ESA for anything flagged.
Does this satisfy an ASTM E1527-21 records review or AAI? No. astmMode approximates the standard's search-distance table against this actor's EPA databases. It is not a Phase I ESA and does not satisfy ASTM E1527-21 or 40 CFR Part 312.
What are the ASTM E1527-21 search distances? See the table above — 1.0 mi for NPL and RCRA CORRACTS, 0.5 mi for SEMS-CERCLIS / RCRA TSD / LUST / Brownfields, 0.25 mi for registered UST and RCRA generators.
Can I screen a whole portfolio at once? Yes — pass as many items as you want in assets; each site hit is one row.
How is billing calculated? One dataset row per site hit (assets mode, including the optional astm_summary row) or per SEMS site (inventory mode). Boundary and AUL checks add fields, not rows, and are not billed. Runs that cannot screen anything fail without billing.