gridcarbon

Methodology

Version v1

gCO2eq / kWh

How the numbers are made

Every figure this API returns is derived, not measured. This page states exactly how — and where the derivation is weakest. If something here changes your mind about using it, that is the page working.

This page exists so you can decide whether to trust our numbers, and — more importantly — so you can work out where they are wrong. Every carbon-intensity figure on the internet is a model. Most of them hide the model. This one is written down: the formula, the emission factors, the timestamp conventions, the revision behaviour, and a list of the biases we know we have and have not fixed yet.

If you only read one thing, read Great Britain is measured differently and Known limitations and biases.

Status: pre-alpha. The archive begins at 2026-08-21T11:00:00Z and grows by one hour every hour. There are no API keys, no rate limits, no pricing and no SLA yet. Values are recomputed in place and can change under you (see Revisions). If you need a number you can defend in an audit, snapshot it yourself when you read it.

§ 1At a glance

At a glance

UnitgCO2eq/kWh
BasisLifecycle (cradle-to-grave) for the 44 computed zones; operational (combustion-only) for GB
PerspectiveProduction-based. Generation inside the zone only. Imports and exports are not modelled.
Zones45 — 33 European bidding zones, 11 US balancing authorities/aggregates, 1 GB
TimestampsUTC, ISO 8601, interval start
Granularity60 min for all computed zones; 30 min for GB
CollectionCloudflare Worker cron, hourly at minute :07 UTC, 72-hour trailing re-pull
Method tagscomputed:v1, upstream:uk-neso:actual, upstream:uk-neso:forecast
Primary factor sourceIPCC AR5 WGIII (2014) Annex III, Table A.III.2 — median lifecycle values

Every row returned by the API carries a method field. Branch on it. It is the only thing that tells you whether a number came out of our formula or straight off an upstream operator's own, differently-defined model.

§ 2Data sources and cadence

Data sources and cadence

SourceZonesWhat we pullUpstream publicationOur pollObserved lag
ENTSO-E Transparency Platform33 European bidding zonesA75 Actual Generation per Production Type, processType=A16, all psrTypesTarget H+1 after the MTU closes; several TSOs run lateHourly, per zone, 72 h window2–4 h
U.S. Energy Information Administration (EIA)11 US BAs and aggregateselectricity/rto/fuel-type-data, frequency=hourly (UTC), all fuel typesNear-real-time feed, 1–3 h nominal, in practice much worseHourly, all respondents in one paged request, 72 h window11–14 h
NESO Carbon Intensity APIGB/intensity/{from}/{to} — the published intensity series itself, not a generation mix30-minute settlement periods; actual backfills over 0.5–2 hHourly, 72 h window1–2 h

The lag column is what we actually measured across all 45 zones at 2026-08-25T15:52Z, not what the documentation promises. EU zones were 1.9–3.9 h behind, US zones 10.9–13.9 h behind, GB 1.4 h behind. The US lag is the single biggest disappointment in this dataset. EIA-930's nominal 1–3 h delay is not what arrives at our collector; plan around half a day, not three hours.

Nothing is fetched on the read path. A request to the API is a lookup against a table that the cron job filled in earlier, served from the edge with cache-control: max-age=300 on /v1/intensity/latest, 600 on /v1/intensity, and 3600 on /v1/zones. So a cached response can be up to five more minutes stale than the numbers above.

Fetch reliability

  • ENTSO-E: 45-second timeout, one retry on timeout or 5xx, no retry on 429 (rate-limiting is a signal to back off, not to push harder). Zones are fetched serially and persisted in chunks of ten, so a mid-run failure loses at most the current chunk.
  • EIA: 30-second timeout, single paged request covering every respondent, capped at 10 pages × 5,000 rows.
  • NESO: 30-second timeout.
  • A failure is recorded per-source and per-zone in an internal fetch log and simply leaves a hole. We never interpolate, never carry forward, and never substitute a neighbouring zone. A missing hour is missing.

§ 3How a zone's intensity is computed

How a zone's intensity is computed

