EIA Electricity Data
Verified Jun 22, 2026 · tested with live keyed EIA API v2 pulls, electricity/retail-sales (annual price) and electricity/electric-power-operational-data (annual coal generation, fueltype COW, 2022)
The US Energy Information Administration (EIA) publishes the official US energy statistics. The electricity branch covers retail sales, prices, and revenue by state and customer sector; net generation and fuel consumption by fuel type; plant-level operating data; operable-generator inventory; and, via the SEDS and CO2 branches, the emission factors used to convert generation into carbon. It is the standard source for electricity-sector calibration, including the brown-electricity emission factor in Pedersen (2026). This page is the distilled access recipe.
- Cost: free, no paywall.
- API key: free but required (bare requests are rejected).
- Coverage: monthly/quarterly/annual electricity series by state and sector, generally from 2001; plant-level and hourly grid data on their own histories.
- Home: https://www.eia.gov/electricity/ · API docs: https://www.eia.gov/opendata/documentation.php
Access
Section titled “Access”Register a key
Section titled “Register a key”Get a free key at https://www.eia.gov/opendata/register.php (instant email).
Store it in the environment (e.g. .env as EIA_API_KEY=...); never hard-code
it. The same key works across all EIA branches (coal, natural gas, petroleum,
SEDS, …), not just electricity.
Pull a series (API v2)
Section titled “Pull a series (API v2)”API v2 is a browsable route tree. Each leaf /data/ endpoint takes one or more
data[] metrics, optional facets[...][] filters, and a frequency. Query the
parent route (no /data/) to discover the available data columns, facets,
and frequency values first.
import os, requestskey = os.environ["EIA_API_KEY"]r = requests.get( "https://api.eia.gov/v2/electricity/retail-sales/data/", params={ "api_key": key, "frequency": "annual", "data[0]": "price", "facets[stateid][]": "CA", "start": "2022", "end": "2023", "length": 5000, },)rows = r.json()["response"]["data"] # period/stateid/sectorid/price/price-unitsThe electricity sub-routes: retail-sales (sales, revenue, price, customers by
state and sector), electric-power-operational-data (generation and fuel
consumption by fuel type), rto (daily/hourly grid operations), facility-fuel
(individual plants), operating-generator-capacity, and
state-electricity-profiles. For emission factors and CO2, use the seds and
co2-emissions branches.
Gotchas (the ones that bite pipelines)
Section titled “Gotchas (the ones that bite pipelines)”The reason to read this page rather than the EIA docs. Verified against live keyed pulls on the date above.
- The
data[0]/facets[...][]brackets are real and must survive the shell. Withcurl, the[and]are glob metacharacters: the request silently returns an empty body until you pass-g(or--globoff). In Python’srequests, pass them as literal param keys ("data[0]": "price") and it works. A blank response is almost always this, not an auth failure. - You must name at least one
data[]metric. A leaf/data/call with nodata[0]=returns metadata-style output or an error, not the series. Pick the column (price,sales,revenue,customers,generation, …) explicitly. - 5000-row JSON cap, with a quiet warning. Each call returns at most 5000
rows; beyond that you get a
"warnings": [{"warning": "incomplete return"}]block and silently truncated data. Constrain withfacets,start/end, or paginate withoffset; do not trust an unpaginated bulk pull. - Codes, not labels, in facets. Fuel types are codes (
COW= all coal,NG= natural gas, …), sectors are numeric IDs, states are postal codes plus Census-region aggregates (e.g.location: 90Pacific). Pull the facet’s value list from the parent route before filtering. - Sales price is cents per kWh, sector-split.
retail-salespriceis in cents/kWh and is reported persectorid(residential, commercial, industrial, transportation, andALL); do not average sectors naively. Generation is in thousand megawatthours. - Some endpoints are deprecated mid-flight. The CO2 aggregates endpoint, for
example, is marked deprecated, see SEDS. Check the route’s
name/descriptionfor a redirect before standardizing a pipeline on it.
Endpoints you actually need
Section titled “Endpoints you actually need”Route (under /v2/electricity/) | What it is | Key data columns |
|---|---|---|
retail-sales | Sales, price, revenue, customers by state & sector | price, sales, revenue, customers |
electric-power-operational-data | Net generation & fuel use by fuel type | generation, total-consumption |
facility-fuel | Plant-level operations | generation, consumption |
operating-generator-capacity | Operable generator inventory | nameplate-capacity-mw |
rto | Daily/hourly grid demand & interchange | value |
Outside /electricity/: /seds/ (State Energy Data System, including emission
coefficients) and /co2-emissions/ for carbon.
Standard operations
Section titled “Standard operations”- Electricity prices:
retail-salesprice(cents/kWh); filter to onesectoridand state, and state the sample window. - Generation mix / emission factors:
electric-power-operational-datagenerationbyfueltypeid; convert to CO2 with the SEDS coefficient for the fuel and vintage you need. Pedersen (2026) calibrates its brown-electricity factor at ~0.82 kg CO2/kWh; EIA’s published coal factors run somewhat higher, so use the paper’s number only as its stated calibration, not as the EIA coal factor. - Always paginate or constrain to stay under the 5000-row cap, and keep the facet codes (fuel, sector, state) documented next to any aggregate.
Citation
Section titled “Citation”U.S. Energy Information Administration. Electricity data. Washington, DC: EIA. Cite the specific series or table and your access date, e.g. U.S. Energy Information Administration, Electricity retail sales (annual, by state and sector), accessed YYYY-MM-DD, https://www.eia.gov/opendata/.