Hourly Grid Carbon Intensity by ZIP Code: Free API Guide

A practical guide to the free hourly US grid carbon intensity API, with working code for two use cases: backtesting demand response and timing EV charging. It is a timing and analysis tool, not a source of Scope 2 reporting factors.

Published April 17, 2026 · Recomputed October 7, 2026 · By the emission-factors.com team

Community discussion: the April 2026 three-state chart from this analysis was discussed on r/dataisbeautiful. That chart used earlier, rounded fuel factors and counted California's battery discharge as fossil. Every figure on this page was recomputed in October 2026 with the method below, with hours labeled by their start (EIA-930 stamps each hour at its end).

Is there a free API for hourly grid carbon intensity in the US?

Yes. emission-factors.com returns hourly grid carbon intensity for any Lower-48 US ZIP code, derived from EIA Form 930 hourly fuel-mix data. Call GET /api/intensity?zip=94105&hours=24 for up to 168 hours (7 days) for the balancing authority serving that ZIP. Data lags up to about a day; it is not real-time. For live or forecast intensity, WattTime and Electricity Maps offer commercial APIs.

How it works

  1. Resolve ZIP to balancing authority. By the ZIP's utility (EIA-861), then its state and eGRID subregion, then its state (e.g. 94105 → CISO). The response's ba_basis says which rule applied. 46 balancing authorities are mapped; 45 currently report to EIA-930 (WACM has not reported since April 2, 2026, and returns a 404 that says so).
  2. Fetch hourly fuel mix from EIA-930. MWh generated by each fuel type for every hour, per balancing authority.
  3. Compute intensity. Multiply each fuel's MWh by its CO₂e rate (kg per MWh), sum, divide by total generation. Storage output (batteries, pumped storage) is excluded, including batteries reported inside "other" (CAISO).

Fuel factors (direct, operational CO₂e; not lifecycle):

FuelEIA codekg CO₂e per MWhSource (EPA eGRID2023)
CoalCOL1,018US coal output rate (USCC2ERT, 2,244.545 lb/MWh)
Natural gasNG408US gas output rate (USGC2ERT, 900.028 lb/MWh)
PetroleumOIL708US oil output rate (USOC2ERT, 1,560.637 lb/MWh)
OtherOTH579US all-fossil output rate (USFSC2ERT); EIA-930 does not say what "other" burns
GeothermalGEO28Geothermal plants' CO₂e over their net generation (60.7 lb/MWh)
Nuclear / hydro / wind / solar / biomass-0No combustion; biomass CO₂ is biogenic

Because these are US-average rates applied to in-region generation only (imports are not counted), hourly values do not add up to the annual eGRID subregion factor. Use them to compare hours, not to report Scope 2.

How much does intensity vary within a day?

A lot, depending on the grid. Hour-of-day averages over the 7 days (168 hours) ending April 16, 2026, 03:00 UTC:

Three-grid comparison: CA vs TX vs NY

GridCleanest hour (local)Dirtiest hourSwingWeek avg
CAISO (California)2pm PT @ 0.024
62% solar, 16% wind
3am PT @ 0.106
27% wind, 26% gas, 24% hydro
4.5×0.066
ERCOT (Texas)noon CT @ 0.189
34% solar, 27% wind
8pm CT @ 0.305
42% gas, 38% wind, 13% coal
1.6×0.257
NYISO (New York)5pm ET @ 0.313
49% gas, 24% hydro
midnight ET @ 0.338
50% gas, 23% other
1.1×0.327

Values in kg CO₂e per kWh. Three findings:

CAISO 24-hour profile

Hour (PT)Avg intensity (kg CO₂e/kWh)Pattern
midnight–6am0.102–0.106No solar; wind, hydro, nuclear and gas
7am0.061Solar ramping up
8am–4pm0.024–0.034Solar peak
5pm0.037Solar fading
6pm0.058Solar drops out
7pm–11pm0.083–0.095Evening; batteries discharge (excluded as storage)

One day of raw hours (CAISO, April 15 PT)

Hour (UTC)Intensity (kg CO₂e/kWh)Fuel mix
22:00 Apr 15 (3pm PT, cleanest)0.01966% solar · 12% wind · 4% gas
Day avg (24 hours)0.054-
13:00 Apr 15 (6am PT, dirtiest)0.1007% solar · 16% wind · 24% gas