For a zone and an hour, over the production types f reported for that hour:

              Σ  m_f · e_f
I  =  ────────────────────────      where the sum runs over every f with m_f > 0
              Σ  m_f                that is not in the zone's excluded set
  • m_f — average power for that production type over the interval, in MW.
  • e_f — the lifecycle emission factor for that production type, in gCO2eq/kWh, from the table below.
  • The result is rounded to one decimal place.
  • If the denominator is zero — no positive, non-excluded generation at all — no row is written. You get a gap, not a zero.

Because both m_f and e_f are per-unit-energy quantities over the same interval, the MW/MWh distinction cancels and no unit conversion is needed. ENTSO-E reports average MW per market time unit; EIA reports MWh over an hour, which is numerically the same as average MW.

Four rules that do the real work

1. Negative generation is dropped, not clamped into the denominator. Pumped-storage pumping and battery charging appear as negative values (EIA), or as separate consumption-side time series (ENTSO-E outBiddingZone_Domain, which we skip at parse time). Anything that is not strictly greater than zero is excluded from both the numerator and the denominator. Treating charging as negative generation would be a load, not a source; treating it as zero-carbon generation would manufacture clean electricity out of nothing.

2. Storage discharge is excluded from both sums. ENTSO-E B10 (pumped storage), B25 (energy storage); EIA PS, BAT, UES, OES. These carry factor = null and the policy exclude_from_mix.

This is a decision, not a fact, so here is the reasoning. Storage is not a primary source — a pumped-storage plant discharges electricity that came off the grid some hours earlier, minus roughly 25% round-trip loss. Assigning it 0 gCO2eq/kWh would dilute the mix and invent zero-carbon power. Assigning it the grid average creates a self-reference. Removing it from both sums is arithmetically identical to assigning it the weighted average intensity of everything else generating in the same interval, resolves in a single pass, and has no circularity.

What it gets wrong: it ignores the ~25% round-trip loss, and it ignores time-shifting — power pumped at 03:00 on a coal-heavy grid and released at 19:00 is charged the 19:00 average rather than the 03:00 one. Electricity Maps does this better, with flow-traced charging-hour intensity. We do not, yet.

3. Exclusion is applied before the unknown-fuel fallback. This ordering is load-bearing. A production type we do not recognise falls back to B20 Other / OTH at 700 gCO2eq/kWh. If storage codes fell through to that fallback instead of being excluded first, evening intensity in pumped-storage-heavy zones such as AT and CH would roughly double. Storage codes are matched against the exclusion set first and never reach the fallback.

4. Unknown codes fail loud, not silent. Upstream operators add fuel codes without warning — EIA added BAT, PS, SNB, UES in October 2024. An unrecognised code is priced at the 700 g "unidentified thermal" fallback. If even that fallback is missing from the table, the collector throws and the hour is not written. We would rather lose an hour than publish a number that quietly dropped a fuel out of the denominator.

Zone-specific override

There is currently exactly one. US-CAISO OTH is treated as storage and excluded. CISO reports no BAT rows at all — zero over 30 days when we checked on 2026-08-24 — and its OTH series swings between −9.4 and +9.0 GWh, which is a battery charging and discharging, not a fuel. CISO reports geothermal separately as GEO, so its OTH is storage-dominated. Left in at 700 g, it would inflate California's evening peak. This override should be removed if CISO starts reporting BAT properly.

A worked example

Illustrative, not a real hour. A zone reports:

Production typeMWFactorgCO2eq contribution
B19 Wind Onshore12,00011132,000
B16 Solar8,00048384,000
B04 Fossil Gas6,0004902,940,000
B05 Fossil Hard coal4,0008203,280,000
B01 Biomass5,0002301,150,000
B11 Hydro Run-of-river1,5002436,000
B10 Hydro Pumped Storage (discharge)2,000excluded
Total counted36,5007,922,000

7,922,000 / 36,500 = 217.04 → published as 217.0 gCO2eq/kWh.

Had the 2,000 MW of pumped storage been counted as zero-carbon generation, the same hour would read 205.8 — 5.2% lower. That gap is the entire content of decision (2) above, and it is why the policy is documented rather than buried.

