# Electricity Rates & Grid Mix by State — EIA Site Economics (`malonestar/eia-v2-site-energy-economics`) Actor

Electricity cost screening by state from the EIA v2 API: industrial, commercial and residential retail rates with YoY change and a live US benchmark, plus operating capacity by fuel, balancing authority, storage split and planned retirements. For data-center and industrial siting.

- **URL**: https://apify.com/malonestar/eia-v2-site-energy-economics.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 $4.40 / 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

## Electricity Rates & Grid Mix by State — EIA Site Economics

Answers "what will power cost here, and what is the grid made of" for one or many
US states, straight from the **US Energy Information Administration v2 API**.
Built for data-center, manufacturing and industrial site selection.

Per state you get the **industrial, commercial, residential and all-sector retail
rate**, the **year-over-year change** in each, the state's rate measured against
the **live national industrial average**, and a full **operating capacity
rollup** — by fuel, by prime mover, by balancing authority, with **battery and
pumped storage split out of generation**, biomass counted as renewable, and
**planned retirements, uprates and derates** flagged.

Data is first-party EIA. No scraping.

### Who it's for

- **Data-center and industrial site selectors** — compare industrial c/kWh across a shortlist, then check whether the grid behind it is gas, wind or coal, and what is scheduled to retire.
- **Energy developers and IPPs** — see operating capacity by balancing authority (ERCOT vs SPP vs MISO) before siting generation or storage.
- **Corporate real estate and economic development** — power cost and carbon mix in one row per state.
- **Analysts and AI agents** — a clean, chainable per-state energy-economics record.

This is a screening tool built on EIA's published data, not an engineering study
or a utility tariff quote. Retail rates are state averages across all utilities;
your actual rate comes from a specific tariff.

### What changed in v1.2 (2026-08-10) — read this if you stored earlier numbers

v1.1 fixed the *units* of what EIA publishes. v1.2 fixes the *classification* of
it. Two corrections change numbers you may already have saved:

| Defect | Effect |
|---|---|
| **Hydroelectric pumped storage was counted as renewable hydro generation.** EIA files it under energy source code `WAT` — byte-identical to a conventional dam — and the only thing that separates them is `prime_mover_code = PS`, which v1.1 never read. | Pumped storage is a net **consumer** of electricity (~80% round-trip). Nationally **21,931.2 MW** was misclassified (2026-05). **South Carolina's `hydro_capacity_mw` read 4,376.0 MW against a true 1,334.8 MW — 3.28x** — and Virginia 3,912.6 against 803.3 (**4.87x**). Colorado read 1,187.6 against a true 679.1. Renewable share of generation: SC **23.41% → 15.73%**, VA 29.91% → 24.41%. v1.1 had deliberately excluded *batteries* from generation while counting the grid's original battery as renewable hydro. Now in `pumped_storage_capacity_mw`. |
| **Biomass was omitted from renewables entirely.** EIA's own renewable definition includes wood, wood waste, landfill gas, black liquor, agricultural byproducts and other biomass; v1.1 counted only SUN/WND/WAT/GEO. | The error runs the other way — it **understated** biomass states. **Vermont's renewable share of generation read 72.21% against a true 82.46%**, Maine 49.44% against 56.28%. Nationally 9,594 MW. Now counted, and broken out as `biomass_capacity_mw`. Municipal solid waste is only partly biogenic and EIA does not publish the split on this route, so it is reported separately in `msw_capacity_mw` and deliberately **not** counted as renewable. |

Fields affected by both: `hydro_capacity_mw`, `renewable_capacity_mw`,
`renewables_share_pct`, `renewables_share_of_generation_pct`,
`zero_carbon_share_pct`, `operating_generation_capacity_mw`, `coal_share_pct`,
`gas_share_pct`. No field was removed or renamed.

Also in v1.2:

| Change | Why |
|---|---|
| **Closed vocabularies for `energy_source_code` (38 values) and `prime_mover_code` (18) are now asserted live**, and an unknown value fails the run | Every fuel class the Actor publishes is keyed on that vocabulary. A code EIA adds later would be counted in the state total and appear in **none** of the coal / gas / nuclear / renewable / petroleum / storage figures. Nothing checked this before. |
| **`other_capacity_mw` + `fuel_classification_complete`** | Waste heat, purchased steam and "other" fit no named class. Colorado carries 6.1 MW and Texas 237.4 MW of it. Previously invisible; now reported, with a flag saying whether the named classes account for the whole state. |
| **`petroleum_capacity_mw`, `geothermal_capacity_mw`, `msw_capacity_mw`** | Oil-fired peaking and black-start capacity (18.2 GW nationally) had no bucket at all. |
| **Hydrogen (`H2`) mapped to gas** | A real, if small, EIA code that fell out of every class. |
| **`top_generation_fuel`** | `top_fuel` can legitimately answer `MWH`, which is storage rather than a fuel. |
| **The retail query is now bounded to the requested history window** | v1.1 sent no date bounds, so `months` set only the *page size* while `response.total` was the whole 2001-present series (Colorado: 1,830 rows). The completeness guard then paged all 25 years — **13 EIA requests per state** to answer a 24-month question. Now one bounded request, and the window ships on the row as `retail_window_start` / `retail_window_end`. |
| **Announced uprates and derates** | EIA publishes `planned-uprate-*` and `planned-derate-*` on the same route and v1.1 requested them from nothing. A site looking for headroom cares about these as much as about retirements. |
| **`entity_id`, `unit`, `sector_id`, `is_storage`, `is_pumped_storage` on plant rows** | All fetched on every row since v1.0 and emitted by nothing. `entity_id` is the join key to EIA Form 861 and ownership data. |

### What changed in v1.1 (2026-08-01)

Every item below was found by re-probing the live EIA API, and each was
producing a confident wrong answer on a green run:

| Defect | Effect |
|---|---|
| `sales_ind_mwh_latest` published EIA's raw number under an MWh label | EIA publishes retail sales in **million kilowatt-hours**. Colorado 2026-05 read **1,259.96 "MWh"** against a true **1,259,956 MWh** — every sales volume was **1,000x too small**. Fixed, with the raw EIA figure preserved as `sales_ind_gwh_latest`. |
| `total_nameplate_capacity_mw`, titled "operating", summed **all four** EIA generator statuses | Texas 2026-05 reported **201,329.5 MW**, of which **3,922.5 MW is not operating** — including 2,314.0 MW EIA marks as out of service and *not expected to return*. Now operating-only (**197,407.0 MW**), with the rest in `non_operating_capacity_mw` and `capacity_by_status_mw`. |
| Battery storage was treated as a fuel | EIA files batteries under energy source code `MWH`. Texas had **16,306.5 MW** of storage sitting in the denominator of the renewables share, reporting **38.41%** against a true operating-generation share of **42.54%**. Storage is now split out and `renewables_share_of_generation_pct` added. |
| The rate note compared against a **hard-coded 8.0 c/kWh** "US average" | The live national industrial average is **8.71 c/kWh** (2026-05). Colorado's 9.47 went from "**well above** the US average (+18%)" to "**near** the US average (+8.7%)" — the verdict flipped. The benchmark is now fetched live every run and published on the row. |
| A missing nameplate value became `0 MW` | Six Colorado generators publish no net-summer capacity; those were being summed as zero. Nulls are now nulls, and `capacity_rows_missing_nameplate` counts them. |
| A capacity fetch that returned nothing produced `0 MW`, `0%` renewables, `0` plants | A billable row asserting the state has no power plants. Those fields are now **null**, with `capacity_source_status: "unavailable"` and `partial_result: true`. |
| An unrecognised state id returned HTTP 200 with zero rows | A typo'd state was published as a real state with no generation. Now rejected up front with `state_id_recognized: false`. |
| `length=5000`, no pagination, `response.total` never read | Texas reports `total` **290,133**. It happened to work only because the newest month fits in one page. The capacity query now pins an explicit month and pages to completion, failing rather than emitting a fragment. |
| An error row was pushed per state from inside the loop | A bad key or an EIA outage produced a green run and a **billable** row per state carrying no data. The run now fails if no state could be read, and nothing is pushed until that gate passes. |
| 20+ fetched columns were discarded | Operator, balancing authority, net summer/winter capacity, in-service date, planned retirement date, county and lat/lon were all in the payload and thrown away. |

### Live self-checks (every run, before anything is billed)

An offline fixture cannot see the upstream change, because the fixture was shaped
from the upstream. Before a single row is emitted the Actor probes EIA and
**fails the run** — emitting nothing, billing nothing — if any of these drifts:

1. **Units.** `price` must still be *cents per kilowatt-hour*, `sales` must still be *million kilowatt hours*, and nameplate capacity must still be *MW*. This is the assertion that catches the 1,000x class of bug rather than publishing it.
2. **Closed retail sector vocabulary** — RES, COM, IND, TRA, OTH, ALL. A new sector fails the run instead of vanishing from the price fields.
3. **Closed generator status vocabulary** — OP, OA, OS, SB. Capacity totals count only `OP`, so an unrecognised status would be silently excluded from every state total.
4. **Freshness** — EIA's published `endPeriod` must be within 8 months of today.
5. **Positive canary** — the national industrial benchmark must exist and land in a plausible 3–40 c/kWh band.
6. **Negative control** — a state id that cannot exist must match **zero** rows. If it matches anything, the `stateid` facet is not being applied and every "per state" answer is really national data.
7. **Truncation guard** — `response.total` is compared with the rows actually retrieved on every paged query.
8. **Closed energy-source vocabulary** — the live `energy_source_code` facet must contain no code outside the 38 the fuel mapping knows, and must still contain NG, SUN, WND, WAT, NUC and MWH. An unmapped code would sit in the state total and in none of the fuel classes.
9. **Closed prime-mover vocabulary**, and specifically that **`PS` still exists**. Conventional hydro and pumped storage share the `WAT` fuel code and are separated by nothing else, so if `PS` disappeared every hydro and renewable figure would silently re-inflate.

Checks 8 and 9 also run against the rows actually returned for each state, not
only against EIA's published facet list — a code can appear in the data before it
appears in the facet.

Every measured value is written to the run log.

### You need a free EIA API key

Register in about a minute at **https://www.eia.gov/opendata/register.php** (no
cost, no card) and paste it into `apiKey`. It is sent only to `api.eia.gov`.

Leaving `apiKey` blank falls back to this Actor's own key, which is **shared
across all users** and throttles sooner. With no key available at all the run
**fails loudly** with the registration URL and bills nothing — it does not return
a green empty dataset.

### Example input

```json
{ "states": ["CO", "TX"], "months": 24 }
```

Full generator inventory for one state — every unit with operator, balancing
authority, capacity, in-service date, planned retirement and coordinates:

```json
{ "states": ["CO"], "includePlantDetail": true, "maxPlantRows": 600 }
```

Multi-state shortlist for a data-center search:

```json
{ "states": ["TX", "OH", "GA", "AZ", "IA"], "months": 24 }
```

`"US"` is accepted as a state id and returns the national aggregate.

### Output fields — `state_profile` rows

