Free Electricity Data API
A free, read only JSON API with 4 datasets and 5 endpoints, data to 2026-10-27.
There is no key and no server: each response is a static file at /api/v1/, rebuilt with every site build and
served with open CORS headers. Every payload carries the source attribution and licence you must keep.
The machine readable description is /api/v1/openapi.json (OpenAPI 3.1, 43 KB).
Key Facts
- Annual electricity generation, demand and emissions by country: 215 countries, 1985 to 2025, from Ember (CC BY 4.0).
- Monthly electricity generation and demand by country: 88 countries, 1999-01 to 2026-09, from Ember (CC BY 4.0).
- US grid region daily electricity demand and generation: 14 US grid regions, 2025-09-23 to 2026-10-27, from U.S. Energy Information Administration (US Government work, public domain).
- European cross border physical electricity flows: 88 borders, 2026-09-28 to 2026-10-27 (30 days), from ENTSO-E Transparency Platform (ENTSO-E Terms of Use plus CC BY 4.0 for listed data items).
- 5 endpoints, plus an index and an OpenAPI 3.1 description. Files are static and rebuilt with every site build.
- Ember statistics and operator data (EIA, ENTSO-E) are separate endpoints and are never merged into one figure.
Quick start
Real endpoint: /api/v1/countries/germany.json
Each sample fetches /api/v1/countries/germany.json, prints the latest values of total_generation_twh and demand_twh and
the attribution text. Field names and the endpoint come from the OpenAPI description, so they match the files exactly.
curl
curl -s https://worldpowermonitor.com/api/v1/countries/germany.json
curl -s https://worldpowermonitor.com/api/v1/countries/germany.json | jq '.annual | {years: .years[-5:], total_generation_twh: .total_generation_twh[-5:], demand_twh: .demand_twh[-5:]}'
curl -s https://worldpowermonitor.com/api/v1/countries/germany.json | jq -r '.attribution[0].attribution' Python (requests)
import requests
url = "https://worldpowermonitor.com/api/v1/countries/germany.json"
data = requests.get(url, timeout=30).json()
rows = list(zip(data["annual"]["years"], data["annual"]["total_generation_twh"]))
for year, value in rows[-5:]:
print(year, value) # total_generation_twh
print(data["attribution"][0]["attribution"]) JavaScript (fetch)
const res = await fetch("https://worldpowermonitor.com/api/v1/countries/germany.json");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
const { years, total_generation_twh, demand_twh } = data.annual;
console.log(years.at(-1), total_generation_twh.at(-1)); // latest total_generation_twh
console.log(data.attribution[0].attribution); R (jsonlite)
library(jsonlite)
d <- fromJSON("https://worldpowermonitor.com/api/v1/countries/germany.json")
df <- data.frame(years = d$annual$years, total_generation_twh = d$annual$total_generation_twh, demand_twh = d$annual$demand_twh)
tail(df)
d$attribution$attribution pandas one liner
import pandas as pd, requests
df = pd.DataFrame({k: v for k, v in requests.get("https://worldpowermonitor.com/api/v1/countries/germany.json", timeout=30).json()["annual"].items() if k in ("years", "total_generation_twh", "demand_twh")}).set_index("years") Try it
Same origin requests Without JavaScript, open an example directly:
Endpoints
Base https://worldpowermonitor.com| Path | Returns | Layer | Licence | Files |
|---|---|---|---|---|
| /api/v1/index.json | Datasets, coverage, cadence and attribution | Index | CC BY 4.0, US Government work, public domain, ENTSO-E Terms of Use plus CC BY 4.0 for listed data items | 1 |
| /api/v1/openapi.json | This OpenAPI 3.1 description | Index | Not data | 1 |
| /api/v1/countries.json | List of countries with a data file | Ember statistics | CC BY 4.0 | 1 |
/api/v1/countries/{id}.jsonexample: germany | Ember annual and monthly series for one country | Ember statistics | CC BY 4.0 | 215 |
| /api/v1/regions.json | List of US grid regions with a daily file | Operator data | US Government work, public domain | 1 |
/api/v1/regions/{id}.jsonexample: eia-texas | Daily demand and generation for one US grid region | Operator data | US Government work, public domain | 14 |
| /api/v1/europe/flows.json | Physical cross border flows between European zones | Operator data | ENTSO-E Terms of Use plus CC BY 4.0 for listed data items | 1 |
Country ids (215) are listed in /api/v1/countries.json , US grid region ids (14) in /api/v1/regions.json. An unknown id answers with the site 404 page, not JSON.
Response fields
Numbers are raw values, never formatted strings; the unit is in the field name (_twh, _mwh, _gw,
_pct, _mtco2, _gco2_kwh). A null is a value the source did not report. Every series in a block has one value per
entry of its time axis (years, months or dates), in the same order.
Attribution object (in every file) attribution
| Field | Type | Meaning |
|---|---|---|
| source | text | Source name. |
| source_url | text | Source home page. |
| attribution | text | The exact attribution text to copy. |
| licence | text | Licence name. |
| licence_url | text or null | Licence text, or null when the licence has no stable URL. |
Datasets, coverage, cadence and attribution /api/v1/index.json
| Field | Type | Meaning |
|---|---|---|
| api_version | text | Always v1 for these files. |
| publisher | text | Publisher name, World Power Monitor. |
| docs | text | URL of the documentation page. |
| openapi | text | URL of this OpenAPI document. |
| note | text | Scope note. |
| datasets[] | object list | One entry per dataset in this build. |
| datasets[].id | text | Dataset id. |
| datasets[].name | text | Dataset name. |
| datasets[].coverage | text | Coverage in words. |
| datasets[].as_of | text | Last year, month or day in the dataset. |
| datasets[].temporal_coverage | text | Time span as ISO 8601 start/end. |
| datasets[].update_cadence | text | How often the source publishes and when the files change. |
| datasets[].changes | text | What World Power Monitor changed from the source. |
| datasets[].attribution | object | |
| datasets[].endpoints[] | object list | Endpoints that serve this dataset. |
| datasets[].endpoints[].path | text | Path template. |
| datasets[].endpoints[].url | text | Full URL or URL template. |
| datasets[].endpoints[].summary | text | What it returns. |
List of countries with a data file /api/v1/countries.json
| Field | Type | Meaning |
|---|---|---|
| api_version | text | Always v1 for these files. |
| publisher | text | Publisher name, World Power Monitor. |
| attribution[] | object list | Attribution for the datasets behind the country files. |
| note | text | Scope note. |
| countries[] | object list | One entry per country. |
| countries[].id | text | Country id: the slug in /countries/<id>/ and the file name. |
| countries[].name | text | Country or region name. |
| countries[].iso3 | text or null | ISO 3166-1 alpha-3 code; null for aggregates such as World or EU. |
| countries[].latest_annual_year | integer or null | Latest year with annual generation data. |
| countries[].latest_month | text or null | Latest month with monthly data (YYYY-MM); null when the country has no monthly series. |
| countries[].endpoint | text | URL of the country file. |
| countries[].page | text | URL of the country page on this site. |
Ember annual and monthly series for one country /api/v1/countries/{id}.json
| Field | Type | Meaning |
|---|---|---|
| api_version | text | Always v1 for these files. |
| publisher | text | Publisher name, World Power Monitor. |
| id | text | Country id. |
| name | text | Country or region name. |
| iso3 | text or null | ISO 3166-1 alpha-3 code; null for aggregates. |
| page | text | URL of the country page on this site. |
| attribution[] | object list | Ember attribution; keep it with any copy. |
| note | text | How to read the numbers. |
| annual | object or or null | Annual series, or null when that dataset is not offered. |
| annual.dataset | text | Dataset id. |
| annual.as_of | text | Last year in the block. |
| annual.changes | text | What World Power Monitor changed from the source. |
| annual.years | integer list | Calendar years, ascending. |
| annual.total_generation_twh | number or null list | Total electricity generation, TWh. |
| annual.demand_twh | number or null list | Electricity demand, TWh. |
| annual.demand_per_capita_mwh | number or null list | Electricity demand per person, MWh. |
| annual.net_imports_twh | number or null list | Net electricity imports, TWh; negative means net exports. |
| annual.carbon_intensity_gco2_kwh | number or null list | Carbon intensity of generation, gCO2 per kWh. |
| annual.total_emissions_mtco2 | number or null list | Power sector emissions, MtCO2. |
| annual.generation_twh | object | Generation by fuel, TWh. Keys are fuel ids (coal, gas, oil, other_fossil, nuclear, hydro, wind, solar, bioenergy, geothermal, other_renewables, storage, other); only fuels with data for this file appear. |
| annual.share_pct | object | Share of generation by fuel, percent. Keys are fuel ids (coal, gas, oil, other_fossil, nuclear, hydro, wind, solar, bioenergy, geothermal, other_renewables, storage, other); only fuels with data for this file appear. |
| annual.capacity_gw | object | Installed capacity by fuel, GW; empty when Ember has none for the country. Keys are fuel ids (coal, gas, oil, other_fossil, nuclear, hydro, wind, solar, bioenergy, geothermal, other_renewables, storage, other); only fuels with data for this file appear. |
| annual.emissions_mtco2 | object | Emissions by fuel, MtCO2. Keys are fuel ids (coal, gas, oil, other_fossil, nuclear, hydro, wind, solar, bioenergy, geothermal, other_renewables, storage, other); only fuels with data for this file appear. |
| monthly | object or or null | Monthly series, or null when the country has none. |
| monthly.dataset | text | Dataset id. |
| monthly.as_of | text | Last month in the block (YYYY-MM). |
| monthly.changes | text | What World Power Monitor changed from the source. |
| monthly.months | text list | Months as YYYY-MM, ascending. |
| monthly.demand_twh | number or null list | Electricity demand, TWh. |
| monthly.carbon_intensity_gco2_kwh | number or null list | Carbon intensity of generation, gCO2 per kWh. |
| monthly.generation_twh | object | Generation by fuel, TWh. Keys are fuel ids (coal, gas, oil, other_fossil, nuclear, hydro, wind, solar, bioenergy, geothermal, other_renewables, storage, other); only fuels with data for this file appear. |
List of US grid regions with a daily file /api/v1/regions.json
| Field | Type | Meaning |
|---|---|---|
| api_version | text | Always v1 for these files. |
| publisher | text | Publisher name, World Power Monitor. |
| attribution | object | |
| note | text | Scope note. The Lower 48 region overlaps the others; do not add them together. |
| regions[] | object list | One entry per region. |
| regions[].id | text | Region id: the file name. |
| regions[].name | text | Region name. |
| regions[].first_day | text or null | First day in the file (YYYY-MM-DD). |
| regions[].last_day | text or null | Last day in the file (YYYY-MM-DD). |
| regions[].endpoint | text | URL of the region file. |
Daily demand and generation for one US grid region /api/v1/regions/{id}.json
| Field | Type | Meaning |
|---|---|---|
| api_version | text | Always v1 for these files. |
| dataset | text | Dataset id. |
| publisher | text | Publisher name, World Power Monitor. |
| attribution | object | |
| changes | text | What World Power Monitor changed from the source. |
| id | text | Region id. |
| name | text | Region name. |
| as_of | text | Last day in the file. |
| timezone | text | Time zone label of the daily boundaries, as published by EIA (for example Central). |
| note | text | How to read the numbers. |
| first_day | text | First day in the file. |
| last_day | text | Last day in the file. |
| dates | text list | One date per day, ascending, no gaps. |
| demand_mwh | number or null list | Electricity demand per day, MWh; null where missing or reported as exactly zero. |
| net_generation_mwh | number or null list | Net generation per day, MWh; null where missing or reported as exactly zero. |
| interchange_mwh | number or null list | Net interchange with neighbouring regions per day, MWh. |
| generation_mwh | object | Net generation by fuel per day, MWh; null where EIA reported none. Keys are fuel ids (coal, gas, oil, other_fossil, nuclear, hydro, wind, solar, bioenergy, geothermal, other_renewables, storage, other); only fuels with data for this file appear. |
Physical cross border flows between European zones /api/v1/europe/flows.json
| Field | Type | Meaning |
|---|---|---|
| api_version | text | Always v1 for these files. |
| dataset | text | Dataset id. |
| publisher | text | Publisher name, World Power Monitor. |
| attribution | object | |
| changes | text | What World Power Monitor changed from the source. |
| as_of | text | Last day of the window. |
| period_start | text | First day of the window. |
| period_end | text | Last day of the window. |
| days | integer | Days in the window. |
| note | text | How to read the flows. |
| borders[] | object list | One entry per border. |
| borders[].zone_a | text | First zone id. |
| borders[].zone_a_name | text | First zone name. |
| borders[].zone_b | text | Second zone id. |
| borders[].zone_b_name | text | Second zone name. |
| borders[].a_to_b_mwh | number or null | Energy that flowed from A to B, MWh. |
| borders[].b_to_a_mwh | number or null | Energy that flowed from B to A, MWh. |
| borders[].net_a_to_b_mwh | number or null | Net flow, MWh; positive when the net flow goes from A to B. |
| zones[] | object list | One entry per zone. |
| zones[].zone_id | text | Zone id. |
| zones[].zone | text | Zone name. |
| zones[].exports_mwh | number or null | Total exports, MWh. |
| zones[].imports_mwh | number or null | Total imports, MWh. |
| zones[].net_exports_mwh | number or null | Exports minus imports, MWh. |
Datasets, licences and update cadence
Data as of 2026-10-27| Dataset | Coverage | Licence | Update cadence |
|---|---|---|---|
| Annual electricity generation, demand and emissions by country | 215 countries, 1985 to 2025 | CC BY 4.0 | Ember publishes annual figures as national statistics arrive, mostly once a year, with revisions. The files are rebuilt from the latest Ember release with every site build. |
| Monthly electricity generation and demand by country | 88 countries, 1999-01 to 2026-09 | CC BY 4.0 | Ember adds a month of data as national sources publish it, usually a month or two after the month ends. The file is rebuilt from the latest release with every site build. |
| US grid region daily electricity demand and generation | 14 US grid regions, 2025-09-23 to 2026-10-27 | US Government work, public domain | EIA publishes hourly grid data with a lag of about one hour for demand and up to 13 hours for generation by fuel. Daily totals are rebuilt with every site build and cover a rolling window of about 400 days. |
| European cross border physical electricity flows | 88 borders, 2026-09-28 to 2026-10-27 (30 days) | ENTSO-E Terms of Use plus CC BY 4.0 for listed data items | A rolling 30 day window, rebuilt with every site build from the latest ENTSO-E physical flow data. |
Attribution you must keep
Every file carries an attribution field. Keep it, or the line below for each source you use, with any copy or derived work
(a chart, an app screen, a dataset). It is the same text as on every dataset page. Ember statistics (countries) and operator data
(EIA, ENTSO-E) are separate layers: credit each one where you show it, and do not add figures from the two layers into one number.
Ember Ember statistics
Source: Ember (ember-energy.org), licensed under CC BY 4.0.
Licence: CC BY 4.0. Source: https://ember-energy.org/. Covers Annual electricity generation, demand and emissions by country; Monthly electricity generation and demand by country.
U.S. Energy Information Administration Operator data
Source: U.S. Energy Information Administration (EIA).
Licence: US Government work, public domain. Source: https://www.eia.gov/. Covers US grid region daily electricity demand and generation.
ENTSO-E Transparency Platform Operator data
Source: ENTSO-E Transparency Platform (transparency.entsoe.eu), CC BY 4.0. Aggregated and converted by World Power Monitor; ENTSO-E does not endorse this site.
Licence: ENTSO-E Terms of Use plus CC BY 4.0 for listed data items. Source: https://transparency.entsoe.eu/. Covers European cross border physical electricity flows.
Only datasets whose licence allows republishing are served; other series on the site are not available here.
OpenAPI description
https://worldpowermonitor.com/api/v1/openapi.json is an OpenAPI 3.1 document (43 KB) generated at build time from the code that
writes the files: paths, id patterns, response schemas with units, licence and attribution per dataset, cache headers and a real example for every endpoint.
It is open to any website (CORS) and has no tracking or external references. This page embeds no third party viewer; import the URL into a tool you trust.
- Postman. Import, choose Link, paste
https://worldpowermonitor.com/api/v1/openapi.json, then Continue and Import. It creates a collection with one request per path. - Insomnia. Create, Import, From URL, and paste the same address.
- Swagger Editor, Swagger UI or Redoc. Open your own copy or the tool's hosted page, and load the same address with its import or URL field.
- Code generation. Point an OpenAPI 3.1 generator at the address to get typed clients. Support for 3.1 varies by tool; if an older tool rejects the document, the endpoint and field tables on this page cover the same ground.
The same address is advertised in a Link: rel="service-desc" response header on this page, as RFC 8631 describes.
Versioning, caching and limits
- Version. The version is in the path:
/api/v1/. These are the v1 files. - Not breaking. Adding fields, endpoints, datasets, ids or fuel keys; new values with each rebuild (Ember revises past figures, and files always follow the latest release). Ignore fields you do not know.
- Breaking. Removing or renaming a path or field, changing a unit or a type, or changing what a field means. That would ship as
/api/v2/. A dataset can also be withdrawn if its licence stops allowing republishing, and its files would then be gone. - No guarantee. There is no service level agreement, uptime or latency promise. The files are static and served from the Cloudflare edge.
- Caching. Responses send
Access-Control-Allow-Origin: *andCache-Control: public, max-age=300, s-maxage=3600. Files change at most once per site build, so poll no more than hourly. - Limits. This site sets no quota and issues no keys. Please cache what you fetch.
- Missing values. A null is a value the source did not report. Days of exactly zero regional demand are reported as null, not zero.
- As of dates. Every file states its own
as_ofand, inchanges, what was done to the source data.
Source: Ember (ember-energy.org), licensed under CC BY 4.0. Source: U.S. Energy Information Administration (EIA). (US Government work, public domain) Source: ENTSO-E Transparency Platform (transparency.entsoe.eu), CC BY 4.0. Aggregated and converted by World Power Monitor; ENTSO-E does not endorse this site. (ENTSO-E Terms of Use plus CC BY 4.0 for listed data items) Data as of 2026-10-27. Each dataset has its own as-of date.