§ 4Emission factors

Emission factors

Basis: lifecycle (cradle-to-grave). Wind, solar, nuclear and hydro are not zero. The primary source is IPCC AR5 WGIII (2014), Annex III, Table A.III.2, median values — the most widely cited harmonised LCA set, and the same basis Electricity Maps uses for its lifecycle numbers, so our figures are comparable to theirs. Every value below was re-extracted from the AR5 PDF and checked line by line against the published table on 2026-08-24; the full audit trail lives in the repository at research/factors.md and research/factors.json.

ENTSO-E production types (psrType)

CodeNamegCO2eq/kWhSourceNote
B01Biomass230AR5 median, dedicated biomass (130–420)Assumes sustainable feedstock accounting
B02Fossil Brown coal/Lignite820AR5 coal-PC median (proxy)Known underestimate — lignite runs ~1000–1200 direct
B03Fossil Coal-derived gas490AR5 gas-CC median (proxy)Blast-furnace gas is dirtier; volumes tiny
B04Fossil Gas490AR5 gas-CC median (410–650)UNECE 2022: 403–513. OCGT peakers run higher
B05Fossil Hard coal820AR5 coal-PC median (740–910)UNECE 2022: 751–1095
B06Fossil Oil650UK POST (2006)AR5 has no oil row
B07Fossil Oil shale820AR5 coal median (proxy)Known underestimate — ~950–1100. No covered zone burns it at scale
B08Fossil Peat820AR5 coal median (proxy)Known underestimate — peat ≥ lignite. Mainly FI/IE
B09Geothermal38AR5 median (6–79)Site-specific; some reservoirs exceed 100
B10Hydro Pumped StorageexcludedProject policyStorage discharge; out of numerator and denominator
B11Hydro Run-of-river24AR5 hydropower median (1–2200)Run-of-river is typically lower; 24 is conservative
B12Hydro Water Reservoir24AR5 hydropower median (1–2200)Reservoir methane makes this extremely site-specific
B13Marine17AR5 ocean median (5.6–28)We diverge from Electricity Maps, which maps this to 700
B14Nuclear12AR5 median (3.7–110)UNECE 2022: 5.1–6.4 — AR5 is on the high side
B15Other renewable230Biomass proxy (policy)Mostly biogas/landfill/sewage gas. EM maps this to 700
B16Solar48AR5 utility-scale PV median (18–180)AR5 rooftop median is 41; modern PV is materially lower
B17Waste540Zero Waste Europe (2020)Fossil (plastics) fraction counted. EM uses 230
B18Wind Offshore12AR5 median (8–35)UNECE 2022: 12–23
B19Wind Onshore11AR5 median (7–56)UNECE 2022: 7.8–16
B20Other700Electricity Maps unknownAssumes unidentified thermal. Also the fallback for new codes
B21AC LinkskippedENTSO-E code listGrid asset, not a production type
B22DC LinkskippedENTSO-E code listGrid asset, not a production type
B23SubstationskippedENTSO-E code listGrid asset, not a production type
B24TransformerskippedENTSO-E code listGrid asset, not a production type
B25Energy storageexcludedProject policyGrid batteries; same treatment as B10

EIA-930 fuel types

CodeNamegCO2eq/kWhSourceNote
COLCoal820AR5 coal-PC medianUS fleet is bituminous/sub-bituminous PC
NGNatural gas490AR5 gas-CC medianUS upstream methane leakage may push the true value higher
NUCNuclear12AR5 median
OILPetroleum650UK POST (2006)Mostly peakers; small volumes
SUNSolar48AR5 utility-scale PV medianEIA-930 is utility-scale only — rooftop PV is absent entirely
WATHydro24AR5 hydropower medianPre-2024 data nets pumped storage into WAT; negative hours dropped
WNDWind11AR5 onshore medianUS fleet is >99% onshore
OTHOther700Electricity Maps unknownMixes biomass, geothermal, waste, batteries and masked plants
BATBattery StorageexcludedProject policyEIA code since 2024-10
PSPumped StorageexcludedProject policyEIA code since 2024-10, split out of WAT
UESUnknown Energy StorageexcludedProject policyEIA code since 2024-10
OESOther Energy StorageexcludedProject policyConfirmed against the live facet endpoint
SNBSolar + integrated battery48Priced as SUNReal solar co-located with storage
WNBWind + integrated battery11Priced as WNDConfirmed against the live facet endpoint
GEOGeothermal38AR5 medianConfirmed against the live facet endpoint
UNKUnknown700Same as OTHUnidentified generation