| Field | Meaning |
|---|---|
| `row_type` | "state\_profile" for the one summary row per state, or "plant" for an optional per-generator detail row. |
| `stateid` | Two-letter US state id. |
| `state_description` | Full state name as returned by EIA. |
| `latest_period` | Most recent monthly retail-rate period available (YYYY-MM). |
| `price_res_cents_kwh` | Latest-month average residential retail electricity price, cents per kWh. |
| `price_com_cents_kwh` | Latest-month average commercial retail electricity price, cents per kWh. |
| `price_ind_cents_kwh` | Latest-month average industrial retail electricity price, cents per kWh — the key figure for power-intensive site selection. |
| `price_all_sectors_cents_kwh` | Latest-month average retail electricity price across all sectors, cents per kWh. |
| `yoy_price_change_pct_res` | Percent change in residential price vs. the same calendar month one year prior. Null if the prior-year month is unavailable. |
| `yoy_price_change_pct_com` | Percent change in commercial price vs. the same calendar month one year prior. |
| `yoy_price_change_pct_ind` | Percent change in industrial price vs. the same calendar month one year prior — a key power-cost trend signal for a site. |
| `yoy_price_change_pct_all` | Percent change in all-sectors price vs. the same calendar month one year prior. |
| `sales_ind_mwh_latest` | Latest-month industrial electricity sales in MEGAWATT-HOURS. EIA publishes this series in million kilowatt-hours; v1.0 emitted the raw EIA number under an MWh label, so every value was 1,000x too small. See sales\_ind\_gwh\_latest for the raw EIA figure. |
| `total_nameplate_capacity_mw` | Total nameplate capacity of OPERATING generators (EIA status OP) in the state for the latest available month, megawatts. Battery storage is included here and broken out separately; non-operating capacity is excluded and reported in non\_operating\_capacity\_mw. Null means capacity was not retrieved - never 0. |
| `capacity_by_fuel` | Operating nameplate megawatts per EIA energy-source code (NG, WND, SUN, SUB, WAT, NUC, MWH...). MWH is battery/flywheel storage, not a fuel, and WAT mixes conventional hydro with pumped storage - see capacity\_by\_prime\_mover\_mw to separate them. |
| `top_fuel` | EIA energy-source code with the largest operating nameplate capacity in the state. This can legitimately answer "MWH", which is battery storage rather than a fuel; read top\_generation\_fuel for the largest generating fuel. |
| `plant_count` | Number of distinct plants with at least one OPERATING generator in the latest capacity month. |
| `capacity_period` | Monthly period (YYYY-MM) the capacity rollup is scoped to. |
| `renewables_share_pct` | renewable\_capacity\_mw as a percent of total\_nameplate\_capacity\_mw, which includes storage. For the generation-only figure see renewables\_share\_of\_generation\_pct. CORRECTED IN v1.2 - the numerator now excludes pumped storage and includes biomass. Null when capacity was not retrieved - never 0. |
| `industrial_rate_rank_note` | Plain-English note comparing the state industrial retail rate to the LIVE US industrial average fetched from EIA in the same run (see us\_avg\_industrial\_cents\_kwh). A screening note, not a determination. |
| `error` | Error message when BOTH EIA endpoints failed for this state; null otherwise. Per-source outcomes are in retail\_source\_status and capacity\_source\_status. |
| `checked_at` | UTC timestamp of the run. |
| `sales_ind_gwh_latest` | Latest-month industrial electricity sales exactly as EIA publishes it, in million kilowatt-hours (= GWh). sales\_ind\_mwh\_latest is this value x1000. |
| `sales_res_mwh_latest` | Latest-month residential electricity sales, converted from EIA million-kWh to megawatt-hours. |
| `sales_com_mwh_latest` | Latest-month commercial electricity sales, converted from EIA million-kWh to megawatt-hours. |
| `sales_all_mwh_latest` | Latest-month all-sectors electricity sales, converted from EIA million-kWh to megawatt-hours. |
| `revenue_ind_musd_latest` | Latest-month industrial electricity revenue in millions of dollars, as published by EIA. |
| `customers_ind_latest` | Number of industrial retail customers in the latest month. |
| `customers_all_latest` | Number of retail customers across all sectors in the latest month. |
| `price_period_res` | Month (YYYY-MM) the residential price is from. Sectors can publish at different lags. |
| `price_period_com` | Month (YYYY-MM) the commercial price is from. |
| `price_period_ind` | Month (YYYY-MM) the industrial price is from. |
| `price_period_all` | Month (YYYY-MM) the all-sectors price is from. |
| `price_tra_cents_kwh` | Latest-month average transportation-sector retail price, cents per kWh. |
| `us_avg_industrial_cents_kwh` | The national industrial retail rate the rate note is written against, fetched live from EIA (stateid=US, sectorid=IND). |
| `us_avg_industrial_period` | Month (YYYY-MM) of the national industrial benchmark. |
| `us_benchmark_source` | Always "eia\_live" on an emitted row: the national industrial benchmark is fetched from EIA (stateid=US, sectorid=IND) in the pre-flight, and a run that cannot retrieve it fails before any row is emitted or billed rather than falling back to a pinned constant. |
| `industrial_rate_vs_us_pct` | Percent by which this state industrial rate is above (+) or below (-) the national industrial average. |
| `operating_generation_capacity_mw` | Operating nameplate capacity EXCLUDING all storage - battery/flywheel (energy source MWH) and hydroelectric pumped storage (prime mover PS). This is capacity that actually generates electricity. CORRECTED IN v1.2 - v1.1 excluded batteries but counted 21,931.2 MW of national pumped storage as generation. |
| `battery_storage_capacity_mw` | Operating nameplate capacity filed under energy source code MWH - batteries and flywheels. Does NOT include hydroelectric pumped storage; see pumped\_storage\_capacity\_mw and total\_storage\_capacity\_mw. |
| `non_operating_capacity_mw` | Nameplate capacity in the state with a status other than OP (out of service or standby). Reported separately and EXCLUDED from the operating totals. |
| `capacity_by_status_mw` | Nameplate megawatts per EIA generator status code: OP Operating, OA out of service but expected back, OS out of service and not expected back, SB standby/backup. |
| `net_summer_capacity_mw` | Sum of operating generators net summer capacity - the figure that matters for summer peak. Null when EIA publishes none. |
| `net_winter_capacity_mw` | Sum of operating generators net winter capacity. |
| `generator_count` | Number of generator records in the latest capacity period, all statuses. |
| `nuclear_capacity_mw` | Operating nameplate capacity with energy source code NUC. |
| `coal_capacity_mw` | Operating nameplate capacity across coal energy source codes (BIT, SUB, LIG, ANT, RC, WC, SGC). |
| `gas_capacity_mw` | Operating nameplate capacity across gas energy-source codes NG, BFG, OG, PG, SGP and H2 (hydrogen, added to the mapping in v1.2). |
| `solar_capacity_mw` | Operating nameplate capacity with energy source code SUN. |
| `wind_capacity_mw` | Operating nameplate capacity with energy source code WND. |
| `hydro_capacity_mw` | CONVENTIONAL hydroelectric operating nameplate capacity: energy source code WAT with a prime mover other than PS. CORRECTED IN v1.2 - v1.1 counted every WAT generator, which folded hydroelectric PUMPED STORAGE into hydro. South Carolina read 4,376.0 MW against a true 1,334.8 MW (3.28x) and Virginia 3,912.6 against 803.3 (4.87x). Pumped storage is now reported separately in pumped\_storage\_capacity\_mw. If you stored this number before 2026-08-10 it is too high wherever the state has pumped storage. |
| `renewable_capacity_mw` | Renewable operating nameplate capacity: solar (SUN) + wind (WND) + conventional hydro (WAT excluding prime mover PS) + geothermal (GEO) + biomass (WDS, WDL, OBS, OBL, OBG, BLQ, AB, SLW, LFG). CORRECTED IN v1.2 in two directions - v1.1 counted pumped storage as renewable hydro AND omitted biomass entirely. Municipal solid waste is only partly biogenic and EIA does not publish the split here, so it is reported separately in msw\_capacity\_mw and is NOT counted as renewable. |
| `renewables_share_of_generation_pct` | renewable\_capacity\_mw as a percent of operating\_generation\_capacity\_mw (storage excluded from both sides). CORRECTED IN v1.2: South Carolina reads 15.73% against v1.1's 23.41%, Virginia 24.41% against 29.91% (pumped storage removed), while Vermont reads 82.46% against 72.21% and Maine 56.28% against 49.44% (biomass added). |
| `zero_carbon_share_pct` | Renewable plus nuclear capacity as a percent of operating\_generation\_capacity\_mw. Follows the v1.2 renewable correction (pumped storage out, biomass in). |
| `coal_share_pct` | Coal capacity as a percent of operating\_generation\_capacity\_mw. The denominator changed in v1.2 when pumped storage was reclassified as storage. |
| `gas_share_pct` | Gas capacity as a percent of operating\_generation\_capacity\_mw. The denominator changed in v1.2 when pumped storage was reclassified as storage. Hydrogen (H2) is counted here. |
| `capacity_by_balancing_authority_mw` | Operating nameplate megawatts per balancing authority (ERCO, MISO, SWPP, PSCO, ...). The grid a site would actually interconnect to. |
| `top_balancing_authority` | Balancing authority holding the largest share of the state operating capacity. |
| `planned_retirement_capacity_mw` | Operating nameplate capacity that EIA records a planned retirement date for. Null when no generator carries one. |
| `planned_retirement_generator_count` | Number of operating generators carrying a planned retirement date. |
| `next_planned_retirement_period` | Earliest FUTURE planned retirement year-month among operating generators in the state, relative to the capacity month. Dates EIA files in the past are excluded and counted in planned\_retirement\_dates\_before\_period. |
| `retail_source_status` | Per-source outcome for the EIA retail-sales endpoint on this row: ok, empty, unknown\_state, or unavailable. Null price fields under "unavailable" mean NOT CHECKED, not zero. |
| `capacity_source_status` | Per-source outcome for the EIA generator-capacity endpoint: ok, empty, unknown\_state, or unavailable. |
| `us_benchmark_status` | Whether the national industrial benchmark was retrieved this run. Always "ok" on an emitted row - the run fails if it was not. |
| `state_id_recognized` | False when the supplied state id is not one EIA publishes - a typo returns HTTP 200 with zero rows, which would otherwise look like a state with no power plants. |
| `partial_result` | True when any contributing source was degraded, so no field on this row should be read as a verified negative. |
| `retail_rows_total` | Rows EIA reports as matching the retail-sales query (response.total). From v1.2 the query is bounded to the requested history window, so this is the row count for that window rather than the whole 2001-present series. |
| `retail_rows_fetched` | Number of retail-sales rows actually retrieved. Equal to retail\_rows\_total on a complete fetch. |
| `capacity_rows_total` | Number of generator rows EIA reports for the pinned capacity month, from response.total. |
| `capacity_rows_fetched` | Number of generator rows actually retrieved. The run fails rather than emit a fragment if these disagree. |
| `capacity_rows_missing_nameplate` | How many generator rows EIA published with no nameplate capacity. Those rows contribute nothing to the totals rather than being counted as 0 MW. |
| `generator_id` | EIA generator id within the plant. |
| `energy_source_description` | EIA plain-text description of the energy source code. |
| `prime_mover_code` | EIA prime mover code (GT, CT, CA, ST, WT, PV, BA, ...). |
| `net_summer_mw` | Generator net summer capacity in megawatts. Null when EIA publishes none - never 0. |
| `net_winter_mw` | Generator net winter capacity in megawatts. |
| `status` | EIA generator status code: OP, OA, OS or SB. |
| `status_description` | Plain-text EIA status description. |
| `entity_name` | Utility or independent power producer that operates the generator. |
| `sector_name` | EIA sector of the operating entity (Electric Utility, IPP Non-CHP, ...). |
| `balancing_authority_code` | Balancing authority the generator sits in (ERCO, MISO, SWPP, PSCO, ...). |
| `balancing_authority_name` | Plain-text balancing authority name. |
| `operating_year_month` | Year-month the generator entered service. |
| `planned_retirement_year_month` | Year-month EIA records as the planned retirement. Null when none is filed. |
| `county` | County the plant is in. |
| `latitude` | Plant latitude, WGS84 decimal degrees. |
| `longitude` | Plant longitude, WGS84 decimal degrees. |
| `period` | Capacity month (YYYY-MM) the plant row is scoped to. |
| `planned_retirement_dates_before_period` | How many operating generators carry a planned-retirement date EARLIER than the capacity month. EIA files a few in-service dates into that column (Texas 2026-05: Jones units 3 and 4 at 1956-12 and 1958-12), so they are counted here and excluded from next\_planned\_retirement\_period rather than publishing a retirement date in 1956. |
| `pumped_storage_capacity_mw` | Operating nameplate capacity of hydroelectric PUMPED STORAGE - energy source WAT with prime mover PS. A net consumer of electricity (about 80% round-trip), so it is excluded from hydro, renewable and generation totals. 21,931.2 MW nationally in 2026-05. |
| `total_storage_capacity_mw` | All operating storage: battery\_storage\_capacity\_mw plus pumped\_storage\_capacity\_mw. |
| `biomass_capacity_mw` | Operating nameplate capacity across the biomass energy-source codes WDS, WDL, OBS, OBL, OBG, BLQ, AB, SLW and LFG. Counted inside renewable\_capacity\_mw from v1.2; v1.1 omitted it entirely. |
| `msw_capacity_mw` | Operating nameplate capacity with energy source code MSW. Reported on its own line and deliberately NOT counted as renewable: only part of MSW is biogenic and EIA does not publish the split in this dataset. |
| `geothermal_capacity_mw` | Operating nameplate capacity with energy source code GEO. Counted inside renewable\_capacity\_mw. |
| `petroleum_capacity_mw` | Operating nameplate capacity across DFO, RFO, KER, JF, PC, WO and TDF - mostly oil-fired peaking and black-start units. |
| `other_capacity_mw` | Operating megawatts that fall into none of the named classes (for example waste heat WH, purchased steam PUR, other OTH, or a row with no energy source code). Should be small; a large value means the fuel mapping no longer covers the state. |
| `fuel_classification_complete` | True when every operating megawatt in the state landed in a named fuel class (other\_capacity\_mw is zero). False means part of the state total is unclassified. |
| `capacity_by_prime_mover_mw` | Operating nameplate megawatts per EIA prime-mover code (ST, CT, GT, WT, PV, CA, HY, BA, PS, ...). This is what separates conventional hydro (HY) from pumped storage (PS) and batteries (BA) from flywheels (FW). |
| `top_generation_fuel` | EIA energy-source code with the largest operating nameplate capacity once storage (MWH) is excluded - the fuel a site would actually be buying from. |
| `operating_generator_count` | Number of generator records with status OP in the latest capacity period. generator\_count counts all statuses. |
| `storage_share_of_operating_capacity_pct` | total\_storage\_capacity\_mw as a percent of total\_nameplate\_capacity\_mw. |
| `petroleum_share_pct` | petroleum\_capacity\_mw as a percent of operating\_generation\_capacity\_mw. |
| `planned_uprate_capacity_mw` | Sum of planned-uprate summer capacity across operating generators that have an announced uprate. Null when no operating generator in the state publishes one. |
| `planned_uprate_generator_count` | Operating generators with an announced uprate date. |
| `next_planned_uprate_period` | Earliest announced uprate month among operating generators in the state. |
| `planned_derate_capacity_mw` | Sum of planned-derate summer capacity across operating generators that have an announced derate. Null when no operating generator in the state publishes one. |
| `planned_derate_generator_count` | Operating generators with an announced derate date. |
| `next_planned_derate_period` | Earliest announced derate month among operating generators in the state. |
| `capacity_rows_missing_fuel_code` | Generator rows EIA published with no energy\_source\_code. Their megawatts are in the state total and in other\_capacity\_mw, not in any fuel class. |
| `retail_window_start` | First month of the bounded retail-sales query, derived from the "months" input and EIA's published endPeriod. |
| `retail_window_end` | Last month of the bounded retail-sales query - EIA's published endPeriod for retail sales. |

