EPA AirToxScreen Cancer Risk Screener - Census Tract Air Toxics avatar

EPA AirToxScreen Cancer Risk Screener - Census Tract Air Toxics

Pricing

from $4.40 / 1,000 screened sites

Go to Apify Store
EPA AirToxScreen Cancer Risk Screener - Census Tract Air Toxics

EPA AirToxScreen Cancer Risk Screener - Census Tract Air Toxics

EPA AirToxScreen 2019 census-tract cancer-risk API: total risk per million, top contributing pollutants, point/on-road/non-road/non-point source attribution, non-cancer hazard index, and a live national percentile. For Phase I due diligence and environmental-justice screening.

Pricing

from $4.40 / 1,000 screened sites

Rating

0.0

(0)

Developer

Kyle Maloney

Kyle Maloney

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 days ago

Last modified

Share

EPA AirToxScreen Cancer Risk Screener — Census Tract Air Toxics

EPA AirToxScreen 2019 census-tract air-toxics cancer-risk screener. Give it a list of coordinates and it runs a server-side point-in-polygon lookup against EPA's national AirToxScreen 2019 tract-level modeled cancer-risk layer and returns, for each point: the total estimated lifetime cancer risk per million people, the top contributing pollutants ranked from EPA's own per-pollutant risk fields, a source-group breakdown (stationary point sources, on-road and non-road mobile, non-point, fire, biogenics, secondary formation, background), the non-cancer hazard index by target organ, and a live national percentile computed against all 73,445 risk-rated census tracts.

One clean, billable row per asset — including for a point outside any 2010 census tract (out_of_coverage) and for a tract EPA genuinely publishes no risk total for (matched_no_risk_data), both of which are valid, useful, non-fabricated answers.

This is a screening tool, not a personal health-risk or regulatory determination. AirToxScreen models ambient air-toxics concentrations at the census-tract level from EPA's National Emissions Inventory — it does not measure any individual's actual exposure. Consult EPA's own AirToxScreen documentation and a qualified environmental professional before using this for a health, legal or real-estate decision.


Two vintages, and both matter

AirToxScreen risk is EPA's 2019 modeling cycle (assessment_vintage: 2019), reported against 2010 census tract boundaries (tract_geography_vintage: 2010, an 11-digit GEOID). Both are published on every row, matched or not, because they are properties of the underlying EPA service, not of any one lookup. If you join tract_geoid against a 2020-vintage tract layer (ACS 2020+, this portfolio's own fema-nri-county-risk-profile tract mode, etc.), the boundaries do not line up 1:1 — some 2010 tracts were split, merged or renumbered in 2020. Re-derive the join key from a crosswalk rather than assuming GEOID equality across vintages. The 2020 AirToxScreen cycle does not exist as a service — EPA's NATA20AC_CRP_CRSG layer answers an ArcGIS "Invalid URL" error (live-verified 2026-08-11) — so 2019 is the only year this actor, or any keyless AirToxScreen consumer, can serve today.

Who it's for

  • Phase I / Phase II environmental due-diligence consultants — add an authoritative EPA air-toxics cancer-risk data point to a site assessment, with pollutant- and source-level attribution, not just a single number.
  • Environmental-justice (EJ) screening teams — a national percentile lets you flag disproportionately high-risk tracts without hosting or joining EPA's own EJScreen infrastructure.
  • Industrial and facility siting teams — see whether a candidate site sits in an elevated-risk tract and why (traffic vs. industry vs. background) before committing.
  • Real-estate and relocation research — screen a shortlist of addresses for a nationally comparable, EPA-published risk figure.
  • GIS & data teams / AI agents — enrich any coordinate list with EPA AirToxScreen risk without hosting the 318-field national layer yourself.

Example input

{
"assets": [
{ "lat": 29.7355, "lon": -95.2400, "label": "Houston Ship Channel / Manchester, TX" },
{ "lat": 34.0339, "lon": -118.2076, "label": "Boyle Heights, Los Angeles, CA" },
{ "lat": 39.7392, "lon": -104.9903, "label": "Denver, CO" },
{ "lat": 39.3000, "lon": -101.0000, "label": "Rural Thomas County, KS" }
],
"topPollutantsCount": 5
}
Sitematch_statustotal_cancer_risk_per_millionpercentile_context.percentile_upper_boundTop pollutant
Houston Ship Channel, TXmatched4099.1Formaldehyde (17.41)
Boyle Heights, Los Angeles, CAmatched4099.1Formaldehyde
Denver, COmatched30~90
Rural Thomas County, KSmatched10~30