Where we deliberately disagree with Electricity Maps

Because the AR5 baseline is shared, these are the only places our numbers can diverge from theirs for the same mix, and each one is a judgement call we are prepared to defend:

  • Waste (B17): 540 vs their 230. Municipal waste is roughly half fossil plastics. Pricing an incinerator as biomass ignores that. Genuine uncertainty here is wide — somewhere in 230–700 depending on fossil share and biogenic-CO2 convention.
  • Marine (B13): 17 vs their 700. They bucket tidal and wave into "unknown thermal". That is an engineering fallback, not an LCA judgement.
  • Other renewable (B15): 230 vs their 700. The category is dominated by biogas and landfill gas. It is renewable; 700 is indefensible for it.
  • Solar: 48 vs their blended 45. Immaterial (<7%), and both are too high for modern panels.

§ 5Great Britain is measured differently

Great Britain is measured differently

Do not compare GB against any other zone in this API. Not in a chart, not in a "which region is cleanest" ranking, not in a Scope 2 comparison. The numbers are not on the same scale.

For the 44 computed zones we apply the formula and factors above. For GB we do not compute anything — we republish the value that the NESO Carbon Intensity API publishes, and tag it upstream:uk-neso:actual or upstream:uk-neso:forecast.

NESO's model differs from ours on two independent axes:

Axis 1 — operational, not lifecycle. NESO uses combustion-only emission factors. In their published table, wind, solar, nuclear, hydro and pumped storage are all exactly 0. Ours are 11, 48, 12, 24 and excluded respectively. Their fossil factors are also different numbers on a different basis: coal 937, oil 935, OCGT 651, CCGT 394, biomass 120, other 300.

The practical effect: a clean GB hour reads lower than the same physical mix would read anywhere else in this API, and a dirty GB hour can read higher. On a windy night GB approaches 0 in a way that is structurally impossible for a lifecycle zone — our floor is the low tens even for pure hydro or pure wind. We have seen NESO report a GB regional intensity of exactly 0 gCO2/kWh.

Axis 2 — imports are counted. NESO prices interconnector imports with per-country factors (French imports 53, Dutch 474, Irish 458). Our computed zones ignore cross-border flow entirely. So GB is partly consumption-based while every other zone here is strictly production-based.

We republish rather than compute because ENTSO-E stopped publishing GB data on 2021-06-15 after the post-Brexit TCA, and the NESO feed gives intensity directly without a generation mix in MW. Rebuilding GB on our own basis would require a separate mix source (Elexon/NESO data portal). It is on the roadmap; it is not done.

Two smaller GB caveats:

  • GB is Great Britain, not the UK. Northern Ireland is on the all-island Irish grid and appears in our IE zone, not GB. Calling this number "UK carbon intensity" is wrong.
  • GB is 30-minute, not hourly. Timestamps land on :00 and :30. A day is 48 rows, not 24. Code that assumes hourly spacing across all zones will break here.

§ 6Timestamp semantics

Timestamp semantics

**Every timestamp in this API is UTC and marks the start of the interval.** 2026-08-25T14:00:00Z covers 14:00–15:00 UTC. There is no local-time representation anywhere in the pipeline, and no local calendar arithmetic, so daylight saving cannot produce a missing or duplicated hour in our data.

Getting there requires three different conversions:

ENTSO-E — position arithmetic, then aggregation to the hour. Each Period in the A75 response declares its own resolution (PT15M, PT30M or PT60M) and its own UTC start. A point's timestamp is period_start + (position − 1) × resolution. Resolution varies by zone and by date — ES moved to 15-minute in 2022, FR in December 2024, DK and NO in April 2025, SE in December 2025 — so it is read from the document, never assumed.

Since the R3 platform migration (A75 moved on 2025-10-23) responses use curveType=A03, where an unchanged value is simply omitted: a missing position inherits the previous point's quantity through to the end of the Period. We carry values forward accordingly. Parsers that assume contiguous positions silently lose data here.

Sub-hourly slots are then averaged into their hour bucket. Two honest caveats:

  • Every slot in a bucket gets equal weight. When the hour has a single resolution — the normal case — that is exactly the time-weighted average MW. On the rare hour that straddles a resolution change, the weighting is slightly wrong and we do not correct for it.
  • Positions occurring before the first declared point in a Period are dropped, so an hour can occasionally be averaged over fewer slots than it nominally contains.

We also read only the generation series (inBiddingZone_Domain). Consumption series (outBiddingZone_Domain) — pumping load, battery charging — are skipped at parse time and never enter the mix.

EIA — hour-ending to interval-start. EIA-930 reports hour-ending periods: 2026-08-25T15 is the energy delivered between 14:00 and 15:00 UTC. We subtract one hour to get our interval start. Concretely, EIA T15 becomes our 2026-08-25T14:00:00Z. Our request window is shifted the same way, asking for hour-ending from+1h through to. We always request frequency=hourly (UTC) and never local-hourly, because a BA's reporting timezone is not necessarily its geographic one and the local series contains DST gaps and duplicated hours.

NESO — already interval-start. Each block carries an explicit from and to; we take from. The blocks are 30 minutes.

§ 7Revisions: what changes after we publish it

Revisions: what changes after we publish it

Values are not immutable. Every hour, the collector re-pulls a 72-hour trailing window from all three sources and upserts the result — the primary key is (zone, ts) for intensity and (zone, ts, fuel) for the raw generation mix, so a re-pull overwrites the earlier value in place. Nothing is versioned and no history of the correction is kept.

Three consequences you should design around:

1. A number you read can change for up to 72 hours. This is by design. Upstream operators revise: DE, AT, PT, GR and LV publish an extrapolation first and backfill settlement data later; IT revises at D+1 and D+40; EIA-930 is explicitly provisional and BAs revise for days. Re-pulling is how those corrections reach you.

2. Revisions that land after 72 hours are never picked up. This is the uncomfortable half. Italy's D+40 revision is far outside our window, so IT zones will keep their D+1 value permanently. EIA's longer-tail revisions — which PUDL documents as running to months — are likewise lost. Meanwhile ES never revises at all (its data is a real-time setpoint feed), and PL, CZ, EE, BG, FI and NO publish once and never update, so for those zones the window is irrelevant.

3. GB rows can flip method. NESO's actual is null for the most recent 0.5–2 hours while settlement completes. We fall back to forecast and say so in the method field. On a later re-pull inside the 72-hour window the same timestamp is overwritten with the settled value and the tag flips from upstream:uk-neso:forecast to upstream:uk-neso:actual. The value changes and the method changes; the timestamp does not. If you cached a GB row, re-read it.

Factor changes are not retroactive. We store the raw generation mix precisely so intensity can be recomputed if the factor table changes. But the pipeline only ever computes within its 72-hour window. If we revise a factor, everything older than 72 hours keeps its old value until someone runs a manual backfill. The method string (computed:v1) is the version marker; a factor change would bump it, and for a while the archive would contain both.

§ 8Known limitations and biases

Known limitations and biases

Ranked roughly by how much damage each can do to a decision you might make with these numbers.

It is production-based. Imports are invisible.

We compute the intensity of electricity generated inside a zone. We do not model cross-border flow. A bidding zone that imports heavily — IT-NORD from Switzerland and France, DK from Norway and Germany, small zones generally — will show the intensity of its own generators, not of the electricity its consumers actually draw. For a large, roughly self-sufficient zone the two are close. For a small importing zone they can differ a lot.