### Output fields — `plant` rows (`includePlantDetail: true`)

Set `includePlantDetail: true` to also get one billable row per generator.

| Field | Meaning |
|---|---|
| `plantid` | EIA plant id. Present only on row\_type "plant" rows. |
| `plant_name` | Generating plant name. Present only on row\_type "plant" rows. |
| `fuel` | EIA energy-source code for the generator. Present only on row\_type "plant" rows. |
| `technology` | Generator technology description. Present only on row\_type "plant" rows. |
| `nameplate_mw` | Generator nameplate capacity in megawatts. Null when EIA publishes no value - never 0. |
| `is_storage` | True when the generator is a storage device rather than a generator: energy source MWH (battery/flywheel) or prime mover PS (pumped storage). Present only on row\_type "plant" rows. |
| `is_pumped_storage` | True when the generator is hydroelectric pumped storage (WAT + prime mover PS). Present only on row\_type "plant" rows. |
| `entity_id` | EIA entity (utility/operator) id - the join key to EIA Form 861 and ownership data. Fetched on every row since v1.0 and emitted from v1.2. Present only on row\_type "plant" rows. |
| `unit` | Generator unit designation as EIA publishes it. Present only on row\_type "plant" rows. |
| `sector_id` | Machine-readable EIA sector id (electric-utility, ipp-non-chp, industrial-chp, ...). Present only on row\_type "plant" rows. |
| `planned_uprate_year_month` | Announced uprate month for this generator, YYYY-MM. Present only on row\_type "plant" rows. |
| `planned_uprate_summer_cap_mw` | Summer capacity this generator is planned to reach. Present only on row\_type "plant" rows. |
| `planned_derate_year_month` | Announced derate month for this generator, YYYY-MM. Present only on row\_type "plant" rows. |
| `planned_derate_summer_cap_mw` | Summer capacity this generator is planned to fall to. Present only on row\_type "plant" rows. |

