# EPA Brownfield-to-Solar Site Finder - RE-Powering Mapper (`malonestar/epa-repowering-brownfield-to-solar-site-finder`) Actor

Find EPA RE-Powering pre-screened contaminated land, landfills and abandoned mine sites with renewable-energy redevelopment potential. Filter 190,976 sites by state, technology, acreage, solar and wind resource and 2022 interconnection context, ranked as development candidates.

- **URL**: https://apify.com/malonestar/epa-repowering-brownfield-to-solar-site-finder.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 $5.50 / 1,000 re-powering candidate sites

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

## EPA Brownfield-to-Solar Site Finder — RE-Powering Mapper

**Find contaminated land, closed landfills and abandoned mine sites that EPA has already pre-screened as renewable-energy redevelopment candidates.** Screen a state, county or city against all **190,976 sites** in EPA's RE-Powering America's Land Mapper, filter by technology, acreage, solar and wind resource and grid context, and get back a ranked list of development candidates with every EPA caveat stated on the row.

This is a **finder**, not a screener. You give it a region and criteria; it tells you which sites qualify. That is a different question from "what is at my coordinates", which is what the site-screening actors in this portfolio answer.

***

### Who it is for

- **Brownfield-to-solar and landfill-solar developers** doing origination: which closed landfills in Pennsylvania are over 20 acres, near transmission, with decent irradiance?
- **Renewable site-selection and land-acquisition teams** building a pipeline of pre-vetted parcels in a target market.
- **Abandoned mine land redevelopment specialists** working AML and coal-community reuse programmes.
- **Project-finance and diligence analysts** who need to know what a site's contamination programme actually is before underwriting it.
- **AI agents** doing grounded siting research — this returns a record class no language model holds.

### What makes it different

EPA published this screening layer and nobody has transformed it. The moat is not the fetch; it is the **honest labelling**. EPA's RE-Powering data contains at least six traps that turn into confident wrong answers if you read the columns literally, and every one of them is measured, flagged and disclosed on the row. See "What EPA's data actually says" below.

***

### Example input

```json
{
  "states": ["PA"],
  "landfillOnly": true,
  "minAcreage": 20,
  "maxTransmissionDistanceMiles": 2,
  "sortBy": "score_desc",
  "maxResults": 200
}
```

Or, for a broad regional sweep:

```json
{
  "states": ["CO"],
  "technologies": ["utility_solar"],
  "minAcreage": 20,
  "sortBy": "score_desc",
  "maxResults": 300
}
```

***

### ⚠ What EPA's RE-Powering data actually says — and the six traps

**EPA RE-Powering is a DESKTOP PRE-SCREEN.** It is not an entitlement, not a feasibility study, not a site-control position, and not a determination that a project can be built or interconnected. Every row carries `epa_screening_only: true`, `is_entitlement: false` and a full-text `screening_disclaimer`. Cleanup status, ownership, zoning, offtake and interconnection all have to be confirmed independently.

Everything below was measured live against EPA's service on 2026-08-18.

**1. `Acreage = 0` is a null sentinel, not zero acres.** 108,888 of 190,976 sites (57.0%) read 0, and 108,886 of them also carry EPA's own "No Acreage PV" flag — EPA could not size an array *because* acreage was unknown. `Acreage IS NULL` returns zero rows, so 0 is the only way this layer expresses "unknown". Reading it as zero acres would rank a viable mine site as unbuildable. This actor publishes `acreage_acres: null` plus `acreage_raw_value` and `acreage_is_null_sentinel` so nothing is hidden.

**2. PV capacity sits on a 600 MW PLATEAU — but 600 MW is not a ceiling, and 16 sites exceed it.** `EstPVCap` reads **exactly 600 MW on 362 sites whose acreage spans 4,144 to 2,669,225 acres** — a 644x range of site sizes mapped to one identical number. Fort Carson at 137,400 acres and a 4,144-acre site both read "600 MW". But **16 sites publish MORE than 600 MW, up to 11,788.08 MW** (Hudson River PCB Sediments, NY, at 81,337.78 acres), so **never filter on `est_pv_capacity_mw <= 600`** — that would silently drop the largest solar-redevelopment candidates in the layer, which is exactly what this actor exists to find. Of the 375 sites over 4,200 acres with a published capacity, 359 read exactly 600, 16 read above it, and none read below.

`EstWindCap` **is** a genuine ceiling by contrast: 1,600 MW is never exceeded anywhere in the layer, and 49 sites sit exactly on it.