If you need consumption-based intensity for Scope 2 market-based or location-based reporting, understand that this is not that number. Consumption-based accounting requires flow tracing across the whole interconnected network, and we do not do it.

The emission factors are twelve years old

IPCC AR5 Annex III was published in 2014 and reflects pre-2014 supply chains. Renewables have decarbonised since; fossil methane accounting has tightened.

  • Utility solar at 48 g is high. UNECE 2022 puts modern utility PV around 37, with a range down to 8.
  • Nuclear at 12 g is roughly double UNECE 2022's 5.1–6.4. The absolute error is small, so the effect on a mix is negligible.
  • Gas at 490 g may be low for the US, where upstream methane leakage is not fully captured in the AR5 median.

We keep AR5 rather than mixing sources, because a half-AR5, half-UNECE table would be internally inconsistent and would silently break comparability with anyone else using AR5. Switching wholesale to UNECE 2022 is a legitimate future v2.

Lignite, oil shale and peat are systematically understated

AR5 gives one coal number. We apply 820 to hard coal, lignite (B02), oil shale (B07) and peat (B08) alike, following the same mapping Electricity Maps uses. In reality lignite runs about 1000–1200 gCO2/kWh direct, Estonian oil shale about 950–1100, and peat at least as high as lignite.

This makes lignite-heavy zones look cleaner than they are: DE, PL and EE are biased low by roughly 15–25%. It is the largest known directional error in the dataset, and it points the wrong way — the dirtiest grids get the most flattering treatment.

Some hours are computed from a partial mix, and we do not catch them

There is no plausibility gate. If a zone has published only one production type with positive volume when we fetch, we compute an intensity from that one type and store it.

At the time of writing, 105 of the 4,459 values in the archive (2.4%) sit exactly on a single emission factor. Most are genuine: 93 of them are NO-5 at exactly 24.0, and NO-5 really is essentially pure hydro. The remaining twelve are the failure mode:

  • IE's three most recent hours all read exactly 820.0 — the coal/peat factor — because those were the only categories with positive published volume at fetch time. Ireland's preceding hours run 320–360.
  • AT has an hour at exactly 38.0, the geothermal factor. Austria does not run on geothermal.
  • FI and NO-4 each have an hour at exactly 48.0, the solar factor.

Some of these correct themselves on a later re-pull. Some do not, and once the 72-hour window slides past, the wrong value is frozen. A minimum-category count or a cross-check against total load would catch this; neither is implemented.

Practical defence: treat a value that lands exactly on a table factor as suspect unless the zone is genuinely single-source, and prefer values that are a few hours old over the newest one.

US data arrives half a day late, and is provisional when it does

EIA-930 is explicitly provisional. Our measured lag is 11–14 hours, not the documented 1–3. For any near-real-time scheduling use case in the US, this API is currently not fit for purpose. Use it for retrospective accounting, not for deciding whether to run a job in the next hour.

CAISO's batteries hide in "Other"

CISO reports no BAT rows. Its grid batteries land in OTH, which we exclude as storage for that zone only (see the override above). This is inference from an observed charge/discharge signature, not from an EIA statement. If CISO's OTH also contains real thermal generation, we are excluding generation that should count. The override needs revisiting whenever CISO's reporting changes.

Rooftop and behind-the-meter solar is missing everywhere

EIA-930 covers utility-scale generation only; distributed rooftop PV is behind the meter and does not appear. ENTSO-E has the same problem in several zones. Netherlands and Switzerland are the weakest European coverage — CH's A75 categories are coarse and distributed solar is largely absent or folded into Other, and a large share of NL's distributed PV is not on the Transparency Platform at all. Both zones would benefit from a national source (Swissgrid, NED.nl) as a cross-check. Sunny midday hours in affected zones read dirtier than reality.

"Other" at 700 g is a guess

B20 and OTH are priced as unidentified thermal at 700 gCO2eq/kWh. For zones where that category is actually masked fossil plant, this is reasonable. For zones where it is dominated by biomass or geothermal, it is far too high. EIA masks any fuel category with three or fewer generators into OTH, so the composition varies by BA and we cannot see inside it. Per-BA overrides are the obvious fix and are not built.