### Field coverage (verified live, full dataset, 2026-08-10)

Audited on the complete dataset of a healthy run using the Actor's own prefill
(`states: ["CO","TX"]`), not a sample:

- The `state_profile` prefill run populates every declared summary field except the ones that are structurally conditional: `error` (null on success — good news) and the `*_source_status` values that only read anything other than `ok` when a source is degraded.
- `planned_retirement_capacity_mw` / `next_planned_retirement_period` are null for a state where EIA files no retirement dates; Colorado 2026-05 has **26 generators** carrying one, so `{"states":["CO"]}` populates them.
- `planned_uprate_*` / `planned_derate_*` are EIA's own columns, not derived values, so a null means EIA published nothing — never 0 MW. The prefill populates both: Colorado carries 1 announced uprate (0.3 MW, 2027-10) and Texas the only announced derate in the country on 2026-05 data (Coleto Creek, 28 MW, 2026-12). `{"states":["SC"]}` is the densest uprate case — 23 generators, 222 MW.
- `pumped_storage_capacity_mw` reads a measured **0** in a state with no pumped storage (Texas, Vermont) and **508.5 MW** in Colorado; `{"states":["SC","VA"]}` shows the largest values in the country (3,041.2 and 3,109.3 MW).
- `msw_capacity_mw` and `geothermal_capacity_mw` are a measured 0 in the prefill states. `{"states":["NY","FL","MN"]}` populates MSW; `{"states":["CA","NV","HI"]}` populates geothermal.
- `other_capacity_mw` / `fuel_classification_complete`: Colorado carries 6.1 MW of waste heat and Texas 237.4 MW of waste heat plus purchased steam, so both prefill states report `fuel_classification_complete: false` with the residual named. South Carolina and Vermont report `true` and `0`.
- `plant` rows only exist when `includePlantDetail: true`. `{"states":["SC"],"includePlantDetail":true,"maxPlantRows":400}` is the recorded input that populates `is_pumped_storage: true` (16 of 395 generators — Jocassee, Bad Creek) and the uprate columns.
- `unit` is the one plant column EIA populates sparsely — **2,150 of 25,868** operating generators nationally (8.3%), concentrated in TX, CA, FL, NY and PA. `{"states":["TX"],"includePlantDetail":true}` is the recorded input that populates it. Null there means EIA files no unit designation, not that the generator has none.
- `net_summer_mw` is null on the handful of generators EIA publishes no net-summer value for — 6 of 508 in Colorado. That is "EIA has not published it", never 0 MW.

