The dry heat illusion
By Heat Index, shown above by default, Arizona isn't the hottest reading. Switch to UTCI and it jumps back to the top. Same place, same day: dry air hides what solar radiation is actually doing.
One request replaces what is otherwise six months to a year of specialist geospatial labor and reports how much to trust each number it returns.
The Heat Risk Data API takes a set of geographic polygons and returns per-polygon heat-risk, air-quality, and vulnerability metrics, drawn from roughly fourteen distinct external data products: satellite thermal imagery, global population rasters, a European climate reanalysis service, ground-station and satellite air-quality networks, canopy-height models, and settlement classification, among others. None of it is visible to the caller. A request names the polygons to evaluate; the response returns the metrics for each.
A new project is queryable in approximately 20 to 35 minutes end to end, from initial polygon submission to a first complete set of metrics.
What comes back, per polygon, falls into three tiers. First, each raw source aggregated to the polygon: air temperature and Heat Index (max/min/mean, split into full-day, daytime, and nighttime windows), population and age structure, air quality (ground-station and satellite-model, reconciled), and the vulnerability inputs (settlement classification, tree canopy, land cover, night-time lights, relative wealth, subnational HDI, nearby health facilities). Second, processed metrics computed from those aggregates: the UTCI and WBGT thermal-comfort indices and forward-looking forecast metrics. Third, derived composites and comparisons: a warm-season land-surface-temperature composite, daily anomaly tiers grading how unusual a day is against a ten-year reference climatology, and vulnerability composites.
Responses from the main evaluation endpoint also include polygon_coverage: for
twelve of the API's roughly fourteen sources, a signal reporting how well the underlying
data actually resolves that specific polygon. Raster sources get a valid-area fraction,
centroid-sampled weather sources get a sampling-representativeness ratio, sparse sources
get a point or facility count, and the one categorical join gets a matched-region flag.
Where it applies, it states how much to trust each number, for that specific polygon.
POST /v1/evaluate queries fourteen external data
products behind a single interface; the response carries heat, air-quality, and
vulnerability metrics with polygon_coverage attached. Each source is shown
with its access pattern. Upstream attribution and licensing requirements are handled
once, centrally, and invisible to the caller.
A request is a single POST with a JSON body: an authenticated caller, the action, and a payload naming the project and, for a new project, the polygons to evaluate.
POST https://5trhrgas69.execute-api.us-east-1.amazonaws.com/v1/evaluate
Content-Type: application/json
{
"username": "<username>",
"key": "<api-key>",
"action": "evaluate-heat-risk",
"payload": {
"project_id": "<your-project-id>",
"json_obj": { "type": "FeatureCollection", "features": [ ... ] }
}
}
The full action, request, and response reference, every action, payload field, error code, and a worked end-to-end walkthrough, is provided to accepted users alongside their credentials.
T2m and Heat Index alongside UTCI (ISO 15743) and WBGT (ISO 7243), the physiological and occupational-safety standards, comparable across a dry desert and a humid tropic alike.
WBGT crosses its own hard line at 32°C (suspend moderate/heavy outdoor work) and 35°C (all outdoor work must stop). These are the thresholds occupational-health agencies and emergency managers act on directly.
Standard measurement, 2m above ground.
"Feels like" temperature. Misleading in dry climates.
Radiation + wind + humidity + temp. Comparable across climates.
Occupational threshold. >35°C: stop outdoor work.
Color always reflects each area's real UTCI danger level. Switch metrics and watch bar height move, while the color, the actual physiological risk, doesn't. That gap is the whole reason this API reports four metrics, not one.
By Heat Index, shown above by default, Arizona isn't the hottest reading. Switch to UTCI and it jumps back to the top. Same place, same day: dry air hides what solar radiation is actually doing.
Switch to WBGT: Bangladesh jumps past Arizona and Andalusia. 35.2°C is the ISO threshold where all outdoor work must stop.
Every area here changes rank depending on which lens is applied. That's the case for reporting all four, every time, instead of picking just one.
Every metric this API returns traces back to a named, public dataset, not an internal estimate. This section names all fourteen, how far back the archive reaches, and one worked example of what it looks like when two hazards from two different sources land on the same place on the same day.
On June 22, the same day as this page's own Andalusia peak, 119 of 120 municipios hit Extreme-or- beyond UTCI, and, separately, 119 of 120 exceeded the WHO PM2.5 guideline. 118 municipios hit both thresholds on the same day. Écija itself: UTCI 56.2°C, PM2.5 at 18.4 µg/m³.
Share of the trailing 30 days' polygon-readings above the WHO 24-hour PM2.5 guideline (15 µg/m³), refreshed daily.
Station-measured days shown solid, model days hollow: the same firmness vocabulary the reconciliation ribbon uses, since CAMS-vs-OpenAQ is the same measured-vs-modeled axis as ERA5-vs-Open-Meteo. Five of six cities have at least one real monitor inside a project polygon, up to 11 stations in Maricopa County, and station data always overrides the model. Oaxaca's highlands have none; there, model output is labeled as exactly that.
Every metric on this page traces back to a named, public dataset, not an internal estimate. Grouped by the same category colors used in the coverage matrix on the Evidence page: heat measurement in ember, social/vulnerability indicators in atmos, environment in slate-green, air quality in haze.
Each response carries the signals needed to judge how far to trust its own numbers. Coverage and validation are returned as normal fields, for twelve sources at once. The engineering stories behind these guarantees are in the companion write-up.
polygon_coverage on every evaluate response. Eight raster
and weather sources report the fraction of a polygon's area backed by valid pixel data. For
centroid-sampled ERA5 and CAMS, a resolution_adequate flag marks when the
source grid is coarser than the polygon, so a small polygon still receives its point
estimate with an explicit reliability flag. The four structurally sparse sources each
report the signal that fits them: a point or facility count for RWI, Healthsites, and
OpenAQ, and a matched-region overlap fraction for GDL subnational HDI.area_apportioned: true,
so a partial-pixel estimate is distinguishable from a full measurement in the response.A trimmed real response for one polygon, one day, showing the shape (48 reference-climatology columns per row omitted for length):
{
"metrics": [{
"name": "Colonia Roma", "date": "2024-07-01",
"population": 45230,
"day_t2m_max": 31.2, "day_hi_max": 98.4,
"...": "48 ref_* reference-climatology columns, plus UTCI/WBGT and daytime/nighttime splits"
}],
"polygon_coverage": {
"Colonia Roma": {
"lst": {"valid_px_frac": 0.62, "below_threshold": false, "scene_date": "2025-08-14"},
"population": {"valid_px_frac": 1.0, "below_threshold": false, "area_apportioned": false},
"era5": {"grid_cells_spanned": 0.0007, "resolution_adequate": false,
"polygon_area_km2": 0.6, "grid_cell_area_km2": 820.85},
"healthsites": {"facility_count": 2, "nearest_km": 0.8},
"rwi": {"n_points": 8, "has_data": true},
"gdl": {"matched": true, "region_name": "MEXcty Ciudad de México",
"overlap_frac": 0.93, "used_centroid_fallback": false},
"cams": {"grid_cells_spanned": 0.0028, "resolution_adequate": false,
"polygon_area_km2": 0.6, "cams_grid_cell_area_km2": 214.5},
"...": "plus viirs, worldcover, ghsl_smod, canopy, and openaq (twelve sources in all)"
}
}
}
resolution_adequate: false rather than presenting it as
reliable at that scale.
The base weather grid is ERA5-Land, roughly 9 km per cell. A city neighborhood is far
smaller than one cell, so the centroid sample above cannot resolve variation at the block
scale, the same resolution_adequate: false case the figure just showed.
A statistical model corrects the grid air temperature for each polygon, using covariates the API already computes for every polygon: elevation, tree canopy height, impervious and built fraction, warm-season land-surface-temperature anomaly, population density, wind, and climate zone. The corrected temperature is then run back through the same heat-index, UTCI, and WBGT functions the base pipeline uses. The model corrects temperature only; it does not model the composite indices directly.
A response can carry one of four kinds of value for a polygon-day, in order of precedence, best first: where a station sits inside the polygon itself, that station's own observed reading, which overrides the model outright; a model-corrected estimate additionally adjusted against nearby real weather stations; the model-corrected estimate on its own; or the raw grid estimate. A better value can replace a worse one, never the reverse, so a real observation is never quietly downgraded back to a modeled estimate.
data_source values a polygon-day can carry, strictly ordered, Tier 1
(best) leftmost through Tier 4 (worst) rightmost, same order as the tier ladder above.
Real per-zone pass rates and the one project with live Tier 2 data are covered in the
paragraphs above; full validation detail is at
the Evidence page.
The correction is validated per climate zone, separately for daytime and nighttime. Daytime-maximum correction passes cross-validation in all 19 zones tested. Nighttime-minimum correction passes in 15 of 19, failing in four zones spanning tropical, humid-subtropical, and hot-desert climates (Am, As, Cwa, BWh), where the raw grid value is served instead. Where a metric does not pass for a zone, the response returns the uncorrected grid value and says so.
The correction is not limited to days that have already happened. A separate near-term band
(covering the most recent few days, before the historical archive catches up) and the
seven-day forecast horizon are each validated on their own terms, per climate zone, and
current and forecast values carry a correction under the same discipline. Its structural
eligibility is reported per polygon in polygon_coverage as a
downscaling entry. Some zone/band passes reflect genuine per-polygon
differentiation; others clear the gate only through a flat per-zone bias adjustment, and
that share grows with forecast lead time. Both count as a validated pass here; which kind
applies to a given zone, band, and target is disclosed on
the Evidence page.
Only air temperature is corrected. Humidity, wind, and solar radiation are not, so WBGT and UTCI improve only through their temperature term and still carry the grid-scale wind and solar values. The corrected resolution varies with covariate availability: roughly 100–300 m where the fine covariates are present, degrading toward about 1 km where only coarse covariates exist, a floor rather than a fixed number.
The correction is enabled across every active project. A polygon-day carries a corrected value once its covariate context is complete and its zone's gate passes for that target. An absent or grid-tier value in the meantime is a normal, temporary state that resolves automatically as each project's daily update runs. Per-zone validation results, the global station coverage behind the station-adjusted tier, and the full methodology are at the Evidence page.
Risk depends on who is exposed and their adaptive capacity, not heat exposure alone. Each indicator below is extracted per polygon at project initialization.
82.7M people live in Bangladeshi districts facing both extreme heat stress and below-average wealth, as of July 4.
Each dot is one of Bangladesh's 64 districts: position is heat exposure (UTCI) vs. relative wealth, color is the site's severity tier, size is population. Wealth data (Meta RWI) covers ~93 low- and middle-income countries; for high-income geographies the API substitutes healthcare-access and land-cover indicators.
| District | UTCI °C | RWI | Facilities/10k | Population |
|---|---|---|---|---|
| Sunamganj | 53.5 | −0.21 | 0.10 | 2.9M |
| Sylhet | 52.6 | 0.00 | 0.30 | 4.0M |
| Natore | 52.5 | −0.07 | 0.35 | 2.0M |
| Netrakona | 52.5 | −0.19 | 0.24 | 2.6M |
| Thakurgaon | 52.1 | −0.28 | 0.12 | 1.6M |
| Maulvibazar | 52.0 | −0.08 | 0.18 | 2.2M |
| Mymensingh | 52.0 | −0.08 | 0.26 | 5.9M |
| Lalmonirhat | 51.9 | −0.19 | 0.09 | 1.5M |
Top 8 of 37 qualifying districts, ranked by UTCI · real ERA5 data
Population-weighted age structure per project, from the same WorldPop extraction that already populates every polygon's vulnerability record: no new pipeline work, just a comparison nobody had drawn yet. Residents 65 and older carry the sharpest heat-mortality risk of any age group; under-5s the second sharpest. The nearly 8× spread below reflects eight real demographic profiles sharing one API. Who is exposed and how hot their own neighborhood actually runs are now reported at the same resolution, so the two can be read together instead of a per-polygon vulnerability profile sitting on top of one shared grid-cell temperature.
La Paz County, Arizona: 31.8% elderly, the 4th-highest of the Phoenix project's 17 counties (behind Yavapai, Mohave, and Gila), and 1.15 health facilities per 10,000 residents, 5.9× fewer than Maricopa County's 6.78, while facing the same Beyond-Extreme UTCI severity (60.5°C) as the rest of the state. The heat here is no worse than anywhere else in Arizona; the county just has more people who are vulnerable to it and less capacity to respond. That's what this section's opening line ("risk depends on who is exposed and their adaptive capacity") looks like as three numbers from one polygon.
Lagos's demographic profile isn't the only place it stands apart. Seven of these eight projects show essentially zero mangrove cover in the underlying ESA WorldCover extraction: Lagos alone averages 2.2%, and one polygon, Amuwo Odofin, is 16.1% mangrove and 18.7% open water. Land cover, alongside population, is part of what "adaptive capacity" means here: a coastal ecology none of the other seven projects have.
Bangladesh: a typical day, not a record heatwave, at district resolution. Mexico City: the same API at colonia resolution, 1,182 neighborhoods deep, with every field the API returns for one colonia laid out in the specimen explorer below.
64 districts, initialized in under 35 minutes. June 23 peak conditions, and "typical" is exactly what the ten-year baseline in the Mexico City deep dive below is built to test.
| District | UTCI °C | WBGT °C | Population |
|---|---|---|---|
| Loading live districts… | |||
Top 8 of 64 districts by UTCI · real ERA5 data
Mexico City runs at colonia resolution: 1,182 neighborhoods, each measured against its own ten-year baseline (2016–2025) of daily peaks for this time of year. This is the API's full output, nothing summarized away.
On June 28, 1,179 of Mexico City's 1,182 colonias ran warmer than usual for the date, each measured against its own ten-year baseline. 3 crossed the 95th percentile.
Warmer than usual. Today's peak topped roughly three of every four days this colonia has seen at this time of year since 2016, but short of extreme.
The gauge reads from live data, and on a normal day it says so. Baseline: 120 monthly reference distributions per colonia, 2016–2025 (WMO-standard decade), matched by day of year.
1,182 colonias make a solid choropleth unreadable at this scale; each one's heat values are corrected toward its own neighborhood rather than shared with the whole grid cell (see the specimen explorer below). Instead, three that each tell part of today's story, located within the city:
A median composite of clear-sky Landsat 8/9 thermal readings across this city's three most recent warm seasons (March–May 2024–2026), each colonia measured against the city's own average, skin temperature, not air temperature. Unlike the raw ERA5 grid, Landsat's ~100 m thermal band resolves individual colonias directly, so this is the first per-colonia map this API has been able to draw at all.
Search any of Mexico City's 1,182 colonias to see every field the API returns for it: 36 heat metrics, 16 ten-year baseline percentiles, 42 vulnerability indicators (including the Landsat persistent-heat composite above), and an Open-Meteo forecast outlook, from one API call.
Loading colonia detail…
Five of the API's projects, the question each was set up to answer, and which metrics each draws on.
Behavioral guarantees of the daily pipeline. The engineering stories behind them are in the companion write-up.
A GeoJSON FeatureCollection, each feature a named polygon: city districts, census tracts, health zones, river catchments, anything with a boundary.
For every polygon, every day, drawn from the sources named in Sources & provenance above.
curl -X POST https://5trhrgas69.execute-api.us-east-1.amazonaws.com/v1/evaluate \
-H "Content-Type: application/json" \
-d '{
"username": "<username>",
"key": "<api-key>",
"action": "evaluate-heat-risk",
"payload": { "project_id": "<your-project-id>", "limit": 500, "offset": 0 }
}'
{
"project_id": "<your-project-id>",
"total_rows": 68620, "limit": 500, "offset": 0,
"metrics": [{
"name": "Colonia Roma", "date": "2026-07-01", "population": 45230,
"day_t2m_max": 31.2, "day_hi_max": 98.4,
"downscaled": {
"data_source": "era5_land_downscaled", "confidence": "medium",
"tmax": { "delta_c": 2.06, "ci95_c": 2.49 },
"metrics": { "day_t2m_max": 33.3, "...": "all 36 metric columns" }
},
"...": "36 heat columns plus the reference-climatology ref_* columns"
}],
"polygon_coverage": { "Colonia Roma": { "era5": { "resolution_adequate": false }, "...": "one entry per source" } }
}
Trimmed to the shape of a query against an existing project. A new project is created by the same
call with a GeoJSON json_obj in the payload and answers 202 initializing
first. The full contract, every action, and the error codes are in docs/api.md,
provided with credentials.
A project initializes in roughly 20 to 35 minutes from initial submission. After that, a scheduled process updates every active project every morning at 06:00 UTC, blending near-real-time estimates with authoritative ERA5 data as it becomes available; no further action is required once a project is set up.
Rate limits: 300 requests/hour per authenticated user on the primary evaluation endpoint, with administrative accounts exempted; a stage-wide throttle of 20 requests/second applies across all traffic, regardless of endpoint. Authentication is via an API key, issued once at account creation and not stored or logged in plaintext afterward.
This page covers what the API does and how it's built. The full technical reference (every action, request/response shapes, error codes, and a worked end-to-end walkthrough) is provided directly to every accepted user alongside their credentials.
Account creation itself is invite-based (2026-07-12): an administrator mints a single-use invite code that expires after seven days; whoever holds it redeems it in one call and receives their API key directly, so the plaintext key is never relayed over email or seen by anyone but the account holder. Each invite carries the organization and role the new account will hold, so redeeming it places the holder into the right organization with the right permissions in that single call. A leaked code can be revoked immediately. This is closed-group by construction: a code exists only because an administrator minted one. Access still starts with an email to datascience_crisisready@harvard.edu. Pre-merge review of the mechanism caught and fixed a redemption race that could burn a code without creating an account, and re-keyed a rate limit that one bad actor could have exhausted for every code holder at once.
Every account belongs to an organization, which is the boundary for what it can reach. A role inside the organization sets what an account can do: an organization administrator manages that organization's users and can run data work on any project in the organization; a member owns and runs its own projects; a read-only account cannot change anything. A project is private by default and visible to its owner; marking a project public grants read-only access to it from any organization, which is how the public demonstration projects are shared, while a private project is never readable from outside its organization. Broader read access across an organization's members is supported but switched off by default while the service is in early access. Ownership and edit rights are separate, so an account demoted to read-only keeps the projects it owns but can no longer change them.
A project starts with the core heat metrics and can be extended with further data layers without going through an administrator. One read action reports which layers a project already holds and flags whether a missing layer reflects a real data gap or a pipeline problem, so a user can tell whether an absence is on their end or ours. A second action enables any supported layer through one entry point, whether that is land surface temperature, air quality, the WMO climate reference period, population, or one of the vulnerability layers, without the user needing to know which internal pipeline produces which layer. These onboarding requests run through a shared queue with per-source limits, so a burst of new projects or layers cannot overrun the upstream data services, the same pacing discipline that keeps the daily updates inside their rate limits.
An account holder can rotate their own key at any time. The previous key stops working the instant the replacement is issued, with no overlap window, so a suspected leak can be closed at once; a key can also be issued with an expiry date for time-limited access. An account can read its own current usage, meaning its consumption against the hourly rate limit and the number of projects it holds, which is the basis for the per-account cost accounting the service will add as it moves toward general availability.
Once finalized, access to this API will be granted upon issuance of an API key and subject to terms along these lines:
Permitted use. The API and the data it returns are free to use for non-commercial purposes, including academic research, journalism, humanitarian response, and public health practice. Any publication, report, or product that uses the API's output must include attribution to CrisisReady.
Commercial use. Use of the API or its output in a commercial product or service requires a separate written agreement. Contact datascience_crisisready@harvard.edu.
Upstream attribution. Several underlying data sources carry their own attribution requirements independent of these terms. Most notably, whenever this API's output is published or redistributed, the following Copernicus/ERA5 statement is required: "T2m, heat index, and the UTCI/WBGT thermal-comfort inputs derived from it are generated using Copernicus Climate Change Service (C3S) information via the ERA5 reanalysis (2026). Neither the European Commission nor ECMWF is responsible for any use that may be made of the Copernicus information or data it contains." Complying with these requirements is a condition of use. Full per-source attribution and licensing notes for the rest of the fourteen external data products are available on request to datascience_crisisready@harvard.edu.
No warranty. The API and its output are provided "as is," without warranty of accuracy, completeness, or availability. CrisisReady is not liable for decisions made based on this data.
Changes. The API is in early access (see Versioning & support, below); these terms and the service's rate limits and pricing may change, with advance notice to existing users before changes take effect against their existing usage.
A methods paper describing this system's approach is in preparation, and the underlying work will be registered with Harvard Dataverse for a formal, citable DOI.
The API is at v1; the URL path carries the major version
(/v1/evaluate). The API is in early access (see Access,
limits & terms above for what may still change). The intent, not yet a fully ratified
policy, is that testers using
the API before general availability would get at least 30 days' notice before any change
takes effect against their existing usage, and that a breaking change would ship under a
new version path rather than alter /v1/'s existing behavior. A fuller,
formally adopted deprecation policy is deferred until there's an actual /v2/
to write one against.
For questions about coverage, licensing for a specific use case, or integration support, contact datascience_crisisready@harvard.edu.