# US EPA FRS Risk Matcher: Registry Matching & Review (`afkdigital/newapi10-epa-facility-risk-matcher`) Actor

Find public EPA facility registry records by state, ZIP, NAICS or program. Compare facility names and addresses with explainable evidence for review prioritization. FRS registration does not establish noncompliance or environmental risk.

- **URL**: https://apify.com/afkdigital/newapi10-epa-facility-risk-matcher.md
- **Developed by:** [AFK Digital](https://apify.com/afkdigital) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$6.00 / 1,000 unique facility records

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

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

## US EPA Facility Registry & Commercial Environmental Risk Matcher

**Registry matching and review prioritization using public EPA facility records.**

Find U.S. facilities in the Environmental Protection Agency's Facility Registry Service (FRS), organize their recorded NAICS codes and program associations, and optionally compare a facility name and address with the registry.

“Risk matcher” describes **record matching and the prioritization of records for further review**. It does not mean an environmental-risk score, a violation detector, a compliance certification, or a determination of liability. An FRS record or program association alone does not establish a violation.

### What you receive

- One Dataset item per unique FRS registry ID, with facility name, address, industry codes, program associations and available coordinates.
- A direct EPA source URL and observation timestamp for each record.
- Explainable match status, heuristic confidence and field-level evidence when you supply a name or address.
- A free run summary stating why processing stopped and whether the queried source was exhausted.
- JSON and CSV exports through Apify Dataset.

This release **does not retrieve separate compliance findings**. `compliance_status` and `compliance_status_url` remain null. Missing coordinates remain null and are not converted to 0,0.

### Quick start

The small default query is Colorado ZIP 80002, at most five unique facilities and a $0.03 facility-charge cap.

```json
{
  "state": "CO",
  "zip": "80002",
  "maxResults": 5,
  "maxCostUsd": 0.03
}
```

To compare a known facility against EPA records:

```json
{
  "state": "VA",
  "zip": "23234",
  "facilityName": "J W FERGUSSON & SONS, LLC",
  "streetAddress": "4107 CASTLEWOOD ROAD",
  "maxResults": 1,
  "maxCostUsd": 0.006
}
```

### Inputs

| Field | Meaning |
|---|---|
| `state` | Two-letter U.S. state or territory abbreviation. |
| `zip` | Five-digit ZIP or ZIP+4, supplied as text. A five-digit query includes ZIP+4 records. |
| `naicsCode` | Two to six digits. A prefix matches any associated NAICS code beginning with those digits. |
| `epaProgram` | An FRS program acronym. Program associations are registry facts, not noncompliance findings. |
| `facilityName` | Optional identity comparison. Matching results require review as described below. |
| `streetAddress` | Optional address comparison, including building and unit number when available. |
| `maxResults` | 1–1,000 unique delivered facilities; default 5. |
| `maxCostUsd` | Maximum facility charges in USD; default 0.03. The lower Apify run spending limit also applies. |

Multiple supplied filters are combined. Industry or program filters identify candidate facilities, while enrichment preserves the associated values retrieved for each facility. State and ZIP filter the public master query. NAICS and program filters are checked after complete program/industry enrichment, independently at the facility level. Narrow geographic filters reduce requests and processing time. If all filters are omitted, the safe default geography is used.

### Output fields

| Field | Interpretation |
|---|---|
| `registry_id` | EPA's 12-digit registry identifier, preserved as a string. |
| `facility_name` | Recorded primary facility name. |
| `street_address`, `city`, `state`, `zip` | Recorded facility location. ZIP remains text to preserve leading zeros. |
| `naics_codes` | Deduplicated recorded NAICS codes; an empty array means none were returned. |
| `epa_programs` | Distinct FRS program acronyms returned for this facility. |
| `epa_program_details` | Program acronyms with their source program identifiers. |
| `latitude`, `longitude` | Available EPA coordinates, or null when absent/invalid. |
| `source_url` | Public EPA source query for the facility. |
| `observed_at` | UTC retrieval timestamp; not a certification that the underlying record was updated on that date. |
| `match_status` | `not_requested`, `exact_match`, `probable_match` or `possible_match` for delivered records. |
| `match_confidence` | 0–1 heuristic similarity score, or null; not a statistically calibrated probability. |
| `match_evidence` | Query/source values, normalization comparisons, agreements and reasons for review. |
| `compliance_status`, `compliance_status_url` | Null in this release; compliance is not assessed. |

JSON preserves arrays and nested evidence. CSV uses Apify's standard serialization of those values; it does not create multiple billed records for a facility's multiple programs.

### How matching works

Name comparisons normalize punctuation, spacing, “&” and common legal suffixes. Address comparisons normalize common street abbreviations while retaining street and unit numbers. A conflicting known street or unit number is not accepted as a match.

An `exact_match` requires both an exactly normalized name and address. Strong address agreement with a similar name can produce a `probable_match`. A name-only or address-only comparison produces at most a `possible_match`; an address may be shared by several facilities.

When matching is requested, candidates classified as `not_matched` are omitted from the billed Dataset. If the scoped search finishes without a match, the free `SUMMARY` record reports `unmatched`. This means no accepted match was found in the queried scope; it does not prove the facility is absent from every source.

### Pricing and spending limits

**$0.006 per unique delivered facility — $6 per 1,000 facilities.** Failed requests, duplicate registry IDs and summary/diagnostic records are not additional facility events. The release uses one per-Dataset-item billing event, with no separate startup event or additional platform-usage charge for ordinary runs.

The Actor checks `maxResults`, the input cost cap and the platform's run spending limit before output. It uses whole-record capacity: a $0.013 cap permits at most two $0.006 records. The run summary's charge estimate is the record-price calculation; Apify's billing/run details are the authoritative charge record.

### Reliability and continuation

EPA requests use 1-based inclusive pages sorted by registry ID, a 25-second request timeout, a maximum of two retries, at least 500 ms between requests, and a 250-request run ceiling. A run has a four-minute processing allowance and a 10,000-candidate safeguard. HTTP 429 responses respect Retry-After; a delay beyond the run allowance stops processing rather than retrying early. Persistent errors fail visibly while retaining progress. If EPA returns a row outside the requested state or ZIP5 scope, the Actor fails before enrichment instead of silently expanding the search.

Progress includes the pending page and candidate position. On resurrection, the Actor reads existing Dataset registry IDs before continuing, preventing a record accepted before an interrupted response from being blindly written again. Durable input signatures prevent resuming with different filters into the same Dataset. Start a new run to change filters.

A complete unlimited national export is outside this Actor's run scope. The Actor stops at the result/budget limit; source failures or a runtime/candidate safeguard report incomplete processing. The summary separately states whether the queried source was exhausted.

### Data sources and terms

- [EPA Envirofacts Data Service API](https://www.epa.gov/enviro/envirofacts-data-service-api)
- [EPA FRS public API](https://www.epa.gov/frs/frs-api)
- [EPA FRS dataset catalog and license](https://catalog.data.gov/dataset/facility-registry-service-frs)
- [EPA Standard Open Data License](https://edg.epa.gov/EPA_Data_License.htm)
- [EPA's distinction between public and intergovernmental FRS APIs](https://www.epa.gov/frs/intergovernmental-frs-api)

The FRS catalog marks the dataset public and links EPA's public-domain data license. Use is subject to the applicable metadata and EPA's accuracy/utility limitations. This Actor uses public query data and does not submit data to EPA or access NAAS-protected intergovernmental records.

FRS integrates records from multiple programs and can contain incomplete, inconsistent, historical or periodically refreshed information. A program association may refer to a historical interest. Source absence is not evidence of compliance. This independent product is not endorsed by the U.S. EPA.

### Verified examples

Live EPA validation on 19 October 2026 covered Colorado and Virginia. The five-record Colorado default completed in 14.6 seconds on the development server. Virginia registry `110000869588` matched the normalized facility name and street address with an `exact_match` and a 0.99 heuristic score. Colorado registry `110002993226` was retained with both coordinates null. A nonexistent supplied identity was compared with all 404 records in Colorado ZIP 80002 and produced an empty Dataset and an `unmatched` summary. The Apify default run also completed in about 5.5 seconds. A forced cloud timeout after 23 delivered records was resumed to 40 unique records and exactly 40 billed Dataset events, without duplicate output. These timings are observations, not service guarantees.

### Version and support

Version: **1.0.0**. Project code: **NEWAPI10**. Report issues with the run ID, nonsecret input and an example registry ID. Never send access tokens in issue reports.

# Actor input Schema

## `state` (type: `string`):

Two-letter abbreviation. Leave empty to use another geographic, industry or program filter.

## `zip` (type: `string`):

Five digits or ZIP+4. Leading zeros are preserved. A five-digit query includes ZIP+4 records.

## `naicsCode` (type: `string`):

Enter 2–6 digits. Matches any recorded NAICS code beginning with this value.

## `epaProgram` (type: `string`):

Exact FRS acronym, such as RCRAINFO, TRIS, NPDES or SEMS. Program registration is not a violation finding.

## `facilityName` (type: `string`):

Compare this name with candidate registry records. Only exact, probable or possible matches are delivered; an unmatched summary is free.

## `streetAddress` (type: `string`):

Include building and unit number when known. Address-only matches require review because facilities may share an address.

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

Maximum delivered records, after registry ID deduplication.

## `maxCostUsd` (type: `number`):

Stops output before exceeding this amount at $0.006 per unique facility. The lower Apify run spending limit also applies.

## Actor input object example

```json
{
  "state": "CO",
  "zip": "80002",
  "maxResults": 5,
  "maxCostUsd": 0.03
}
```

# Actor output Schema

## `facilities` (type: `string`):

No description

## `csv` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "state": "CO",
    "zip": "80002",
    "maxResults": 5,
    "maxCostUsd": 0.03
};

// Run the Actor and wait for it to finish
const run = await client.actor("afkdigital/newapi10-epa-facility-risk-matcher").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 = {
    "state": "CO",
    "zip": "80002",
    "maxResults": 5,
    "maxCostUsd": 0.03,
}

# Run the Actor and wait for it to finish
run = client.actor("afkdigital/newapi10-epa-facility-risk-matcher").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 '{
  "state": "CO",
  "zip": "80002",
  "maxResults": 5,
  "maxCostUsd": 0.03
}' |
apify call afkdigital/newapi10-epa-facility-risk-matcher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,afkdigital/newapi10-epa-facility-risk-matcher"
        }
    }
}
```

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/LmvPcVIuWkTGOTBVt/builds/pODAxPmeqcAF0eJiJ/openapi.json
