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

Start typing an id, or pick one from the list. Ids are the page slugs, for example germany.

Endpoints

Base https://worldpowermonitor.com
PathReturnsLayerLicenceFiles
/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
FieldTypeMeaning
sourcetextSource name.
source_urltextSource home page.
attributiontextThe exact attribution text to copy.
licencetextLicence name.
licence_urltext or nullLicence text, or null when the licence has no stable URL.
Datasets, coverage, cadence and attribution /api/v1/index.json
FieldTypeMeaning
api_versiontextAlways v1 for these files.
publishertextPublisher name, World Power Monitor.
docstextURL of the documentation page.
openapitextURL of this OpenAPI document.
notetextScope note.
datasets[]object listOne entry per dataset in this build.
datasets[].idtextDataset id.
datasets[].nametextDataset name.
datasets[].coveragetextCoverage in words.
datasets[].as_oftextLast year, month or day in the dataset.
datasets[].temporal_coveragetextTime span as ISO 8601 start/end.
datasets[].update_cadencetextHow often the source publishes and when the files change.
datasets[].changestextWhat World Power Monitor changed from the source.
datasets[].attributionobject
datasets[].endpoints[]object listEndpoints that serve this dataset.
datasets[].endpoints[].pathtextPath template.
datasets[].endpoints[].urltextFull URL or URL template.
datasets[].endpoints[].summarytextWhat it returns.
List of countries with a data file /api/v1/countries.json
FieldTypeMeaning
api_versiontextAlways v1 for these files.
publishertextPublisher name, World Power Monitor.
attribution[]object listAttribution for the datasets behind the country files.
notetextScope note.
countries[]object listOne entry per country.
countries[].idtextCountry id: the slug in /countries/<id>/ and the file name.
countries[].nametextCountry or region name.
countries[].iso3text or nullISO 3166-1 alpha-3 code; null for aggregates such as World or EU.
countries[].latest_annual_yearinteger or nullLatest year with annual generation data.
countries[].latest_monthtext or nullLatest month with monthly data (YYYY-MM); null when the country has no monthly series.
countries[].endpointtextURL of the country file.
countries[].pagetextURL of the country page on this site.
Ember annual and monthly series for one country /api/v1/countries/{id}.json
FieldTypeMeaning
api_versiontextAlways v1 for these files.
publishertextPublisher name, World Power Monitor.
idtextCountry id.
nametextCountry or region name.
iso3text or nullISO 3166-1 alpha-3 code; null for aggregates.
pagetextURL of the country page on this site.
attribution[]object listEmber attribution; keep it with any copy.
notetextHow to read the numbers.
annualobject or or nullAnnual series, or null when that dataset is not offered.
annual.datasettextDataset id.
annual.as_oftextLast year in the block.
annual.changestextWhat World Power Monitor changed from the source.
annual.yearsinteger listCalendar years, ascending.
annual.total_generation_twhnumber or null listTotal electricity generation, TWh.
annual.demand_twhnumber or null listElectricity demand, TWh.
annual.demand_per_capita_mwhnumber or null listElectricity demand per person, MWh.
annual.net_imports_twhnumber or null listNet electricity imports, TWh; negative means net exports.
annual.carbon_intensity_gco2_kwhnumber or null listCarbon intensity of generation, gCO2 per kWh.
annual.total_emissions_mtco2number or null listPower sector emissions, MtCO2.
annual.generation_twhobjectGeneration 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_pctobjectShare 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_gwobjectInstalled 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_mtco2objectEmissions 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.
monthlyobject or or nullMonthly series, or null when the country has none.
monthly.datasettextDataset id.
monthly.as_oftextLast month in the block (YYYY-MM).
monthly.changestextWhat World Power Monitor changed from the source.
monthly.monthstext listMonths as YYYY-MM, ascending.
monthly.demand_twhnumber or null listElectricity demand, TWh.
monthly.carbon_intensity_gco2_kwhnumber or null listCarbon intensity of generation, gCO2 per kWh.
monthly.generation_twhobjectGeneration 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
FieldTypeMeaning
api_versiontextAlways v1 for these files.
publishertextPublisher name, World Power Monitor.
attributionobject
notetextScope note. The Lower 48 region overlaps the others; do not add them together.
regions[]object listOne entry per region.
regions[].idtextRegion id: the file name.
regions[].nametextRegion name.
regions[].first_daytext or nullFirst day in the file (YYYY-MM-DD).
regions[].last_daytext or nullLast day in the file (YYYY-MM-DD).
regions[].endpointtextURL of the region file.
Daily demand and generation for one US grid region /api/v1/regions/{id}.json
FieldTypeMeaning
api_versiontextAlways v1 for these files.
datasettextDataset id.
publishertextPublisher name, World Power Monitor.
attributionobject
changestextWhat World Power Monitor changed from the source.
idtextRegion id.
nametextRegion name.
as_oftextLast day in the file.
timezonetextTime zone label of the daily boundaries, as published by EIA (for example Central).
notetextHow to read the numbers.
first_daytextFirst day in the file.
last_daytextLast day in the file.
datestext listOne date per day, ascending, no gaps.
demand_mwhnumber or null listElectricity demand per day, MWh; null where missing or reported as exactly zero.
net_generation_mwhnumber or null listNet generation per day, MWh; null where missing or reported as exactly zero.
interchange_mwhnumber or null listNet interchange with neighbouring regions per day, MWh.
generation_mwhobjectNet 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
FieldTypeMeaning
api_versiontextAlways v1 for these files.
datasettextDataset id.
publishertextPublisher name, World Power Monitor.
attributionobject
changestextWhat World Power Monitor changed from the source.
as_oftextLast day of the window.
period_starttextFirst day of the window.
period_endtextLast day of the window.
daysintegerDays in the window.
notetextHow to read the flows.
borders[]object listOne entry per border.
borders[].zone_atextFirst zone id.
borders[].zone_a_nametextFirst zone name.
borders[].zone_btextSecond zone id.
borders[].zone_b_nametextSecond zone name.
borders[].a_to_b_mwhnumber or nullEnergy that flowed from A to B, MWh.
borders[].b_to_a_mwhnumber or nullEnergy that flowed from B to A, MWh.
borders[].net_a_to_b_mwhnumber or nullNet flow, MWh; positive when the net flow goes from A to B.
zones[]object listOne entry per zone.
zones[].zone_idtextZone id.
zones[].zonetextZone name.
zones[].exports_mwhnumber or nullTotal exports, MWh.
zones[].imports_mwhnumber or nullTotal imports, MWh.
zones[].net_exports_mwhnumber or nullExports minus imports, MWh.

Datasets, licences and update cadence

Data as of 2026-10-27
DatasetCoverageLicenceUpdate 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: * and Cache-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_of and, in changes, 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.