Storage exclusion is a first-order approximation

Covered in section 3: it ignores round-trip losses and the time-shift between charging and discharging. Zones with heavy pumped storage (AT, CH) carry the most of this error.

The archive is four days deep

History starts at 2026-08-21T11:00:00Z. There is no backfill yet. Anything requiring seasonal patterns, year-on-year comparison, or a baseline is not possible with this data today.

Net vs gross generation

ENTSO-E A75 reports net generation — station service already deducted. Figures from sources reporting gross generation are not directly comparable. Neither source includes transmission and distribution losses, so this is intensity at the generator terminal, not at your meter.

§ 9Does it pass a smell test?

Does it pass a smell test?

The known biases above are real, but they are bounded. The output still lands where an energy person would expect. 24-hour averages observed on 2026-08-25:

ZonegCO2eq/kWhWhy that is the right shape
CH22.8Hydro plus nuclear
NO-128.1Hydro
SE-333.0Hydro, nuclear, wind
FR33.2Nuclear
GB98.3Operational basis — not comparable to the rows above
DK-1106.8Wind, with thermal backup
ES117.6Solar, wind, gas
DE277.6 (range 106–465)Wide daily swing between renewable and coal hours
IT-NORD300.9Gas-dominated
PL490.6Coal — and this is the number our lignite proxy understates

US zones over the same period: US-BPA 57–109 (Columbia River hydro), US-MISO 337–497 (coal and gas), US overall 311–418.

Nothing here is surprising, which is the point. If FR came out at 400 or PL at 90, the pipeline would be broken. Note that GB's 98.3 sits between DK-1 and ES in this table and means something different from both of them — this is exactly the comparison the GB section warns against.

§ 10Check it yourself

Check it yourself

Nothing above needs to be taken on faith. The API is open, uncredentialed and CORS-enabled:

# every zone, right now
curl -s https://api.gridcarbon.dev/v1/intensity/latest

# one zone's history — note the method field on every row
curl -s "https://api.gridcarbon.dev/v1/intensity?zone=DE&from=2026-08-24T00:00:00Z&to=2026-08-25T00:00:00Z"

# GB, to see 30-minute spacing and the forecast/actual method flip
curl -s "https://api.gridcarbon.dev/v1/intensity?zone=GB&from=2026-08-24T00:00:00Z&to=2026-08-25T00:00:00Z"

# the zone list, with each zone's upstream source and native resolution
curl -s https://api.gridcarbon.dev/v1/zones

Then check us against the upstream operators directly — NESO's API needs no key either:

curl -s https://api.carbonintensity.org.uk/intensity/factors

If you find a zone-hour where our number is wrong, we want to know. Being caught is cheaper than being trusted for the wrong reasons.

§ 11Attribution

Attribution

gridcarbon is built entirely on public data published by three operators. Attribution is a condition of use, not a courtesy.

  • ENTSO-E Transparency Platform — actual generation per production type (document type A75) for the 33 European bidding zones.
  • U.S. Energy Information Administration (EIA) — Form EIA-930 hourly generation by energy source, retrieved via the EIA Open Data API, for the 11 United States balancing authorities and aggregates. gridcarbon is not affiliated with, endorsed by, or certified by the U.S. Energy Information Administration (EIA), and nothing in this service should be interpreted as an EIA endorsement of gridcarbon, its methods, or its numbers.
  • NESO Carbon Intensity API — the published carbon intensity series for Great Britain.

Emission factors derive primarily from IPCC AR5 WGIII (2014), Annex III, Table A.III.2, cross-checked against UNECE (2022) and the Electricity Maps open factor set. Oil uses UK POST (2006); waste uses Zero Waste Europe (2020).

If you redistribute values obtained from this API, carry these attributions with them.

Method version computed:v1. Factor table generated 2026-08-24 and independently re-verified against primary sources the same day. Measurements quoted on this page were taken from the live API on 2026-08-25. Corrections welcome.