Use case 1: Did shifting our batch job reduce carbon?

Say your ops team moved a 1 MWh (1,000 kWh) batch job in ERCOT from 8pm local (01:00 UTC) to 11am local (16:00 UTC). How much CO₂e did that avoid?

import requests

API = "https://emission-factors.com/api/intensity"

def intensity_at(ba, hour_utc):
    """Intensity for a specific past hour (within the last 168)."""
    r = requests.get(API, params={"ba": ba, "hours": 168})
    hours = {h["hour_utc"]: h["intensity_kg_co2e_per_kwh"] for h in r.json()["hourly"]}
    return hours.get(hour_utc)

dirty = intensity_at("ERCO", "2026-04-16T01:00Z")  # 0.345 kg/kWh
clean = intensity_at("ERCO", "2026-04-15T16:00Z")  # 0.167 kg/kWh

kwh = 1000
savings = kwh * dirty - kwh * clean
print(f"Carbon avoided: {savings:.0f} kg CO2e ({(1 - clean/dirty)*100:.0f}% less)")
# Output: Carbon avoided: 178 kg CO2e (52% less)

On that day: 178 kg CO₂e avoided, 52% less. Across the week the hour-of-day averages are closer (noon 0.189 vs 8pm 0.305 kg/kWh), about 116 kg per 1 MWh run, so a 250-run-per-year job avoids roughly 29 tCO₂e a year at that week's pattern.

Use case 2: When should I charge an EV fleet in California?

A 20-vehicle fleet in San Francisco charging 100 kWh per vehicle (2 MWh a day). When is the grid cleanest?

import requests
from collections import defaultdict

# cleanest_hours does this in one call, in local time:
r = requests.get("https://emission-factors.com/api/cleanest-hours",
                 params={"zip": "94105", "duration": 4})
print(r.json()["cleanest_window"])

# or build the hour-of-day profile yourself from the hourly series (UTC):
r = requests.get("https://emission-factors.com/api/intensity",
                 params={"zip": "94105", "hours": 168})
by_hour = defaultdict(list)
for h in r.json()["hourly"]:
    by_hour[int(h["hour_utc"][11:13])].append(h["intensity_kg_co2e_per_kwh"])
for hour in sorted(by_hour):
    print(f"{hour:02d}:00 UTC  {sum(by_hour[hour]) / len(by_hour[hour]):.3f}")

Over the April week above, charging at noon to 3pm (about 0.024 kg/kWh) instead of midnight (0.102) means about 48 kg instead of 204 kg CO₂e a day: roughly 156 kg a day, or 57 tCO₂e a year at that pattern. Utility time-of-use rates often price midday as peak, which is exactly California's cleanest time.

In Texas, midday is also cleanest but the gap is smaller (about 0.19 vs 0.31 kg/kWh in the evening). In New York there is essentially no carbon-optimal hour. Use your own grid's data rather than assuming.

When NOT to use this API

FAQ

How is this different from the annual eGRID factor you also provide?

The annual eGRID factor (e.g. CAMX 0.195 kg/kWh) is EPA's generation-weighted rate for a subregion over a year, from plant-level data, and is the standard input for GHG Protocol Scope 2 location-based reporting. The hourly intensity here applies US-average fuel rates to each hour's in-region fuel mix, so it shows how the grid varies through the day but is not comparable to, or a substitute for, the eGRID factor.

Why does CAISO intensity drop near 0.02 kg/kWh in the afternoon?

In the April week above, California's 9am–3pm generation averaged 59–65% solar, with wind, hydro and nuclear making up most of the rest; none of those burn fuel. On April 15 the 3pm PT hour was 66% solar and 4% gas, giving 0.019 kg/kWh.

Which balancing authorities are covered?

46 Lower-48 balancing authorities are mapped (45 currently report to EIA-930). A ZIP maps to one of them through its utility, then its state and eGRID subregion, then its state; you can also call ?ba=CISO directly.

Do I need an API key?

No. The API is free and keyless - no signup, no header, no auth token. Just call the endpoint. Full API docs.

Try it now:
curl "https://emission-factors.com/api/intensity?zip=94105&hours=24"
Returns the last 24 hours of grid carbon intensity for the California ISO. Full API docs · Use as an MCP tool for Claude.