All four values above are live-measured (2026-08-11), not illustrative.


Input options

FieldTypeDefaultMeaning
assetsarrayrequired[{ lat, lon, label }] in WGS84 decimal degrees. One billable row per asset.
includeAllPollutantsbooleanfalseWhen true, also emit cancer_risk_by_pollutant_full (all 72 named cancer-risk pollutants) and ambient_concentrations_ug_m3 (all 177 EPA-modeled ambient concentrations) on every matched row, instead of just the top-ranked ones.
topPollutantsCountinteger10How many top cancer-risk pollutants to rank per tract (max 72, the full named list).
maxAssetsinteger200Safety cap, max 2000.

Output fields — one row per asset

Identity & vintage

FieldTypeDescription
asset_labelstringYour label, or asset_N if omitted.
asset_lat / asset_lonnumberScreened coordinate (WGS84).
assessment_vintageintegerAlways 2019 — the AirToxScreen modeling cycle.
tract_geography_vintageintegerAlways 2010 — the census tract boundary vintage the risk is reported against.
match_statusstringmatched · matched_no_risk_data · out_of_coverage · invalid_input · source_unavailable. See below.
lookup_errorstringDetail for invalid_input / source_unavailable; null otherwise.
tract_geoidstring11-digit 2010 census tract FIPS.
state / county / stcofips / epa_regionstringMatched tract identity. epa_region is null on matched_no_risk_data rows — EPA leaves it null there too.
population_2010integer2010 census population of the tract.
area_sq_milesnumberTract area, converted from EPA's published square-meter field.
checked_atstringUTC timestamp of the run.
source_urlstringThe EPA AirToxScreen FeatureServer layer used.
disclaimerstringInformational-use disclaimer.

match_status — what each value means and does not mean

ValueMeaningRisk fields
matchedA 2010 tract was found and EPA published a real cancer-risk total for it.Populated.
matched_no_risk_dataA 2010 tract was found, but EPA publishes no risk total for it — measured 2026-08-11: 266 of 73,711 tracts (0.36%), almost all unpopulated land or open water (POP2010: 0 on the fixture tract). Never reported as a risk of 0 — 0 is a real, different, achievable value on this layer (national minimum, measured 5) and must not be confused with "not modeled".null.
out_of_coverageThe point does not fall inside any 2010 census tract in this layer (e.g. open ocean, outside the 50 states + DC + territories the layer covers). A valid, useful, non-error answer.null.
invalid_inputThe supplied lat/lon was unusable.null.
source_unavailableThe FeatureServer did not answer after retries, or matched an anomalous >1 tracts (structurally impossible for non-overlapping census tracts — reported rather than silently guessed).null.

Headline risk

FieldTypeDescription
total_cancer_risk_per_millionnumberEPA's published Total_Cancer_Risk — estimated lifetime cancer cases per million people from modeled ambient air toxics. The headline number.
total_cancer_risk_per_million_legacy_fieldnumberEPA's separate CR_Total_Risk field. Live-verified identical to the field above on all 73,711 tracts (2026-08-11); a live drift check fails the run if EPA ever lets the two diverge.
percentile_contextobject{tracts_evaluated, tracts_ranked_lower, tracts_ranked_lower_or_tied, percentile_lower_bound, percentile_upper_bound, note} — where this tract ranks nationally, computed live from a once-per-run histogram of all 73,445 risk-rated tracts. Two bounds, not one number: EPA's published total is a rounded integer with only 18 distinct values nationally, so many tracts tie exactly at the same published risk — a single percentile would fabricate precision the data does not support. null unless match_status is matched.
top_pollutantsarrayTop topPollutantsCount named cancer-risk pollutants, each {pollutant, cancer_risk_per_million, percent_of_published_total}. percent_of_published_total divides by total_cancer_risk_per_million (what you actually see), not an internally recomputed sum — see source_groups.source_group_sum_per_million for why those two totals are not identical.
risk_change_flag / risk_change_flag_recognizedstring / booleanEPA's raw Risk_Change code, passed through verbatim (observed live: E on 0.12% of tracts, N on the rest; EPA's own documentation of the exact meaning was not located, so it is not decoded further). recognized: false flags a code outside those two.
popup_notestringEPA's own free-text note for the tract, when published (rare).

Source-group attribution

