# Historic Land Use Screener - Contaminating SIC/NAICS Sites (`malonestar/historic-land-use-sic-contaminant-screener`) Actor

Screens a coordinate or address radius against EPA FRS SIC and NAICS classifications to find dry cleaners, gas stations, plating shops, auto shops, printers and other recognised contaminating land uses, for ASTM E1527-21 Section 8.3 prior-use review.

- **URL**: https://apify.com/malonestar/historic-land-use-sic-contaminant-screener.md
- **Developed by:** [Kyle Maloney](https://apify.com/malonestar) (community)
- **Categories:** Real estate, Developer tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.60 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Historic Land Use Screener - Contaminating SIC/NAICS Sites

**Give it a coordinate or an address. It returns the dry cleaners, gas stations, plating shops, auto body shops, printers, wood treaters, scrap yards and other recognised contaminating businesses inside the radius - identified by their reported industrial classification, with the contaminants of concern each land use implies and the published authority that says so.**

This is the ASTM E1527-21 **Section 8.3 "prior uses of the property"** line item: *what kind of business is, or was, operating here?* It is a different question from the records review in Section 8.2, and it is the part Phase I consultants most often assemble by hand.

***

### Who it is for

- **Phase I ESA consultants and environmental professionals** completing the prior-use section of an AAI-compliant report.
- **CRE acquisition and lender due-diligence teams** who need a fast, defensible read on whether a target parcel sits next to a solvent user before ordering a full Phase I.
- **Environmental engineers** scoping a Phase II: the contaminant list per land-use class tells you what to analyse for.
- **Brownfield and redevelopment teams** triaging a pipeline of sites.
- **AI agents** doing site due diligence - the output is flat, typed, and every claim carries its own status field.

### What makes it different from a regulatory-database search

Most environmental screens answer *"is this address on a federal list?"* This one answers *"what industry is operating here?"* The two overlap far less than you would expect.

Measured live on 2026-08-18, comparing the facilities this actor finds against the facilities EPA's ECHO radius search returns at the same point and radius:

| Location | Contaminating facilities found here | Of those, invisible to a federal ECHO radius search |
|---|---|---|
| Newark, NJ (Ironbound), 0.5 mi | 38 | **21 (55%)** |
| Van Nuys, CA, 0.5 mi | 15 | **10 (67%)** |
| Denver, CO (CBD), 0.25 mi | 9 | 1 |

The gap is state program systems. EPA's Facility Registry Service unifies **97 program systems**, roughly 40 of which are **state** environmental agency registers - NJ-NJEMS, CA-ENVIROVIEW, TX-TCEQ ACR, PA-EFACTS, MO-DNR, WA-FSIS, OR-DEQ, OH-CORE and others. A neighbourhood laundromat or auto shop that holds only a state registration is simply not in the federal compliance database. Nationally, **15,596 of the 35,836 dry-cleaning (SIC 7216) records - 43.5% - come from non-federal program systems.**

**It pairs with, and does not replace, [epa-contaminated-site-screener](https://apify.com/malonestar/epa-contaminated-site-screener).** That actor answers Section 8.2 - Superfund/SEMS, RCRA, UST/LUST, brownfields, ECHO enforcement, NPL proximity. This one answers Section 8.3. Run both on the same coordinate for a complete records-plus-prior-use picture.

***

### Example input

```json
{
  "assets": [
    { "lat": 39.7392, "lon": -104.9903, "label": "Denver CBD parcel (CO)" },
    { "lat": 40.7274, "lon": -74.1590, "label": "Newark Ironbound parcel (NJ)" },
    { "address": "1438 Tremont Pl, Denver, CO 80202", "label": "Address input example" }
  ],
  "radiusMiles": 0.25,
  "maxFacilitiesPerAsset": 100
}
```

Every property produces **one `facility` row per contaminating land use found**, plus **one `asset_summary` row** carrying the verdict and the coverage statistics behind it.

Optional inputs: `programs` (opt into the state / tribal equivalent record leg - see below), `landUseClasses` (limit to specific classes), `includeSecondaryClassifications`, `includeUnclassifiedFacilities`, `crossStateRecords`, `coordinateStackThreshold`, `maxFacilitiesPerAsset`, `maxResults`, `simulateOutage`.

`maxResults` must be at least the number of properties in `assets`, because every property gets its own summary row. See **Correctness guarantees** below.

***

### The 24 contaminating land-use classes

Dry cleaning and commercial laundry - Fuel dispensing, bulk petroleum storage and distribution - Petroleum refining and crude oil / natural gas production - Metal plating, coating, anodizing and heat treating - Metal fabrication, foundries, smelting and machine shops - Automotive repair, body shops and vehicle maintenance - Scrap, salvage and waste-material recycling - Wood preserving and treating - Sawmills, millwork and reconstituted wood products - Commercial printing, publishing and platemaking - Chemical, paint, resin and pesticide manufacturing - Explosives, ordnance and munitions - Refuse systems, landfills and sanitary services - Printed circuit board, semiconductor and electronic component manufacture - Storage and primary battery manufacture - Leather tanning, textile finishing and coated fabrics - Gas manufacture / distribution and electric utility operations - Truck and rail terminals and maintenance yards - Airports, aviation services and aircraft maintenance - Photofinishing and photographic processing - Pest control and disinfecting services - Plastics and rubber products manufacture - Pulp and paper mills - National security and defence installations.

Each class carries its contaminants of concern on the row. Dry cleaning, for example, returns tetrachloroethene (PCE), trichloroethene (TCE), 1,1,1-trichloroethane, petroleum dry-cleaning solvent and the chlorinated-solvent degradation products.

***

### Where the mapping comes from, and what it is not

The classification-to-contaminant crosswalk is a **curated, versioned vocabulary** (`contaminant_mapping_version` ships on every row). It is **not** a verbatim reproduction of any single agency list, and it is **not** a determination that contamination exists.

Every entry names the published authority that identifies the industry as a potential contaminant source, and that authority ships on the row in `contaminant_mapping_authorities`, `contaminant_mapping_citation` and `contaminant_mapping_url`:

- **U.S. EPA Office of Compliance, Sector Notebook Project** - per-industry profiles of process operations, waste streams and pollutant releases, indexed by SIC code.
- **NJDEP Industrial Site Recovery Act, N.J.A.C. 7:26B** - New Jersey defines an "industrial establishment" by the industry classification codes listed in the chapter's Appendix C, i.e. the classifications the State identifies as having the potential for discharge of hazardous substances.

Code titles are verbatim from their own authorities: **SIC titles from the OSHA SIC Manual (1987)**, **NAICS titles from the U.S. Census Bureau 2022 NAICS file**.

### What "historic" does and does not mean here

**Read this before quoting the output in a report.** EPA FRS publishes the industrial classification a facility **currently reports** to each program system. Every row says so in `temporal_basis` and `temporal_basis_note`.

- It **is** evidence of the reported business type of a facility that appears in the federal registry today, or was last reported on `record_last_reported_date`.
- It is **not** a title-chain search, a city-directory search, or a historical aerial-photograph review, and it does **not** establish what occupied the parcel before the facility was registered.
- The strongest former-use signal this dataset carries is `operational_status` - a record marked terminated, expired or permanently closed, together with `record_last_reported_date`, indicates a use that has ended.

Use it as the systematic first pass over the Section 8.3 question, then close the remaining gap with directories, aerials and interviews.

***

### Opt-in: state and tribal equivalent record sources (ASTM E1527-21 Section 8.2)

ASTM E1527-21 requires a search of **state and tribal agency** record sources alongside the federal ones. EPA already normalises a set of state and tribal agency program systems into the very registry this actor queries, so those records are reachable in the same run at no extra row cost.

Add `"programs": ["state"]` to switch the leg on. **Leave it out and this actor behaves exactly as it did before the leg existed** - same rows, same values, same requests. The leg adds **two requests per distinct state** in your run (not per property) and **no extra rows**; state findings are additional columns on the rows you were already getting.

```json
{
  "assets": [{ "lat": 40.7274, "lon": -74.1590, "label": "Newark Ironbound parcel (NJ)" }],
  "programs": ["state"],
  "radiusMiles": 0.25
}
```

#### Coverage is uneven, and that is the whole point of the contract

**Measured 2026-08-20 across all 56 `STATE_CODE` values: twelve jurisdictions have ZERO state or tribal agency program system in EPA FRS** - Alaska, **Colorado**, the District of Columbia, **Michigan**, South Dakota, Vermont, West Virginia, and the territories American Samoa, Guam, Northern Mariana Islands, Puerto Rico and the US Virgin Islands.

If a screening tool simply filtered the radius on "state systems" and found none, a Colorado buyer would receive a clean, billable *"no state agency records near this property"* that in fact means *"EPA normalises no Colorado state agency records at all"*. On an ASTM deliverable that is not a missing feature, it is a wrong answer.

So every `asset_summary` row carries:

- **`state_coverage`** - `complete` / `partial` / `none`, and `none` is a first-class outcome meaning *this record class could not be searched in this jurisdiction*, not *nothing was found*.
- **`state_program_systems_available_for_state`** - what EPA actually publishes for that state, measured this run, with record counts.
- **`state_program_systems_checked`** - what this property was actually screened against.
- **`state_program_systems_indeterminate`** - systems that could not be classified either way, named rather than quietly sorted.

**When `state_coverage` is `none`, every state count is `null`, never `0`.** Zero would be a claim that we looked. Facility rows in such a jurisdiction carry `state_equivalent_record: null` for the same reason.

Coverage reads `partial` when the radius read did not complete, or when a program system falls in the unclassifiable band - and a `partial` can never produce a clean negative verdict.

#### The inventory is measured live every run, never read from a list

A hard-coded table of "state" program acronyms rots into exactly the false clear above the first time EPA onboards or retires an agency. It is also simply wrong today, because **the acronyms do not say what they are.** Measured:

| Acronym | Actually the agency system of | Share of its national records in that state |
|---|---|---|
| `MERI-FIS` | **New Jersey** (not Maine) | 100.00% of 436 |
| `UST` | **Tennessee** (reads federal) | 100.00% of 772 |
| `FIS` | New York | 100.00% of 131,231 |
| `ACES` | Illinois | 100.00% of 95,511 |
| `AZURITE` | Arizona | 100.00% of 40,447 |
| `CIM` | Utah | 100.00% of 8,547 |
| `CEDS` | Virginia | 100.00% of 5,780 |
| `PDS` | Arkansas | 99.99% of 26,087 |
| `DEN` | Delaware | 99.95% of 9,871 |
| `PERMIT TRACKING` | Alabama | 99.97% of 7,144 |
| `CNFRS` | Oklahoma | 100.00% of 87 |
| `ISD` | Wyoming | 100.00% of 13 |

A two-letter-prefix heuristic would classify every one of those as federal and silently under-report the record class it is being paid to find.

Instead the inventory is derived from two live group-by reads on every run - one national, one for the property's state - and a program system counts as state or tribal equivalent when at least **90%** of its national records sit in that state. That is a property of the data, so it cannot go stale.

**The threshold is measured, not guessed.** Across all 97 program systems: **57 sit between 96.05% and 100%** (the state and tribal agency systems), **three between 53% and 66%** (`CDAFLP` in Idaho, `FARR` in Washington, `NNEMS` in Arizona), and **37 at 42.47% or below** (`RCRAINFO`, `NPDES`, `EIS` and the rest of the federal programmes). 0.90 sits in the middle of a 30-point empty band. Anything landing in the 0.50-0.90 gap is reported as indeterminate and forces `state_coverage` to `partial`.

The measured per-state inventory, 2026-08-20, ranges from **six systems in California** (`CA-ENVIROVIEW` 221,506 · `CA-CERS` 36,851 · `HWTS-DATAMART` 17,734 · `UORS` 3,099 · `DTSC-ENVIROSTOR` 1,860 · `CASWIS` 126) and **four in Maryland**, through **one in most states** (`NJ-NJEMS` 263,315 · `TX-TCEQ ACR` 119,443 · `NV-FP` 4,866), down to **none at all** in the twelve jurisdictions listed above.

#### Four extra drift probes guard it

When the leg is on, four probes run against the live service before any billable row, each in its own error boundary and each reporting `pass` / `fail` / `unavailable`:

1. **Program-system universe** (load-bearing) - the group-by is untruncated, returns a plausible number of systems, and **its counts sum exactly to the layer's own row total**, which is a free exact truncation guard.
2. **Positive canary** (load-bearing) - `NJ-NJEMS` returns a count inside its measured band **and strictly less than the whole layer**, because an ignored `WHERE` on this service returns the national table and would sail past a band check.
3. **Confinement canary** (load-bearing) - the canary state system is still confined to its own state above the threshold. If that stops being true, state and federal systems can no longer be told apart from the data and the run fails rather than guessing.
4. **Negative control** (corroborating) - a bogus `PGM_SYS_ACRNM` returns exactly 0.

None of these run when the leg is off, so a default run makes exactly the same requests it always did.

#### What it is not

The state and tribal agency systems normalised into EPA FRS are a **subset** of any state agency's own record holdings. This leg tells you which state agency program systems EPA publishes for a jurisdiction, which of them a property appears in, and the program ID to quote when requesting the file. It does not replace a direct request to the state agency, and `state_coverage: "none"` is an instruction to make one.

***

### Correctness guarantees, all measured

**A negative is never asserted without verification.** `contaminating_use_match` is `true` when a classification matched, `false` when classifications exist and none matched, and **`null` when EPA publishes no classification at all**. Nationally, FRS\_SIC holds 2,051,024 rows and FRS\_NAICS 2,937,686 against **6,983,618 interest records**, so most FRS facilities carry no classification. Every summary row reports `classification_coverage_pct` and `facilities_without_any_classification` so a clean verdict can be read against how much was actually classifiable.

**EPA geocodes many FRS records to the operator's mailing address, not the operating site.** Measured 2026-08-18: of 188 FRS interests within 402 m of downtown Denver, **90 are Wyoming oil and gas well pads** - SHIPROCK FEDERAL 28-1, WIND DANCER 34-28 PAD, HAYSTACK 30-4 - all filed under `LOCATION_ADDRESS` "1560 BROADWAY SUITE 2000" and **all sharing one identical coordinate**, the operator's Denver office. Reporting those as land uses 1,200 feet from a subject property would be a confident wrong answer on a liability-bearing report. Every row therefore carries `location_confidence`, `location_state_matches_query_state` and `colocated_facility_count`, and mailing-address geocodes and coordinate stacks are **excluded from the verdict by default** while still being emitted and counted.

**A SECONDARY classification is never reported as the facility's business.** EPA marks each code PRIMARY, SECONDARY or UNKNOWN, and `primary_land_use_class_basis` always says which one the verdict rests on.

**Malformed codes are reported, never guessed.** FRS\_SIC is a 4-character text column holding real junk - `OWNE` on 19,018 rows nationally, `UNK` on 11,875, plus 2- and 3-digit truncations. A 3-digit value is genuinely ambiguous, so it is surfaced in `malformed_classification_codes` and never expanded into a match. FRS\_NAICS holds **55,632 rows beginning with a leading zero**, which no valid NAICS code has; those are normalised and the normalisation is disclosed in `naics_leading_zero_codes`.

**Both NAICS vintages are screened.** FRS stores 2017 and 2022 NAICS side by side. Gasoline stations measured 2026-08-18: 447110 = 24,008 plus 447190 = 16,439 plus 44711 = 14,841 in the 2017 family, against 457110 = 15,868 plus 457120 = 6,596 in the 2022 family. A vocabulary built on either vintage alone would silently miss the other, so matching is longest-prefix across both.

**Live drift gate, before any billable row.** Seven probes run against the live service (eleven when the opt-in state leg is requested) before a single row is emitted: the three layers publish the columns the join needs; FRS\_SIC and FRS\_NAICS are above their row-count floors; SIC 7216 and NAICS 812320 return counts inside their measured bands; **the filtered count is strictly less than the unfiltered count** (an ignored WHERE clause on this service would return the whole national table and sail past a floor); and a bogus code returns exactly zero. Each probe has its own error boundary and reports `pass` / `fail` / `unavailable`. A probe that measures the wrong answer fails the run; a **load-bearing** probe that cannot complete fails the run; only the **corroborating** negative control may be unavailable, in which case the run proceeds and says so in `drift_gate_status`.

**No silent zero.** A run that cannot answer fails loudly with 0 rows and 0 billed. `assets` is a required input, so a bare `{}` call is rejected before the run starts.

**Every property you submit comes back, and a truncated answer can never be mistaken for a complete one.** There are two separate caps and both are disclosed on the row.

- `maxFacilitiesPerAsset` caps the facility rows for **one** property. When it bites, that property's `results_truncated` reads `true` and a would-be negative verdict is downgraded to `inconclusive`.
- `maxResults` caps the rows for the **whole run**. It never drops an `asset_summary` row. The run reserves one summary slot per requested property and divides whatever budget is left over the facility detail on a max-min fair basis, so one busy downtown parcel cannot starve nine quiet ones. Where detail was trimmed, the rows read `asset_screen_status: "partial"`, `results_truncated_global: true`, and `facility_rows_dropped_by_global_cap: <n>`. The summary's counts and verdict are computed over **every** facility found, not just the rows emitted, so trimming costs you supporting detail and never the verdict.

**The invariant: the dataset always holds exactly one `asset_summary` row per property you submitted, in the order you submitted them.** `assets_requested`, `assets_screened_complete`, `assets_screened_partial` and `assets_not_reached` are stamped on every row and always add up. So a portfolio run can be reconciled against the input without inspecting the log, and there is no way for a property to be quietly missing.

A property that could not be screened at all — an address the US Census geocoder cannot resolve, for instance — still gets its `asset_summary` row, with `astm_prior_use_verdict: "not_screened"`, a `not_screened_reason` naming the problem, and every count `null` rather than `0`. Null means *not checked*; zero would be a claim that we looked and found none. That row is billable, because it is a per-property answer, and it is bounded by `maxResults` like any other.

If `maxResults` is lower than the number of properties submitted, the run **fails before emitting anything** and tells you the minimum to set. Returning four of your ten properties with nothing in the data saying which six were skipped is the one outcome this design refuses.

***

### Output fields (156 fields)

##### Property (echoed on every row)

| Field | Type | What it means |
|---|---|---|
| `row_type` | string | null | "facility" for one contaminating land use, or "asset\_summary" for the one-per-property rollup. |
| `asset_label` | string | null | The label you supplied for this property, echoed back on every row. |
| `asset_address` | string | null | The address you supplied, or null when the property was given as a coordinate. |
| `asset_lat` | number | null | Latitude actually screened (WGS84), after geocoding if an address was supplied. |
| `asset_lon` | number | null | Longitude actually screened (WGS84), after geocoding if an address was supplied. |
| `asset_state` | string | null | Two-letter state the query coordinate falls in, resolved from the US Census geocoder. Null when the geocoder was unavailable. |
| `asset_state_name` | string | null | Full state name of the query coordinate from the US Census geocoder. |
| `asset_county_fips` | string | null | 5-digit county FIPS of the query coordinate from the US Census geocoder. |
| `asset_county_name` | string | null | County name of the query coordinate from the US Census geocoder. |
| `radius_miles` | number | null | Radius screened around the property. |

##### Facility identity and location

| Field | Type | What it means |
|---|---|---|
| `facility_id` | string | null | Stable identity for the facility - the EPA FRS REGISTRY\_ID, or the FRS KEY\_FIELD when EPA publishes no registry id. |
| `facility_id_basis` | string | null | "registry\_id" or "key\_field" - which identifier facility\_id came from. |
| `registry_id` | string | null | EPA Facility Registry Service REGISTRY\_ID. Null when EPA publishes none for this record. |
| `facility_name` | string | null | PRIMARY\_NAME as EPA FRS publishes it. |
| `facility_address` | string | null | LOCATION\_ADDRESS as EPA FRS publishes it. Note this can be the operator mailing address - see location\_confidence. |
| `facility_city` | string | null | CITY\_NAME as EPA FRS publishes it. |
| `facility_state` | string | null | Two-letter STATE\_CODE the FRS record is filed under. |
| `facility_zip` | string | null | POSTAL\_CODE as EPA FRS publishes it. |
| `facility_county_name` | string | null | COUNTY\_NAME as EPA FRS publishes it. |
| `facility_county_fips` | string | null | 5-digit county FIPS normalised from the FRS FIPS\_CODE column. Null when the published value could not be resolved without guessing. |
| `facility_county_fips_raw` | string | null | The FIPS\_CODE value exactly as EPA published it. Measured spellings include "08031", "CO031", "8031" and null in a single page. |
| `facility_lat` | number | null | LATITUDE83 as EPA FRS publishes it (NAD83). |
| `facility_lon` | number | null | LONGITUDE83 as EPA FRS publishes it (NAD83). |
| `distance_miles` | number | null | Great-circle distance from the property to the FRS coordinate. Read it together with location\_confidence - a mailing-address geocode makes this distance meaningless. |
| `frs_facility_url` | string | null | EPA's own facility detail page for this record. |

##### Location reliability (the mailing-address geocode guard)

| Field | Type | What it means |
|---|---|---|
| `coordinate_accuracy_meters` | number | null | EPA ACCURACY\_VALUE - the accuracy EPA claims for the published coordinate, in metres. |
| `coordinate_collection_method` | string | null | EPA COLLECT\_MTH\_DESC, e.g. "ADDRESS MATCHING-HOUSE NUMBER". |
| `coordinate_reference_point` | string | null | EPA REF\_POINT\_DESC, e.g. "CENTER OF A FACILITY OR STATION". |
| `colocated_facility_count` | number | null | How many distinct facilities in this property's radius publish this exact coordinate. A high value indicates an address-level geocode shared by many registrations. |
| `location_confidence` | string | null | "consistent" | "state\_mismatch" (record filed in another state - almost certainly the operator mailing address) | "coordinate\_stack" (many facilities on one coordinate) | "unknown" (state cross-check could not be performed). |
| `location_state_matches_query_state` | boolean | null | true / false / null. null means the check was not performed, never that it passed. |
| `location_confidence_reason` | string | null | Plain-language explanation of why this coordinate was classified the way it was. Null when confidence is "consistent". |
| `counts_toward_verdict` | boolean | null | Whether this facility contributed to the property's ASTM prior-use verdict. Mailing-address geocodes and coordinate stacks do not, unless crossStateRecords is set to "include". |

##### EPA program registration

| Field | Type | What it means |
|---|---|---|
| `program_systems` | string | null | Semicolon-separated EPA/state program systems this facility is registered in (PGM\_SYS\_ACRNM), e.g. "AIR; AIRS/AFS" or "NJ-NJEMS". |
| `program_system_count` | number | null | How many distinct program systems carry this facility. |
| `program_ids` | string | null | Semicolon-separated program-specific identifiers (PGM\_SYS\_ID). |
| `interest_types` | string | null | Semicolon-separated FRS INTEREST\_TYPE values, e.g. "AIR MINOR", "SQG", "STATE MASTER". |
| `key_fields` | string | null | Semicolon-separated FRS KEY\_FIELD values (PGM\_SYS\_ACRNM + PGM\_SYS\_ID) - the keys the SIC and NAICS classification tables join on. |
| `federal_agency_name` | string | null | FEDERAL\_AGENCY\_NAME when the facility is a federal installation. |
| `epa_region_code` | string | null | EPA region code (01-10). |

##### Operational status and record age (the former-use signal)

| Field | Type | What it means |
|---|---|---|
| `operational_status` | string | null | "operating" | "closed\_or\_terminated" | "unknown". A closed or terminated record is the strongest signal in this dataset that the use is FORMER rather than current. |
| `operational_status_basis` | string | null | "explicit\_phrase" | "coded\_flag" (a program-specific Y/N) | "uninterpretable\_value" | "not\_reported". EPA publishes 47 distinct ACTIVE\_STATUS values across 97 program systems; ambiguous single letters are left unknown rather than guessed. |
| `operational_status_raw` | string | null | The ACTIVE\_STATUS value exactly as EPA published it. |
| `record_created_date` | string | null | FRS CREATE\_DATE as YYYY-MM-DD. |
| `record_updated_date` | string | null | FRS UPDATE\_DATE as YYYY-MM-DD. |
| `record_last_reported_date` | string | null | FRS LAST\_REPORTED\_DATE as YYYY-MM-DD - how recently the program system reported this facility. |

##### Contaminating land-use verdict

| Field | Type | What it means |
|---|---|---|
| `classification_available` | boolean | null | Whether EPA publishes ANY SIC or NAICS classification for this facility. false means EPA published none - it does NOT mean the facility has no contaminating use. |
| `contaminating_use_match` | boolean | null | true when a classification matched the contaminating land-use vocabulary; false when classifications exist and none matched; null when no classification was published at all. |
| `land_use_classes` | string | null | Semicolon-separated contaminating land-use class IDs matched on this facility. |
| `land_use_class_labels` | string | null | Human-readable labels for land\_use\_classes. |
| `primary_land_use_class` | string | null | The single class that best characterises the facility - taken from a PRIMARY-indicator code where one exists, otherwise the highest-risk match. |
| `primary_land_use_class_label` | string | null | Human-readable label for primary\_land\_use\_class. |
| `primary_land_use_class_basis` | string | null | How primary\_land\_use\_class was chosen, e.g. "sic\_primary\_indicator" or "naics\_secondary\_indicator" - so a secondary classification is never silently read as the facility's business type. |
| `contaminant_risk_tier` | string | null | "high" | "moderate" | "low" - the highest tier across the matched classes, from the vocabulary. |
| `contaminants_of_concern` | string | null | Semicolon-separated contaminant groups the cited authorities associate with the matched land uses. These are the constituents typically investigated, not measured concentrations. |
| `contaminants_of_concern_count` | number | null | How many distinct contaminant groups are listed. |

##### SIC classification detail

| Field | Type | What it means |
|---|---|---|
| `sic_codes_all` | string | null | Every SIC\_CODE value EPA publishes for this facility, exactly as stored, including malformed ones. |
| `sic_codes_matched` | string | null | The SIC codes that matched the contaminating land-use vocabulary. |
| `sic_titles_matched` | string | null | Official OSHA SIC Manual titles for the matched SIC codes. |
| `sic_primary_codes` | string | null | SIC codes EPA marks PRIMARY\_INDICATOR = PRIMARY for this facility. |
| `sic_secondary_codes` | string | null | SIC codes EPA marks SECONDARY. A secondary code is not the facility's principal business. |
| `sic_unknown_indicator_codes` | string | null | SIC codes EPA marks UNKNOWN - EPA itself does not say whether the code is the facility's primary business. |
| `sic_row_count` | number | null | How many FRS\_SIC rows joined to this facility. |

##### NAICS classification detail

| Field | Type | What it means |
|---|---|---|
| `naics_codes_all` | string | null | Every NAICS\_CODE value EPA publishes for this facility, exactly as stored. |
| `naics_codes_matched` | string | null | NAICS codes that matched the vocabulary, after leading-zero normalisation. |
| `naics_stems_matched` | string | null | The vocabulary stems that matched. Matching is longest-prefix because FRS stores 5- and 6-digit codes from two NAICS vintages side by side. |
| `naics_titles_matched` | string | null | Official Census NAICS titles for the matched stems. |
| `naics_vintages_matched` | string | null | Which NAICS vintage (2017 or 2022) each matched stem belongs to. |
| `naics_leading_zero_codes` | string | null | NAICS values EPA stored with a leading zero, which no valid NAICS code has. Reported so the normalisation is visible rather than silent. |
| `naics_row_count` | number | null | How many FRS\_NAICS rows joined to this facility. |

##### Match quality and data defects

| Field | Type | What it means |
|---|---|---|
| `match_count_primary_indicator` | number | null | How many matching classifications EPA marks PRIMARY. |
| `match_count_secondary_or_unknown_indicator` | number | null | How many matching classifications EPA marks SECONDARY or UNKNOWN. |
| `malformed_classification_codes` | string | null | Codes EPA published that are not resolvable classification codes (e.g. SIC "OWNE", "UNK", or a 3-digit truncation). They are reported, never guessed at, and never counted as a match. |
| `malformed_classification_code_count` | number | null | How many malformed codes this facility carries. |
| `unmatched_sic_code_count` | number | null | Well-formed SIC codes that are simply not contaminating land uses. |
| `unmatched_naics_code_count` | number | null | Well-formed NAICS codes that are simply not contaminating land uses. |

##### Provenance of the contaminant mapping

| Field | Type | What it means |
|---|---|---|
| `contaminant_mapping_version` | string | null | Version of the classification-to-contaminant vocabulary used for this row. |
| `contaminant_mapping_authorities` | string | null | The published authorities that identify the matched industries as potential contaminant sources. |
| `contaminant_mapping_citation` | string | null | Full citation text for those authorities. |
| `contaminant_mapping_url` | string | null | Link to the primary cited authority. |
| `astm_reference` | string | null | The ASTM E1527-21 clause this screen supports. |
| `temporal_basis` | string | null | Always "current\_reported\_classification". EPA FRS publishes the classification a facility CURRENTLY reports, not a historical land-use record. |
| `temporal_basis_note` | string | null | Plain-language statement of exactly what the classification does and does not tell you about historic use. |

##### Per-source status (null vs false contract)

| Field | Type | What it means |
|---|---|---|
| `frs_interests_status` | string | null | "ok" | "partial" | "unavailable" | "not\_run" for the radius query behind this row. |
| `frs_sic_status` | string | null | "ok" | "partial" | "unavailable" | "not\_run" for the SIC classification join. |
| `frs_naics_status` | string | null | "ok" | "partial" | "unavailable" | "not\_run" for the NAICS classification join. |
| `geocoder_status` | string | null | "ok" | "unavailable" | "not\_run" for the US Census geocoder used to resolve the query point's state. |
| `frs_interests_error` | string | null | Error text when the radius query did not fully succeed. |
| `frs_sic_error` | string | null | Error text when the SIC join did not fully succeed. |
| `frs_naics_error` | string | null | Error text when the NAICS join did not fully succeed. |
| `geocoder_error` | string | null | Error text when the Census geocoder did not answer. |

##### Live drift gate disclosure

| Field | Type | What it means |
|---|---|---|
| `drift_gate_status` | string | null | "verified" or "verified\_degraded" on any emitted row. A failed or incomplete load-bearing gate fails the whole run before anything is emitted or billed. |
| `drift_gate_note` | string | null | What the live drift gate measured on this run. |
| `drift_probes_verified` | string | null | Semicolon-separated ids of the drift probes that passed. |
| `drift_probes_unavailable` | string | null | Semicolon-separated ids of drift probes that could not complete. Only corroborating probes may be unavailable on an emitted row. |
| `drift_negative_control_status` | string | null | Outcome of the corroborating negative control (a bogus SIC code must return zero rows). |

##### State / tribal equivalent records - opt-in, facility rows

| Field | Type | What it means |
|---|---|---|
| `state_program_systems` | string | null | Semicolon-separated EPA FRS PGM\_SYS\_ACRNM values on this facility that were measured this run to be state or tribal agency program systems (at least 90% of their national records sit in this state). null when the opt-in state leg was not requested or could not run - null means NOT CHECKED, never "checked and none". |
| `state_program_ids` | string | null | The facility's PGM\_SYS\_ID values in those state or tribal agency systems - the identifier to quote when requesting the file from the state agency. null when the state leg was not requested or could not run. |
| `state_equivalent_record` | boolean | null | true when this facility carries at least one state or tribal agency program record - the ASTM E1527-21 Section 8.2 "state and tribal equivalent" record class. false is a VERIFIED negative for this facility. null means the state leg was not requested or could not run for this property. Read it together with the summary row's state\_coverage: a false here inside a state whose state\_coverage is "none" only means FRS holds no state system for that jurisdiction. |
| `state_equivalent_record_share` | number | null | The highest measured in-state share of national records among this facility's matched state systems (1.0 = every record that system holds nationally is in this state). Published so the classification can be audited rather than trusted. null when not checked or when no state system matched. |

##### State / tribal equivalent records - opt-in, summary rows (the coverage contract)

| Field | Type | What it means |
|---|---|---|
| `state_leg_requested` | boolean | null | Whether this run asked for the opt-in state and tribal equivalent record leg via programs: \["state"]. false means the leg never ran and every other state\_\* field on this row is null. |
| `state_leg_status` | string | null | "not\_requested" | "ok" | "unavailable" | "state\_unknown" | "not\_screened". Anything other than "ok" means no state-record conclusion was reached for this property and the counts are null rather than zero. |
| `state_coverage` | string | null | "complete" | "partial" | "none" | null. THE LOAD-BEARING FIELD OF THIS LEG. "none" means EPA FRS normalises NO state or tribal agency program system for this jurisdiction at all, so this record class could not be searched here - it is NOT a searched-and-empty result, and the state counts are null so no downstream filter can read it as one. Measured 2026-08-20: AK, CO, DC, MI, SD, VT, WV and the US territories all read "none". "partial" means either the radius read did not complete or one or more program systems could not be classified from the data. null means the leg did not run. |
| `state_coverage_reason` | string | null | Plain-language explanation of the state\_coverage value, naming the jurisdiction, the systems searched and, when coverage is not complete, exactly what was not searched. |
| `state_coverage_note` | string | null | Standing disclosure that the state and tribal agency systems normalised into EPA FRS are a SUBSET of any state agency's own record holdings, and that state\_coverage="none" means the class could not be searched here rather than that nothing was found. |
| `state_program_systems_checked` | string | null | The state or tribal agency program systems this property was actually screened against, with the count of records each holds in this state. null when the leg did not run or the radius read did not complete, in which case nothing was searched and nothing may be read as a negative. |
| `state_program_systems_checked_count` | number | null | How many state or tribal agency program systems this property was actually screened against. null when the leg did not run. |
| `state_program_systems_available_for_state` | string | null | Every state or tribal agency program system EPA FRS publishes for this jurisdiction, measured live this run, with each system's in-state record count. null when the leg did not run; null with state\_coverage="none" means EPA publishes none at all. |
| `state_program_systems_available_for_state_count` | number | null | How many state or tribal agency program systems EPA FRS publishes for this jurisdiction. 0 with state\_coverage="none" is a fact about EPA's coverage of the state, not about this property. |
| `state_program_systems_indeterminate` | string | null | Program systems holding between 50% and 90% of their national records in this state - too concentrated to call federal, too dispersed to call a state agency system. They are neither counted nor discarded, and their presence forces state\_coverage to "partial". Measured 2026-08-20 this affects CDAFLP (ID), FARR (WA) and NNEMS (AZ). |
| `state_program_systems_indeterminate_count` | number | null | How many program systems in this jurisdiction fell into the indeterminate confinement band. Any value above zero downgrades state\_coverage to "partial". |
| `state_program_universe_size` | number | null | How many distinct PGM\_SYS\_ACRNM values the whole FRS\_INTERESTS layer published on this run (measured 97 on 2026-08-20). A drop below the floor fails the run rather than silently shrinking the record class. |
| `state_confinement_threshold` | number | null | The in-state share of national records at or above which a program system was treated as a state or tribal agency system on this run (0.9). Measured basis: 57 systems sit at 96.05%-100%, three between 53% and 66%, and 37 at 42% or below, so 0.9 sits inside a 30-point empty band rather than on a cliff edge. |
| `state_equivalent_facility_count` | number | null | How many FRS facilities within the radius carry at least one state or tribal agency program record. null when state\_coverage is "none" - there was no record class to search, and zero would claim we looked. |
| `state_equivalent_facility_count_counted_toward_verdict` | number | null | The subset of state-record facilities whose published coordinate passed the mailing-address and coordinate-stack checks. Only these drive astm\_state\_equivalent\_verdict, for the same reason they drive the prior-use verdict. null when state\_coverage is "none". |
| `state_equivalent_contaminating_use_count` | number | null | Facilities carrying both a state or tribal agency record and a contaminating SIC/NAICS classification - the strongest single signal this leg produces. null when state\_coverage is "none". |
| `astm_state_equivalent_verdict` | string | null | "state\_equivalent\_record\_identified" | "no\_state\_equivalent\_record\_found" | "state\_equivalent\_records\_not\_available\_for\_this\_state" | "inconclusive" | "not\_requested" | "not\_screened". Deliberately SEPARATE from astm\_prior\_use\_verdict, which is unchanged by this leg. It can never read as a clean negative while coverage is "partial" or "none". |
| `astm_state_equivalent_reference` | string | null | The ASTM E1527-21 clause this leg addresses: Section 8.2 state and tribal equivalent record sources. Distinct from the Section 8.3 prior-use question the rest of the actor answers. |
| `state_program_inventory_basis` | string | null | States plainly that the per-state program-system inventory is measured live from two FRS group-by reads on every run and that no hard-coded list of state agencies is used - because such a list rots into a false clear the first time EPA onboards or retires an agency system. |

##### Asset summary row only

| Field | Type | What it means |
|---|---|---|
| `astm_prior_use_verdict` | string | null | "contaminating\_use\_identified" | "no\_classified\_contaminating\_use\_found" | "inconclusive" | "not\_screened". It can never read as a negative while a source was unavailable or this property's result set was truncated by maxFacilitiesPerAsset, and a property that could not be screened reads "not\_screened" rather than being omitted from the output. |
| `astm_prior_use_verdict_reason` | string | null | Why the verdict reads the way it does, including how many facilities published no classification at all. |
| `highest_contaminant_risk_tier` | string | null | Highest contaminant risk tier among the facilities that counted toward the verdict. |
| `nearest_contaminating_use_name` | string | null | Name of the nearest facility that counted toward the verdict. |
| `nearest_contaminating_use_class` | string | null | Land-use class of the nearest counted facility. |
| `nearest_contaminating_use_distance_miles` | number | null | Distance to the nearest facility that counted toward the verdict. |
| `frs_interest_records_in_radius` | number | null | Raw FRS\_INTERESTS rows returned. One facility usually carries several interest records, one per program system. |
| `frs_facilities_in_radius` | number | null | Distinct facilities after deduplicating interest records. |
| `facilities_with_classification` | number | null | How many of those facilities EPA publishes any SIC or NAICS code for. |
| `facilities_without_any_classification` | number | null | How many publish none. These are NOT evidence of no contaminating use - EPA simply does not classify them. |
| `classification_coverage_pct` | number | null | Share of in-radius facilities that carry any industrial classification. Read the negative verdict against this number. |
| `contaminating_use_facility_count` | number | null | Facilities in radius carrying a contaminating classification, before location filtering. |
| `contaminating_use_facility_count_counted_toward_verdict` | number | null | Of those, how many had a reliable location and so counted toward the verdict. |
| `facilities_emitted` | number | null | How many facility rows this property produced after the per-property cap. |
| `results_truncated` | boolean | null | Whether the PER-ASSET maxFacilitiesPerAsset cap cut this property's result set. When true a negative verdict is downgraded to inconclusive. The separate run-level maxResults cap is reported by results\_truncated\_global and never drops an asset\_summary row. Null on a property that was not screened. |
| `max_facilities_per_asset` | number | null | The per-property cap in force for this run. |
| `mailing_address_geocode_facility_count` | number | null | Contaminating facilities excluded from the verdict because the FRS record is filed in a different state than the query point. |
| `coordinate_stack_facility_count` | number | null | Contaminating facilities excluded from the verdict because many facilities share one identical coordinate. |
| `unknown_location_confidence_facility_count` | number | null | Contaminating facilities whose location could not be cross-checked, usually because the geocoder was unavailable. |
| `cross_state_records_mode` | string | null | How out-of-state FRS records were handled on this run: flag, exclude or include. |
| `coordinate_stack_threshold` | number | null | The threshold in force for classifying a shared coordinate as a stack. |
| `land_use_classes_requested` | string | null | Which classes this run screened for, or ALL. |
| `include_secondary_classifications` | boolean | null | Whether SECONDARY and UNKNOWN indicator codes counted as hits on this run. |
| `classification_coverage_note` | string | null | Measured statement of how much of the FRS universe carries an industrial classification at all, and why absence is never reported as an absence of contaminating use. |

##### Provenance

| Field | Type | What it means |
|---|---|---|
| `data_source` | string | null | The upstream datasets behind this row. |
| `source_url` | string | null | EPA Facility Registry Service homepage. |
| `checked_at` | string | null | UTC timestamp of the run that produced this row. |
| `disclaimer` | string | null | Scope statement: this is a screening aid, not a determination that a release has occurred. |

##### Other fields

| Field | Type | What it means |
|---|---|---|
| `asset_screen_status` | string | null | "complete" | "partial" | "not\_screened". Whether this property was fully screened, screened but with some of its facility rows dropped by the run-level maxResults cap, or never screened at all. Every requested asset gets exactly one asset\_summary row, so a property is never silently absent from the output. |
| `not_screened_reason` | string | null | When asset\_screen\_status is "not\_screened", why this property could not be screened (for example an address the US Census geocoder could not resolve). Null on any property that was screened. |
| `facility_rows_dropped_by_global_cap` | number | null | How many of this property's facility rows the run-level maxResults cap dropped. The summary row's counts and verdict are computed over ALL facilities found, not just the rows emitted, so a non-zero value here means supporting detail is missing - never that the verdict is. |
| `results_truncated_global` | boolean | null | Whether the run-level maxResults cap dropped any facility row anywhere in this run. This is a DIFFERENT cap from results\_truncated, which reports the per-asset maxFacilitiesPerAsset cut. The run-level cap never drops an asset\_summary row, so every property still carries its verdict. |
| `assets_requested` | number | null | How many properties this run was asked to screen. Compare with the number of asset\_summary rows in the dataset: they are always equal. |
| `assets_screened_complete` | number | null | How many of the requested properties were screened with every facility row emitted. |
| `assets_screened_partial` | number | null | How many of the requested properties were screened but had facility rows dropped by the run-level maxResults cap. Their verdicts are still complete. |
| `assets_not_reached` | number | null | How many of the requested properties could not be screened at all. Each still appears as an asset\_summary row with astm\_prior\_use\_verdict "not\_screened" and a not\_screened\_reason. |
| `max_results` | number | null | The run-level row cap that was applied. It is a hard cap on rows and therefore a hard cap on the bill. A run whose maxResults is below the number of requested assets fails before emitting anything. |

***

### Use as an MCP tool

This actor is callable by AI agents over Apify's hosted MCP endpoint. Billing is unchanged when it is called as a tool, and a run that cannot answer fails without billing.

**Endpoint:** `https://mcp.apify.com/?actors=malonestar/historic-land-use-sic-contaminant-screener`

Claude Desktop / Claude Code / Cursor config:

```json
{
  "mcpServers": {
    "historic-land-use": {
      "url": "https://mcp.apify.com/?actors=malonestar/historic-land-use-sic-contaminant-screener",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

Worked agent prompt:

> "Screen 1438 Tremont Pl, Denver CO for prior contaminating land uses within a quarter mile. For each hit, tell me the business type, the contaminants of concern, and whether the location is reliable enough to count."

**Chaining.** For a full site workup, combine with the Section 8.2 records review and the physical-setting screens in one MCP session:

`https://mcp.apify.com/?actors=malonestar/historic-land-use-sic-contaminant-screener,malonestar/epa-contaminated-site-screener,malonestar/fws-wetlands-proximity-screener,malonestar/nhd-surface-water-404-screener`

Related actors: [epa-contaminated-site-screener](https://apify.com/malonestar/epa-contaminated-site-screener) (ASTM Section 8.2 records review), [site-due-diligence-bundle](https://apify.com/malonestar/site-due-diligence-bundle) (20-layer one-call site screen), [state-tank-spill-registry-screener](https://apify.com/malonestar/state-tank-spill-registry-screener) (state tank and spill registers), [epa-drinking-water-quality-screener](https://apify.com/malonestar/epa-drinking-water-quality-screener).

***

### Pricing

Pay per result: **$12 per 1,000 rows**, billed on the automatic Result event. One emitted row is one billable result. Graduated discounts apply on paid Apify plans. A failed run emits nothing and bills nothing.

`maxResults` is a hard cap on rows and therefore a hard cap on the bill. `assets` is required, so there is no accidental national run.

Because one `asset_summary` row is reserved per property, the floor on a run is one row per property submitted, and `maxResults` must be at least the number of properties — a run set lower fails before emitting anything rather than dropping properties silently. A property that could not be screened still costs one row, and carries the reason why.

***

### FAQ

**How do I find out if there was a dry cleaner next to my property?**
Screen the coordinate at 0.25 mi. Any facility carrying SIC 7215/7216 or NAICS 81231/81232 is returned with `primary_land_use_class` = `DRY_CLEANING` and PCE/TCE listed in `contaminants_of_concern`.

**Does this cover gas stations and underground tanks?**
It covers gas stations as a **land use** (SIC 5541, NAICS 4471/4571). For tank registrations, releases and LUST cases, use `epa-contaminated-site-screener`, which reads EPA's UST Finder and LUST data directly.

**Is this a historical land-use search?**
It is a systematic first pass over the Section 8.3 question using the classification EPA publishes today, plus each record's operational status and last-reported date. It is not a title-chain, city-directory or aerial-photograph review. See "What historic does and does not mean here".

**Why did a facility come back with no classification?**
EPA publishes SIC or NAICS for only a minority of FRS records. That case returns `classification_available: false` and `contaminating_use_match: null` - it is explicitly *not* evidence that the facility is harmless.

**Why is a facility flagged `state_mismatch`?**
Because EPA filed it under a different state than the one your coordinate falls in, which almost always means the published coordinate is the operator's mailing address rather than the site. It is emitted, flagged, and left out of the verdict.

**Can I screen addresses instead of coordinates?**
Yes - `{"address": "..."}`. Addresses are geocoded with the free US Census geocoder. A coordinate is faster and more precise, and an address that cannot be geocoded fails loudly rather than screening the wrong place.

**What is the data source?**
EPA's Facility Registry Service: the `FRS_INTERESTS` point layer joined to the `FRS_SIC` and `FRS_NAICS` classification tables on `KEY_FIELD`. Keyless and public.

# Actor input Schema

## `assets` (type: `array`):

Locations to screen for contaminating industrial land uses. Each item is EITHER {"lat": 39.7392, "lon": -104.9903, "label": "..."} OR {"address": "1438 Tremont Pl, Denver, CO 80202", "label": "..."}. Addresses are geocoded with the free US Census geocoder; a coordinate is faster and more precise. Required - a run without it is rejected before it starts, so nothing is billed.

## `radiusMiles` (type: `number`):

Distance from each property within which EPA FRS facilities are screened. ASTM E1527-21 Section 8.3 concerns the subject property and adjoining properties, so 0.25 mi is the working default; 1 mi is the maximum and 0.02 mi the minimum.

## `landUseClasses` (type: `array`):

Optional filter. Leave empty (the default behaviour) to screen against every class in the vocabulary. Unknown values are ignored rather than silently dropping every result.

## `programs` (type: `array`):

OPT-IN. Leave empty (the working default) and this actor behaves exactly as before: ASTM E1527-21 Section 8.3 prior uses only. Add "state" to also screen the ASTM Section 8.2 STATE AND TRIBAL EQUIVALENT record class - the ~57 state and tribal agency program systems EPA normalises into the same registry. Coverage is uneven and is measured live every run: every summary row carries state\_coverage (complete / partial / none), the systems actually searched, and the systems EPA publishes for that state. MEASURED 2026-08-20, EPA publishes NO state or tribal agency system at all for AK, CO, DC, MI, SD, VT, WV or the US territories - for those, state\_coverage reads "none" and every state count is null, so a zero can never be mistaken for a searched-and-clear result. Adds 2 requests per state (not per property) and no extra rows.

## `includeSecondaryClassifications` (type: `boolean`):

EPA marks each SIC/NAICS code on a facility PRIMARY, SECONDARY or UNKNOWN. When true (the working default) a secondary contaminating code still counts as a hit and is labelled as secondary on the row. Set false to count only PRIMARY codes.

## `includeUnclassifiedFacilities` (type: `boolean`):

When false (the working default) only facilities carrying a contaminating classification are emitted, plus one summary row per property. When true, every FRS facility in the radius is emitted, including those EPA publishes no SIC/NAICS for. This multiplies the row count and therefore the bill.

## `crossStateRecords` (type: `string`):

EPA geocodes a substantial share of FRS records to the operator's mailing address rather than the operating site - measured 2026-08-18, 90 of 188 records within 402 m of downtown Denver are Wyoming well pads stacked on one Denver office coordinate. "flag" (working default) emits them with location\_confidence=state\_mismatch and excludes them from the verdict; "exclude" drops them; "include" counts them toward the verdict.

## `coordinateStackThreshold` (type: `integer`):

How many distinct facilities sharing one identical coordinate marks that coordinate as an address-level geocode rather than a site-specific location. Stacked facilities are emitted with location\_confidence=coordinate\_stack and are excluded from the verdict.

## `maxFacilitiesPerAsset` (type: `integer`):

Cap on facility rows emitted per property, nearest first. When the cap truncates the result the summary row says so and the verdict cannot read as a clean negative.

## `maxResults` (type: `integer`):

Hard cap on total dataset rows across the whole run, which is also the hard cap on the bill. One row is one billable result.

## `simulateOutage` (type: `string`):

Permanent diagnostic seam for proving the failure paths on demand instead of only during a real outage. "none" is a genuine no-op. The other values force the named source or drift probe to fail so the loud-failure and degraded-disclosure paths can be re-verified.

## Actor input object example

```json
{
  "assets": [
    {
      "lat": 39.7392,
      "lon": -104.9903,
      "label": "Denver CBD parcel (CO)"
    },
    {
      "lat": 40.7274,
      "lon": -74.159,
      "label": "Newark Ironbound parcel (NJ)"
    }
  ],
  "radiusMiles": 0.25,
  "programs": [],
  "includeSecondaryClassifications": true,
  "crossStateRecords": "flag",
  "coordinateStackThreshold": 5,
  "maxFacilitiesPerAsset": 100,
  "maxResults": 1000,
  "simulateOutage": "none"
}
```

# Actor output Schema

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

The default dataset.

# 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 = {
    "assets": [
        {
            "lat": 39.7392,
            "lon": -104.9903,
            "label": "Denver CBD parcel (CO)"
        },
        {
            "lat": 40.7274,
            "lon": -74.159,
            "label": "Newark Ironbound parcel (NJ)"
        }
    ],
    "radiusMiles": 0.25,
    "programs": [],
    "includeSecondaryClassifications": true,
    "includeUnclassifiedFacilities": false,
    "crossStateRecords": "flag",
    "coordinateStackThreshold": 5,
    "maxFacilitiesPerAsset": 100,
    "maxResults": 1000,
    "simulateOutage": "none"
};

// Run the Actor and wait for it to finish
const run = await client.actor("malonestar/historic-land-use-sic-contaminant-screener").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 = {
    "assets": [
        {
            "lat": 39.7392,
            "lon": -104.9903,
            "label": "Denver CBD parcel (CO)",
        },
        {
            "lat": 40.7274,
            "lon": -74.159,
            "label": "Newark Ironbound parcel (NJ)",
        },
    ],
    "radiusMiles": 0.25,
    "programs": [],
    "includeSecondaryClassifications": True,
    "includeUnclassifiedFacilities": False,
    "crossStateRecords": "flag",
    "coordinateStackThreshold": 5,
    "maxFacilitiesPerAsset": 100,
    "maxResults": 1000,
    "simulateOutage": "none",
}

# Run the Actor and wait for it to finish
run = client.actor("malonestar/historic-land-use-sic-contaminant-screener").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 '{
  "assets": [
    {
      "lat": 39.7392,
      "lon": -104.9903,
      "label": "Denver CBD parcel (CO)"
    },
    {
      "lat": 40.7274,
      "lon": -74.159,
      "label": "Newark Ironbound parcel (NJ)"
    }
  ],
  "radiusMiles": 0.25,
  "programs": [],
  "includeSecondaryClassifications": true,
  "includeUnclassifiedFacilities": false,
  "crossStateRecords": "flag",
  "coordinateStackThreshold": 5,
  "maxFacilitiesPerAsset": 100,
  "maxResults": 1000,
  "simulateOutage": "none"
}' |
apify call malonestar/historic-land-use-sic-contaminant-screener --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,malonestar/historic-land-use-sic-contaminant-screener"
        }
    }
}

```

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/8epmaqvIl3F0Qpelq/builds/ENIbiIkT81yYZnls8/openapi.json