Underneath the plateau, capacity is simply acreage times a single **national** constant — measured at ~0.1449 MW/acre (1 MW per 6.9 acres) in every state checked, including CO, TX, CA, AZ, NY, VA and MA. (The 0.10–0.25 MW/acre spread you see in `pv_density_mw_per_acre_derived` on small sites is EPA publication rounding, not regional variation: restrict to sites of 100 acres or more and it collapses to 0.14489–0.14496.) So EPA's capacity figures carry **no site-specific engineering information**. This actor flags them with `est_pv_capacity_is_capped` (true at or above the 600 MW plateau) / `est_wind_capacity_is_capped`, publishes the derived `pv_density_mw_per_acre_derived` so you can see the constant for yourself, and **excludes EPA capacity from the ranking score entirely**. All three figures — the at-plateau count, the above-plateau count and the observed maximum — are re-asserted against the live layer by the `pv_plateau_integrity` drift probe on every run, so this paragraph cannot go stale without the run failing.

**3. EPA's summary technology columns are constants.** `Solar = 'Y'` on **all 190,976 sites** and `Solar IS NULL` matches nothing; `GeoHeatPmp = 'Y'` on 190,956 of 190,976 (99.99%). An actor that offered "filter for solar-viable sites" and filtered on EPA's `Solar` column would return the entire national inventory while appearing to have filtered. The real discriminators are the **scale-specific** columns — utility-scale PV 17,649 sites, distributed 64,268, off-grid 82,090, utility-scale wind just 601 — and that is what this actor filters on.

**4. The single-space `" "` sentinel is the null on every flag column.** `Landfill IS NULL` returns 0 rows while `Landfill = ' '` returns 172,678. EPA's own RE-Powering Site Profile page renders that sentinel as `-`. Site names, addresses, cities and ZIPs use it too: **1,675 sites publish no name at all**, 22,261 no address, 19,675 no city, 61,533 no ZIP. And EPA publishes **no explicit negative value anywhere in the layer** — so `false` on any flag here means "EPA did not flag this", which is weaker than "EPA determined this is not the case". Every flag ships as both a boolean and a verbatim `_raw` column, with `flag_semantics_note` on the row.