### Pricing

Pay-per-result: **$8.00 per 1,000 results** on the free tier, with graduated
paid-plan discounts (Bronze −20%, Silver −30%, Gold −45%, Platinum −60%,
Diamond −70%). One `state_profile` row per state; per-generator rows are billed
individually and are off by default. A run that fails a drift check, or that
cannot read EIA for any requested state, emits nothing and bills nothing.

### Use as an MCP tool

Callable by AI agents via **mcp.apify.com**. Every output field is described in
the schema, including the per-source status fields — so an agent can tell the
difference between "this state has no coal" and "capacity was not retrieved",
which is the distinction that makes an energy answer safe to act on.

### FAQ

**Where does the data come from?** The EIA v2 API: `electricity/retail-sales` for rates and `electricity/operating-generator-capacity` for the generation fleet. Both are first-party US government data.

**Is `total_nameplate_capacity_mw` the same as what the state can actually generate?** No. It is nameplate capacity of operating units, which is the plate rating. `net_summer_capacity_mw` is closer to what is dispatchable on a hot afternoon, and neither accounts for outages or fuel availability.

**Why is battery storage reported separately?** Because it is not generation. EIA files it under energy source code `MWH`; including it in a renewables share inflates the denominator and understates the answer.

**What does a null mean?** Not checked. A `0` means checked and genuinely zero. Every row carries `retail_source_status`, `capacity_source_status` and `partial_result` so the two are never confused.