FieldTypeDescription
source_groups.point_stationary_per_millionnumberMajor stationary point sources.
source_groups.onroad_mobile_per_million (+ onroad_mobile_detail)number / objectOn-road vehicles; detail splits by light/heavy duty, gas/diesel, on/off network, refueling, hoteling (10 subcategories).
source_groups.nonroad_mobile_per_million (+ nonroad_mobile_detail)number / objectNon-road mobile sources; detail covers construction, agriculture, lawn/garden, marine (CMV), rail, aviation, and more (13 subcategories).
source_groups.nonpoint_per_million (+ nonpoint_detail)number / objectDiffuse stationary sources; detail covers industrial, commercial cooking, oil & gas, solvents/coatings, residential wood combustion, waste disposal, and more (10 subcategories).
source_groups.fire_per_million / biogenics_per_million / secondary_formation_per_million / background_per_millionnumberWildfire/prescribed burn, natural biogenic emissions, secondarily-formed pollutants, and national background, respectively.
source_groups.source_group_sum_per_millionnumberInformational, unrounded sum of the 8 components above. Live-verified (Harris County TX 48201233702): this sum is 41.4569, while EPA's own published total_cancer_risk_per_million is 40 — EPA's AirToxScreen tool rounds internally before publishing the total, and this actor reports both numbers rather than "correcting" one to match the other.

Non-cancer hazard index

FieldTypeDescription
noncancer_hazard_indexobjectEPA's 14 target-organ chronic hazard index values (respiratory, neurological, liver, developmental, reproductive, kidney, ocular, endocrine, hematological, immunological, skeletal, spleen, thyroid, whole_body). A value above 1 indicates modeled exposure at or above a level of concern for that organ system. Already fetched alongside cancer risk on every query — emitted, not discarded.

Full pollutant vectors (only when includeAllPollutants: true)

FieldTypeDescription
cancer_risk_by_pollutant_fullobjectAll 72 named EPA cancer-risk pollutants (per million), keyed by pollutant name. Superset of top_pollutants.
ambient_concentrations_ug_m3objectAll 177 EPA-modeled ambient air-toxics concentrations (µg/m³), keyed by field name with the AC_ prefix stripped.

Live drift protection

Every run checks the EPA FeatureServer before producing a single row: layer identity and name, the field set this actor depends on (an unknown outFields name 400s on this specific service rather than silently returning zero features — verified live and checked anyway, against the layer's own metadata), a tract-count band (measured 73,711), agreement between EPA's two published "total" fields, a positive canary (a known, stable, elevated-risk Houston tract), a negative control (mid-Pacific Ocean must match nothing), the integrity of the once-per-run national percentile histogram, and a projection/coordinate-magnitude check. If any check fails, the run fails and nothing is billed — no confident wrong answer is ever produced from a degraded upstream.

Use as an MCP tool

This actor is callable directly by AI agents (Claude, Cursor, etc.) via Apify's MCP endpoint at mcp.apify.com, using your Apify API token. Example client config for Claude Desktop / Claude Code:

{
"mcpServers": {
"apify-airtoxscreen": {
"command": "npx",
"args": ["-y", "@apify/actors-mcp-server", "--actors", "malonestar/epa-airtoxscreen-cancer-risk-screener"],
"env": { "APIFY_TOKEN": "<your Apify API token>" }
}
}
}

Worked prompt: "Screen 40.7128,-74.0060 and 29.7355,-95.2400 for EPA AirToxScreen cancer risk and tell me the top contributing pollutant at each." Billing when called as a tool is identical to a normal run — one Result event per asset row — and a run that cannot answer fails without billing, same as any other caller.

FAQ

Is this the same as EPA's EJScreen tool? No. EJScreen bundles many environmental and demographic indicators; this actor is EPA's underlying AirToxScreen cancer-risk layer specifically, with full pollutant- and source-level detail EJScreen's own UI does not expose per-tract.

Why is total_cancer_risk_per_million sometimes null even though the tract matched? EPA genuinely does not publish a risk total for about 0.36% of census tracts — almost always unpopulated land or open water. match_status reports this as matched_no_risk_data, distinct from a real low score.

Can I get a single precise percentile? No, deliberately. EPA's published total is a rounded integer with only 18 distinct values nationally, so many tracts share the exact same published risk. percentile_context reports a lower and upper bound instead of a single number that would fabricate precision the data does not have.

Does this work outside the United States? No — AirToxScreen covers the 50 states, DC and US territories on 2010 census tract geography. Points elsewhere return out_of_coverage.

Pricing

$8 per 1,000 Result events (one event per screened asset row), with the standard graduated volume discounts.