**5. The grid fields are a FROZEN 2022 PRECOMPUTATION and are internally inconsistent.** Substation distance, substation voltage, transmission distance, transmission kV and transmission status are baked into the layer, not measured live. **16,803 sites report the nearest line status as `NOT AVAILABLE` while also publishing a voltage** — a contradiction on the face of the record. Every one of those fields is named `*_2022_screening_estimate`, `interconnection_data_is_live` is always `false`, and the contradiction is surfaced on `transmission_status_contradicts_voltage`. **For a live measurement, run [hifld-grid-proximity-screener](https://apify.com/malonestar/hifld-grid-proximity-screener) on the coordinates in the row.** That is the intended workflow: this actor finds the candidate, that one verifies the interconnection.

**6. Some acreage values are not the site footprint.** The largest is 2,669,225 acres — 4,170 square miles for a single "site" — and an urban Denver brownfield is published at 43,000 acres, 67 square miles inside the city. The value is published as EPA wrote it, with `acreage_implausible: true` attached, because which figure EPA intended is unknowable from the data.

***

### How this actor protects you

- **A live drift gate runs before a single billable row.** Six probes: a national row-count floor, a positive canary (a known site must still carry its recorded values), a sentinel-integrity check (EPA's null convention must not have changed), a negative control (a bogus state must return 0), a **strictly-less-than** check (a filtered count must be genuinely smaller than the unfiltered total, so an ignored filter cannot return a national answer under a regional label), and a **documentation** check — the EstPVCap distribution this actor describes in prose on every row (362 at the 600 MW plateau, 16 above it, maximum 11,788.08 MW) is re-measured against the layer, so a stale factual claim fails the run rather than being quietly published.
- **Each probe has its own error boundary and a three-valued outcome** — `pass`, `fail`, or `unavailable`. A probe that could not *complete* is not a probe that *failed*. If a load-bearing probe is unavailable the run fails and bills nothing; if only a corroborating probe is unavailable the run proceeds and says so on every row (`drift_gate_status: verified_degraded`).
- **No silent zero.** `states` is required, so a bare `{}` call gets an HTTP 400 before the run starts and can never bill for a 190,976-site national sweep. An upstream outage fails loudly rather than returning an empty dataset. Zero rows only ever means EPA genuinely holds no matching site.
- **A capped answer can never look complete.** Every row carries `matched_sites_total` (read from EPA's free exact count endpoint before any row is fetched) and `results_truncated`.
- **`null` means not checked; `false` means checked and negative.** Nothing is coerced. There is no `Number(x) || 0` anywhere in this actor.

***

### Related actors — the brownfield-to-solar workflow

| Step | Actor | What it adds |
|---|---|---|
| 1. Find candidates | **this actor** | EPA's 190,976 pre-screened contaminated / landfill / mine sites |
| 2. Verify the grid | [hifld-grid-proximity-screener](https://apify.com/malonestar/hifld-grid-proximity-screener) | Live transmission line and substation distance, voltage, utility, ISO/RTO |
| 3. Check the IRA bonus | [ira-energy-community-bonus-screener](https://apify.com/malonestar/ira-energy-community-bonus-screener) | 10% ITC/PTC energy-community adder eligibility for the coordinates |
| 4. Model the yield | [nrel-pvwatts-solar-resource-scorer](https://apify.com/malonestar/nrel-pvwatts-solar-resource-scorer) | NREL PVWatts production estimate at the site |
| 5. Read the contamination | [epa-contaminated-site-screener](https://apify.com/malonestar/epa-contaminated-site-screener) | Phase I ESA record search — SEMS, RCRA, ECHO, brownfields findings |
| 6. Check the queue | [interconnection-queue-tracker](https://apify.com/malonestar/interconnection-queue-tracker) | Live ISO/RTO interconnection queue positions nearby |
| Public land alternative | [blm-solar-siting-area-screener](https://apify.com/malonestar/blm-solar-siting-area-screener) | BLM Western Solar Plan designated leasing areas |
| Soil and terrain | [ssurgo-soil-suitability-screener](https://apify.com/malonestar/ssurgo-soil-suitability-screener) | NRCS ground-mounted solar array soil interpretations |

***

### Use as an MCP tool

This actor is callable by AI agents through Apify's hosted MCP server. 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/epa-repowering-brownfield-to-solar-site-finder`

**Claude Desktop / Claude Code / Cursor config:**

```json
{
  "mcpServers": {
    "epa-repowering": {
      "url": "https://mcp.apify.com/?actors=malonestar/epa-repowering-brownfield-to-solar-site-finder",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

**Worked agent prompt:** *"Find closed landfills in Pennsylvania over 20 acres that EPA has screened for utility-scale solar and that sit within 2 miles of transmission. Rank them, and tell me which capacity estimates sit on EPA 600 MW plateau rather than being real site-specific estimates."*

**Chain several tools in one connection:**

```
https://mcp.apify.com/?actors=malonestar/epa-repowering-brownfield-to-solar-site-finder,malonestar/hifld-grid-proximity-screener,malonestar/ira-energy-community-bonus-screener
```

***

### Pricing

**$10 per 1,000 results**, billed as the standard Apify Result event — one row, one result. Graduated discounts apply on paid plans. A run that fails emits nothing and bills nothing.

`states` is required and capped at 6 per run, and `maxResults` defaults to 500 with a hard ceiling of 5,000, so there is no way to accidentally trigger a large national bill.

***

### Output fields

Every field this actor can emit is listed below. `null` always means "not checked or not published by EPA", never "zero" and never "no".

#### Site identity

| Field | Type | What it means |
|---|---|---|
| `site_ref` | number | EPA's RE-Powering cross-reference number (the Ref column). Stable identifier for the site inside the RE-Powering Mapper and the key used in the site profile URL. |
| `site_id` | string | The identifier assigned by the originating cleanup program, for example an EPA RCRA handler ID or a state program number. Not unique across programs. |
| `site_name` | string | Site name as published by EPA. Null when EPA published the single-space sentinel instead of a name, which happens on 1,675 sites (mostly state abandoned coal mine areas). |
| `site_name_withheld_by_epa` | boolean | True when EPA published no site name for this record. Distinguishes a genuinely unnamed site from a fetch problem. |
| `program` | string | The originating cleanup program exactly as EPA publishes it. 49 distinct values, from short federal codes such as SUPERFUND and RCRA to full state program names. |
| `program_category` | string | Coarse category derived from the verbatim program name: abandoned\_mine\_land, brownfield, landfill, superfund, rcra\_corrective\_action, underground\_storage\_tank, institutional\_control or state\_cleanup\_program. |
| `program_is_federal` | boolean | True when the program is one of EPA's six federal programs, false when it is a state program. Null when no program was published. |
| `epa_region` | number | EPA regional office number (1-10) covering the site. |
| `objectid` | number | The ArcGIS feature OBJECTID for this row. Useful for reproducing a query; not stable across EPA republications. |

#### Location

| Field | Type | What it means |
|---|---|---|
| `state` | string | Two-letter US state or territory postal code. |
| `county` | string | County name as published by EPA. |
| `city` | string | City name as published by EPA. Null on the 19,675 sites carrying the single-space sentinel. |
| `address` | string | Street address as published by EPA. Null on the 22,261 sites carrying the single-space sentinel. |
| `zip_code` | string | ZIP code as published by EPA. Null on the 61,533 sites carrying the single-space sentinel. EPA does not zero-pad, so New England ZIPs may be four digits. |
| `latitude` | number | Site latitude in decimal degrees, read from EPA's Latitude column. Null when missing or when the value failed a coordinate-range check. |
| `longitude` | number | Site longitude in decimal degrees, read from EPA's Longitude column. Verified to agree with an outSR=4326 geometry to nine decimal places. |
| `coordinate_status` | string | ok, missing, null\_island, or out\_of\_range\_possible\_projection\_drift. A coordinate outside plus or minus 90/180 is rejected rather than published, because Web Mercator metres are in the millions. |

#### Site character

| Field | Type | What it means |
|---|---|---|
| `acreage_acres` | number | Site acreage. NULL when EPA published 0, because 0 is a null sentinel on this layer meaning acreage is unknown (108,888 sites), not zero acres. |
| `acreage_raw_value` | number | EPA's raw Acreage value before the null-sentinel rule is applied, so the 0 sentinel remains visible on the row. |
| `acreage_is_null_sentinel` | boolean | True when EPA published acreage 0, meaning acreage is unknown. On 108,886 of those 108,888 sites EPA also sets No Acreage PV, confirming it could not size an array because acreage was missing. |
| `acreage_implausible` | boolean | True when acreage exceeds the plausibility threshold. Some EPA acreage values are clearly not the site footprint, for example an urban Denver brownfield published at 43,000 acres. Flagged rather than dropped, because the intended figure is unknowable. Null when acreage is unknown. |
| `acreage_implausible_threshold_acres` | number | The acreage above which this actor flags acreage as implausible. Published so the flag can be re-derived. |
| `is_known_landfill` | boolean | True when EPA flags the site as a known landfill (18,298 sites). False means EPA did not flag it, which is weaker than EPA determining it is not a landfill. |
| `known_landfill_raw` | string | EPA's Landfill column verbatim: Y, or null where EPA published the single-space sentinel. |
| `is_abandoned_mine_land` | boolean | True when EPA flags the site as known Abandoned Mine Land (17,756 sites). |
| `abandoned_mine_land_raw` | string | EPA's AML column verbatim: Y, or null where EPA published the single-space sentinel. |

#### Solar screening

| Field | Type | What it means |
|---|---|---|
| `utility_scale_pv` | boolean | True when EPA's screen flagged the site for utility-scale photovoltaics (17,649 sites). This is the meaningful solar discriminator; EPA's summary Solar column is Y on all 190,976 sites and carries no information. |
| `utility_scale_pv_raw` | string | EPA's UtilPV column verbatim: Y, or null for the single-space sentinel. |
| `distributed_scale_pv` | boolean | True when EPA flagged the site for distributed-scale photovoltaics (64,268 sites). |
| `distributed_scale_pv_raw` | null | EPA's DistribPV column verbatim: Y, or null for the single-space sentinel. |
| `offgrid_pv` | boolean | True when EPA flagged the site for off-grid photovoltaics (82,090 sites). |
| `offgrid_pv_raw` | string | EPA's OffgridPV column verbatim: Y, or null for the single-space sentinel. |
| `no_acreage_pv` | boolean | True when EPA recorded that it could not size a PV array because site acreage was unknown. Co-occurs with acreage\_is\_null\_sentinel on 108,886 sites. |
| `est_pv_capacity_mw` | number | EPA's estimated PV capacity. Read the capped and usable flags before using it: it sits on a 600 MW plateau (362 sites read exactly 600 MW) but 600 is NOT a ceiling — 16 sites exceed it, up to 11,788.08 MW, so never filter on est\_pv\_capacity\_mw <= 600. Underneath the plateau the figure is a flat national multiple of acreage at roughly 0.1449 MW/acre, so it carries no site-specific engineering information. |
| `est_pv_capacity_is_capped` | boolean | True when EPA's estimate is at or above 600 MW. Measured live 2026-08-19: 362 sites read exactly 600 across an acreage range of 4,144 to 2,669,225 acres, and 16 more exceed 600 (maximum 11,788.08 MW), so 600 is a plateau rather than a hard ceiling. On all of those sites the number is formulaic, not a site-specific estimate. Null when EPA published no capacity. |
| `est_pv_capacity_usable_for_ranking` | boolean | False when the capacity is missing or capped, and therefore must not be used to rank or compare sites. This actor's score never uses EPA capacity for that reason. |
| `est_pv_capacity_note` | string | Why the capacity is or is not usable: published, at\_or\_above\_600mw\_plateau, or not\_published. |
| `pv_density_mw_per_acre_derived` | number | EPA's estimated PV capacity divided by acreage, computed by this actor. Published so a buyer can see for themselves that EPA's capacity figure is a constant-density desktop calculation. Null when either input is unknown. |
| `ghi_kwh_m2_day` | number | Maximum annual Global Horizontal Irradiance modelled at the site. Measured range across the layer is 2.0 to 6.9. |
| `solar_resource_class` | string | Band derived from GHI: excellent (5.75+), strong (5.25+), moderate (4.75+), marginal (4.25+) or weak. Null when EPA published no GHI. |

#### Wind screening

| Field | Type | What it means |
|---|---|---|
| `utility_scale_wind` | boolean | True when EPA flagged the site for utility-scale wind (601 sites nationally). |
| `utility_scale_wind_raw` | string | EPA's UtilWnd column verbatim: Y, or null for the single-space sentinel. |
| `community_scale_wind` | boolean | True when EPA flagged the site for community-scale wind (9,770 sites). |
| `community_scale_wind_raw` | string | EPA's CommunWnd column verbatim: Y, or null for the single-space sentinel. |
| `facility_scale_wind` | boolean | True when EPA flagged the site for facility-scale wind (18,851 sites). |
| `facility_scale_wind_raw` | null | EPA's FacilWnd column verbatim: Y, or null for the single-space sentinel. |
| `no_acreage_wind` | boolean | True when EPA recorded that it could not size a wind project because site acreage was unknown. |
| `est_wind_capacity_mw` | number | EPA's estimated wind capacity. Capped at 1600 MW, which is never exceeded anywhere in the layer. Read the capped flag before using it. |
| `est_wind_capacity_is_capped` | boolean | True when EPA's estimate is at or above the 1600 MW ceiling (49 sites). Null when EPA published no wind capacity. |
| `est_wind_capacity_usable_for_ranking` | boolean | False when the wind capacity is missing or capped and therefore must not be used to rank sites. |
| `est_wind_capacity_note` | string | Why the wind capacity is or is not usable: published, at\_or\_above\_epa\_ceiling, or not\_published. |
| `wind_speed_40m_ms` | number | Modelled annual average wind speed at 40 m. |
| `wind_speed_80m_ms` | number | Modelled annual average wind speed at 80 m. |
| `wind_speed_100m_ms` | number | Modelled annual average wind speed at 100 m, the hub height modern turbines actually use and the basis for wind\_resource\_class. |
| `wind_resource_class` | string | Band derived from the 100 m wind speed: excellent (8.5+), strong (7.5+), moderate (6.5+), marginal (5.5+) or weak. Null when no wind speed was published. |

#### Biomass screening

| Field | Type | What it means |
|---|---|---|
| `biopower_potential` | boolean | True when EPA flagged the site as a candidate for a biopower facility (30,909 sites). |
| `biopower_potential_raw` | string | EPA's BioPwrPot column verbatim: Y, or null for the single-space sentinel. |
| `biorefinery_potential` | boolean | True when EPA flagged the site as a candidate for a biorefinery (3,667 sites). |
| `biorefinery_potential_raw` | string | EPA's BioRefPot column verbatim: Y, or null for the single-space sentinel. |
| `cumulative_biopower_residues_tpy` | number | Cumulative biopower residues available within 50 miles of the site, in metric tons per year. |
| `cumulative_biorefinery_residues_tpy` | number | Cumulative biorefinery residues available within 50 miles, in metric tons per year. |
| `crop_residues_tpy` | number | Crop residues available within 50 miles, in metric tons per year. |
| `forest_residues_tpy` | number | Forest residues available within 50 miles, in metric tons per year. |
| `primary_mill_residues_tpy` | number | Primary mill residues available within 50 miles, in metric tons per year. |
| `secondary_mill_residues_tpy` | number | Secondary mill residues available within 50 miles, in metric tons per year. |
| `urban_waste_wood_tpy` | number | Urban waste wood residues available within 50 miles, in metric tons per year. |

#### Geothermal screening

| Field | Type | What it means |
|---|---|---|
| `geothermal_heat_pump_potential` | boolean | EPA's geothermal heat pump flag. Note that this is Y on 190,956 of 190,976 sites (99.99%), so it is effectively a constant and is not offered as a filter. |
| `geothermal_heat_pump_raw` | string | EPA's GeoHeatPmp column verbatim: Y, or null for the single-space sentinel. |
| `surface_temperature_c` | number | Modelled annual average surface temperature at the site, used by EPA in its geothermal heat pump screen. |
| `permafrost_present` | boolean | True when EPA flagged permafrost at the site. Only 20 sites nationally, all in Alaska. |
| `permafrost_raw` | null | EPA's PermFrost column verbatim: Y, or null for the single-space sentinel. |

#### Infrastructure (EPA 2022 screening estimates, NOT live)

| Field | Type | What it means |
|---|---|---|
| `substation_distance_miles_2022_screening_estimate` | number | EPA's 2022 precomputed distance to the nearest substation. A FROZEN SCREENING ESTIMATE, not a live measurement. Run hifld-grid-proximity-screener on this row's coordinates for the current figure. |
| `substation_voltage_volts_2022_screening_estimate` | number | EPA's 2022 precomputed nearest substation voltage, published by EPA in the Volts column though the values are in kV magnitude. Null on sites where EPA published none. |
| `substation_voltage_kv_derived` | number | The substation voltage restated for convenience. EPA's column is labelled Volts but publishes values such as 115 and 230, which are kV, so this actor does not rescale it and says so. |
| `transmission_distance_miles_2022_screening_estimate` | number | EPA's 2022 precomputed distance to the nearest transmission line. A frozen screening estimate, not a live measurement. |
| `transmission_line_kv_2022_screening_estimate` | number | EPA's 2022 precomputed nearest transmission line voltage in kilovolts. |
| `transmission_line_status_2022_screening_estimate` | string | EPA's 2022 precomputed status of the nearest transmission line. Measured vocabulary: IN SERVICE, INACTIVE, NOT AVAILABLE, UNDER CONST. |
| `transmission_status_contradicts_voltage` | boolean | True when EPA reports the nearest line status as NOT AVAILABLE while also publishing a voltage above zero. This internal contradiction affects 16,803 sites and is surfaced rather than silently resolved. Null when either input is missing. |
| `nearest_interconnection_distance_miles_2022` | number | The smaller of EPA's 2022 substation and transmission distances. A frozen screening estimate used for ranking only. |
| `road_distance_miles` | number | EPA's precomputed distance to the nearest graded road. |
| `rail_distance_miles` | number | EPA's precomputed distance to the nearest rail line. |
| `interconnection_data_is_live` | boolean | Always false. Every interconnection figure on this row comes from EPA's frozen 2022 precomputation, never from a live grid query. |
| `interconnection_note` | string | Full-text warning that EPA's grid fields are a 2022 precomputation, are internally inconsistent on 16,803 sites, and must not be used to size an interconnection. |
| `verify_interconnection_with` | string | The sibling actor to run on this row's coordinates for a live line and substation measurement. |

#### Ranking

| Field | Type | What it means |
|---|---|---|
| `technologies_flagged` | array | Every renewable technology EPA's screen flagged for this site, from the scale-specific columns: utility\_solar, distributed\_solar, offgrid\_solar, utility\_wind, community\_wind, facility\_wind, biopower, biorefinery. |
| `technologies_flagged_count` | number | Count of technologies EPA flagged for this site. |
| `best_flagged_technology` | string | The flagged technology with the greatest typical project value, ordered utility\_solar, utility\_wind, distributed\_solar, community\_wind, facility\_wind, biopower, biorefinery, offgrid\_solar. Null when EPA flagged none. |
| `development_candidate_score` | number | An EDITORIAL 0-100 ranking score computed by this actor from EPA's screening inputs: resource, site size, 2022 interconnection proximity, road access and reuse archetype. Rescaled to the components that were actually available. NULL, never 0, when no component could be computed. This is a ranking aid, not a feasibility determination. |
| `score_components_available` | array | Which of the five scoring components had inputs on this site. |
| `score_components_missing` | array | Which scoring components could not be computed because EPA published no input. |
| `score_weight_available` | number | How much of the 100-point weight was actually computable on this site. A score built on 45 of 100 available weight is far weaker evidence than one built on 100. |
| `score_is_incomplete` | boolean | True when at least one scoring component could not be computed, so the score rests on partial inputs. |
| `score_basis` | string | Plain-language statement of exactly how this row's score was computed and what was excluded from it. |

#### Honesty and provenance

| Field | Type | What it means |
|---|---|---|
| `epa_screening_only` | boolean | Always true. Everything on this row is EPA's desktop pre-screen output. |
| `is_entitlement` | boolean | Always false. An EPA RE-Powering screening result confers no permit, no land right, no interconnection position and no approval of any kind. |
| `screening_disclaimer` | string | Full-text statement that EPA RE-Powering is a desktop pre-screen and not an entitlement, feasibility study or site-control position. |
| `flag_semantics_note` | string | Full-text explanation that EPA publishes no explicit negative value, so a false on any flag means EPA did not flag it rather than EPA determining the negative. |
| `capacity_ceiling_note` | string | Full-text explanation of EPA's 600 MW PV plateau (which 16 sites exceed, so it is NOT a ceiling), the genuine 1600 MW wind ceiling, and the constant-density national basis of both estimates. Every figure in this sentence is asserted live against the layer by the pv\_plateau\_integrity drift probe before any row is billed. |
| `epa_site_info_url` | string | EPA or state program page for the underlying cleanup site. |
| `epa_repowering_profile_url` | string | EPA's own RE-Powering Site Profile page for this site, where every value on this row can be independently checked against EPA. |
| `data_vintage` | string | The vintage of EPA's RE-Powering Mapper layer. EPA states it in the service name itself. |
| `layer_title` | string | The EPA ArcGIS layer this row came from. |
| `source_url` | string | The EPA ArcGIS FeatureServer layer endpoint queried for this row. |
| `checked_at` | string | UTC timestamp when this run queried EPA. |

#### Run context (repeated on every row)

| Field | Type | What it means |
|---|---|---|
| `matched_sites_total` | number | The exact number of sites matching the query, read from EPA's free returnCountOnly endpoint before any row was fetched. Compare with the row count to see whether the answer was capped. |
| `results_truncated` | boolean | True when more sites matched than were returned, because maxResults capped the run. A capped answer can therefore never be mistaken for a complete one. |
| `max_results_requested` | number | The maxResults cap in force for this run. |
| `filters_applied` | array | Every filter this run actually applied, so a buyer can confirm the query they thought they asked for is the query that ran. |
| `where_clause` | string | The exact SQL WHERE clause sent to EPA's FeatureServer. Published so the result is reproducible. |
| `drift_gate_status` | string | verified when all six live drift probes passed, or verified\_degraded when every load-bearing probe passed but a corroborating probe could not complete. A run never emits rows in any other state. |
| `drift_probes_verified` | array | Which drift probes completed and measured what was expected on this run. |
| `drift_probes_unavailable` | array | Which drift probes could not complete (an outage, not a wrong measurement). A probe that could not complete is not a probe that failed, and only corroborating probes may be unavailable on a run that emits rows. |
| `drift_gate_note` | string | Plain-language summary of what the live drift gate verified before any billable row was produced. |
| `layer_status` | string | ok when every drift probe passed, ok\_degraded when a corroborating probe was unavailable. A failed layer never reaches this field because the run fails first. |

***

### FAQ

**Where does this data come from?**
EPA's RE-Powering America's Land initiative, published as the ArcGIS layer *RE-Powering Mapper Sites 2022* (`services.arcgis.com/cJ9YHowT8TU7DUyn/.../RE_Powering_Mapper_Sites_2022/FeatureServer/0`). 190,976 sites, 55 published columns, verified live.

**How current is it?** The layer is EPA's 2022 vintage and EPA states that in the service name. Every row carries `data_vintage: "2022"`. There is no newer EPA-published copy at the time of writing. The grid fields in particular are a 2022 precomputation — see trap 5 above.

**Does a site appearing here mean I can build a solar farm on it?**
No. It means EPA's desktop screen did not rule the site out. Nothing here confers a permit, a land right, an interconnection position or a cleanup determination. That is why every row carries `is_entitlement: false`.

**Why is `est_pv_capacity_mw` sometimes exactly 600?**
Because 600 MW is a plateau EPA applies to large sites, not a site-specific estimate. 362 sites read exactly 600 across a 644x range of acreage. Those rows carry `est_pv_capacity_is_capped: true` and `est_pv_capacity_usable_for_ranking: false`, and the ranking score ignores EPA capacity entirely.

**Is 600 MW a hard ceiling on `est_pv_capacity_mw`?**
**No — and this is the one number to be careful with.** 16 sites publish more than 600 MW, up to 11,788.08 MW. If you filter with `est_pv_capacity_mw <= 600` you will silently discard the 16 largest solar-redevelopment candidates in the layer. Filter on `est_pv_capacity_is_capped` instead, which is true at or above the plateau and covers both groups. (`EstWindCap`'s 1,600 MW ceiling **is** genuine — zero sites exceed it. That asymmetry is why the PV figure is checked live on every run.)

**Why is `acreage_acres` null on a site that clearly has land?**
Because EPA published acreage 0, which on this layer means "unknown", not "zero". Check `acreage_raw_value` and `acreage_is_null_sentinel`.

**Why is the site name blank?**
1,675 sites publish no name — mostly state abandoned coal mine areas identified only by a program number. Those rows carry `site_name_withheld_by_epa: true` and still have a county, coordinates and an EPA profile URL.

**Can I filter on EPA's `Solar` column?**
No, and you should not want to: it is `Y` on every one of the 190,976 sites. Use the `technologies` input, which filters on EPA's scale-specific columns.

**How do I get a real interconnection distance?**
Run [hifld-grid-proximity-screener](https://apify.com/malonestar/hifld-grid-proximity-screener) on the `latitude`/`longitude` in the row. Every row names it in `verify_interconnection_with`.

**What happens if EPA changes or retires the layer?**
The run fails loudly with a message naming the probe that detected it, and bills nothing. The gate catches a collapsed row count, a moved canary site, a change to EPA's null convention, a filter that stopped being applied, a retired service, and a change to the EstPVCap distribution this actor describes in prose on every row.

**Can I verify a row against EPA directly?**
Yes — every row carries `epa_repowering_profile_url`, EPA's own RE-Powering Site Profile page for that exact site.

**Is a zero-row result a bug?** Only if you did not expect it. This actor never returns an empty dataset because something broke; it fails instead. Zero rows means EPA holds no site matching your filters, and `matched_sites_total` will read 0 to confirm it.

***

### Data source and licence

US EPA RE-Powering America's Land, Cleanups in My Community (CIMC). US federal government data, public domain. This actor adds normalisation, sentinel handling, ranking and disclosure; it does not alter EPA's underlying values, all of which are re-published verbatim in the `*_raw` columns and are checkable against `epa_repowering_profile_url`.

# Actor input Schema

## `states` (type: `array`):

Two-letter US state or territory codes to screen, for example \["CO"] or \["PA","WV"]. Required, and capped at 6 per run, so that a bare {} call can never run against all 190,976 national sites and bill for it.

## `counties` (type: `array`):

Optional county names to narrow the search, matched exactly and case-insensitively against EPA's County column, for example \["EL PASO","DENVER"]. Leave empty for all counties in the chosen states.

## `cities` (type: `array`):

Optional city names to narrow the search, matched exactly and case-insensitively against EPA's City column. Note that 19,675 sites carry no city, so a city filter will exclude them.

## `technologies` (type: `array`):

Keep only sites EPA flagged for at least one of these technologies. Valid values: utility\_solar, distributed\_solar, offgrid\_solar, utility\_wind, community\_wind, facility\_wind, biopower, biorefinery. Leave empty for every technology. Note that EPA's summary Solar column is 'Y' on all 190,976 sites and carries no information, so this actor filters on the scale-specific columns instead.

## `programCategories` (type: `array`):

Keep only sites whose EPA program falls in these categories. Valid values: abandoned\_mine\_land, brownfield, landfill, superfund, rcra\_corrective\_action, underground\_storage\_tank, institutional\_control, state\_cleanup\_program. Applied in memory after the query, because the category is derived from EPA's 49 verbatim program names.

## `landfillOnly` (type: `boolean`):

Keep only the 18,298 sites EPA flags as a known landfill. Landfill-to-solar is the deepest-precedent redevelopment archetype.

## `abandonedMineLandOnly` (type: `boolean`):

Keep only the 17,756 sites EPA flags as known Abandoned Mine Land.

## `minAcreage` (type: `integer`):

Minimum site acreage. EPA writes acreage 0 as a null sentinel on 108,888 sites (it means 'acreage unknown', not 'zero acres'), so any minimum-acreage filter necessarily excludes every site with unknown acreage.

## `minGhi` (type: `integer`):

Minimum maximum-annual Global Horizontal Irradiance. Measured range across the layer is 2.0 to 6.9 kWh/m2/day.

## `minWindSpeed100m` (type: `integer`):

Minimum modelled wind speed at 100 m hub height. Roughly 6.5 m/s and above is where utility-scale wind becomes interesting.

## `maxSubstationDistanceMiles` (type: `integer`):

Maximum distance to the nearest substation. This is EPA's FROZEN 2022 precomputation, not a live measurement, and it must not be used to size an interconnection. Run hifld-grid-proximity-screener on the returned coordinates for the live figure.

## `maxTransmissionDistanceMiles` (type: `integer`):

Maximum distance to the nearest transmission line, again from EPA's frozen 2022 precomputation rather than a live measurement.

## `minTransmissionKv` (type: `integer`):

Minimum voltage of the nearest transmission line from EPA's 2022 precomputation. Note that 16,803 sites publish a voltage while reporting the line status as NOT AVAILABLE, which this actor flags on the row rather than silently resolving.

## `sortBy` (type: `string`):

How to order the returned sites. Valid values: score\_desc (default), acreage\_desc, ghi\_desc, wind\_speed\_desc, interconnection\_distance\_asc, state\_then\_county. Sites with a missing value always sort last.

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

Maximum number of sites to return and bill for. Every row also carries matched\_sites\_total and results\_truncated, so a capped answer can never be mistaken for a complete one.

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

Diagnostic seam that forces a specific drift probe or the paging step to fail, so the failure paths can be re-proved on demand rather than only during a real outage. Valid values: none (default), total\_floor, positive\_canary, sentinel\_integrity, negative\_control, filter\_narrows, pv\_plateau\_integrity, all\_probes, paging.

## Actor input object example

```json
{
  "states": [
    "CO"
  ],
  "technologies": [
    "utility_solar"
  ],
  "minAcreage": 20,
  "sortBy": "score_desc",
  "maxResults": 500,
  "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 = {
    "states": [
        "CO"
    ],
    "technologies": [
        "utility_solar"
    ],
    "minAcreage": 20,
    "sortBy": "score_desc",
    "simulateOutage": "none"
};

// Run the Actor and wait for it to finish
const run = await client.actor("malonestar/epa-repowering-brownfield-to-solar-site-finder").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 = {
    "states": ["CO"],
    "technologies": ["utility_solar"],
    "minAcreage": 20,
    "sortBy": "score_desc",
    "simulateOutage": "none",
}

# Run the Actor and wait for it to finish
run = client.actor("malonestar/epa-repowering-brownfield-to-solar-site-finder").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 '{
  "states": [
    "CO"
  ],
  "technologies": [
    "utility_solar"
  ],
  "minAcreage": 20,
  "sortBy": "score_desc",
  "simulateOutage": "none"
}' |
apify call malonestar/epa-repowering-brownfield-to-solar-site-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,malonestar/epa-repowering-brownfield-to-solar-site-finder"
        }
    }
}

```

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/2ZBFECTPoGkPJLbiO/builds/SItKgwi6bMD4IEpno/openapi.json