**How current is it?** EIA publishes retail sales and generator capacity with roughly a two-month lag; `latest_period` and `capacity_period` state exactly which month each figure is from, and the run fails if the feed goes more than 8 months stale.

**Can I get every generator in a state?** Yes — `includePlantDetail: true`. Each row is billable, so `maxPlantRows` caps it. Colorado has ~508 generators in a month, Texas ~2,451.

### Related Actors

- **Interconnection Queue Tracker** — what is waiting to connect to the grid you just priced.
- **HIFLD Grid Proximity Screener** — distance from a specific coordinate to the nearest transmission line and substation.
- **EPA Nonattainment Air Permit Screener** — whether a thermal plant or generator at that site faces a stricter permitting threshold.

# Actor input Schema

## `apiKey` (type: `string`):

Free EIA v2 API key. Register in about a minute at https://www.eia.gov/opendata/register.php (no cost, no card). Supplying your own key gives you your own rate limit; leave it blank to use the Actor default key, which is shared across all users. If no key is available at all the run FAILS loudly with the registration URL and bills nothing - it does not return a green empty dataset. You may also set an EIA\_API\_KEY environment variable on the Actor.

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

Two-letter US state ids to build an electricity-economics profile for (e.g. "CO", "TX"). One billable state\_profile row per state. "US" is also accepted for the national aggregate. An id EIA does not publish is flagged state\_id\_recognized=false rather than returned as a state with zero capacity.

## `months` (type: `integer`):

How many months of retail-rate history to fetch per state. Used to find the latest month and compute the same-month year-over-year price change, so 13 is the minimum for one full YoY comparison. Does not affect the capacity rollup, which always uses the newest published month.

## `includePlantDetail` (type: `boolean`):

When true, also emit one billable row per GENERATOR (row\_type "plant") with plant name and id, operator, balancing authority, fuel, technology, prime mover, nameplate and net summer/winter capacity, in-service date, planned retirement date, county and lat/lon - capped by "Max plant rows". When false (default) only the one state\_profile summary row per state is returned.

## `maxPlantRows` (type: `integer`):

Safety cap on the number of per-generator rows emitted per state when "Include per-plant capacity rows" is true. Each row is billable. Ignored when that option is false.

## Actor input object example

```json
{
  "states": [
    "CO",
    "TX"
  ],
  "months": 24,
  "includePlantDetail": false,
  "maxPlantRows": 200
}
```

# 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",
        "TX"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("malonestar/eia-v2-site-energy-economics").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",
        "TX",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("malonestar/eia-v2-site-energy-economics").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",
    "TX"
  ]
}' |
apify call malonestar/eia-v2-site-energy-economics --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,malonestar/eia-v2-site-energy-economics"
        }
    }
}

```

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/NRVwKHavUUWC81rok/builds/chZtafZqtUZ3VHLhD/openapi.json
