Data APIdocs

Green space and polygons

Green space in Data API isn't a list of named parks. It's a layer of geographic polygons — actual shapes on the ground — covering parks, recreation grounds, forests, gardens, golf courses, and other open or vegetated land. Those polygons answer two distinct questions: what's around me? (which named parks and vegetation sit nearby) and how much green stuff am I in? (what share of the area is open space).

This page explains where the polygons come from, what classes exist, how the area maths works, and why "Hyde Park in London" and "Hyde Park in Manchester" are kept as separate shapes rather than collapsed into one row.

Overture is the source

The polygon layer comes from the Overture Maps Foundation's land-cover layer. Overture's land data is itself a curated blend that draws heavily from OpenStreetMap, with cleanup and class consolidation applied. We ingest the raw polygon shapes once per country rebuild.

What we get for each polygon:

  • A geometry — the exact shape on the ground, in WGS-84 coordinates. Hyde Park in London is the actual lassoed boundary; a forest is its mapped extent.
  • A class — what kind of place it is (see the next section).
  • A name — where a name exists. Many polygons (a generic grass verge, an unnamed pond) are unnamed and carry through unnamed.
  • A stable ID — Overture's UUID. Useful for cross-referencing if you have other Overture-keyed data.

Polygon classes

We ship two top-level classes, with sub-classes within each. Together they make up the "green space" surface the land-cover endpoints read from.

  • Land — forest, wood, beach, sand, dune, wetland, island, heath, grassland, meadow. The natural-area set.
  • Land use — park, village green, dog park, nature reserve, national park, and the other human-usable categories.

How polygons are stored and queried

Polygons aren't stored as a separate "polygons table" you'd join against in the API. Instead we precompute a cell-level aggregate: every polygon is split into the H3 cells it covers, and we store the per-cell contribution (which polygon, what fraction of the cell falls inside it, what's the polygon's class). The aggregation runs at two H3 resolutions in parallel — 9 (~175 m hex) and 10 (~65 m hex) — so a query can pick the granularity it needs.

This matters because it changes how you reason about queries. When you ask the API for "the green space inside this isochrone," what happens under the hood is:

  1. The isochrone gives us a set of H3 cells (from the sibling TravelTime Routing API's h3-fast endpoint).
  2. We look up the polygon-class aggregates for those cells.
  3. We sum the area contribution per class, intersected with the reachable footprint.
  4. We return a per-class total area and a list of the largest named polygons that fall inside.

You don't see the polygon-to-cell precomputation. You see a clean response that says "3,400 m² of parks, 8,100 m² of grass — and the named parks that contribute are Hyde Park (1,800 m²), Green Park (900 m²), St. James's Park (700 m²)."

Multi-polygon preservation

A subtle but important property: when two polygons share a name, they're kept as separate shapes. "Hyde Park" in central London and "Hyde Park" in Manchester are two distinct polygons in two disjoint sets of H3 cells. Our pipeline never collapses by name — collapse by name only would silently merge two parks in different cities into one inflated rollup.

Within a single cell, if two same-named polygons happen to overlap (rare, but it happens near city-region boundaries), both contribute. You can see this in the API: the top_names array for a cell can list "Hyde Park" twice with different IDs and different area contributions if the cell happens to straddle a boundary.

Two ways to ask

The layer has a cell-keyed endpoint and an entity-keyed one. They read the same aggregate and answer different questions.

GET /v1/h3/land-cover — cell-keyed. "What green space is in each of these cells?" Takes the standard geographic input: exactly one of cells, bbox, or center_lat + center_lng + radius_m.

curl -H "Authorization: Bearer $POI_API_KEY" \
  "$POI_BASE/v1/h3/land-cover?country=GB&bbox=51.50,-0.17,51.52,-0.15&resolution=9&limit=50"

type selects the top-level buckets (green-space, beaches, or both, the default), while include and exclude filter by sub-class — so include=park keeps parks and drops the gardens and recreation grounds that would otherwise ride along.

GET /v1/polygons — entity-keyed. "Which parks are in this area?" One row per Overture polygon rather than per cell, sorted by area descending — this is the endpoint to reach for when you want a list of named places rather than a surface.

curl -H "Authorization: Bearer $POI_API_KEY" \
  "$POI_BASE/v1/polygons?country=GB&bbox=51.50,-0.17,51.52,-0.15&limit=10"

It accepts exactly one of bbox or cells; sending both, or neither, returns 400 with code invalid_input rather than listing a whole country. Its area_m2 is each polygon's own area, not the part falling inside your query — as is land-cover's polygons[].area_m2. The clipped figure exists only as reachable_area_m2 below, and it is one total, not per polygon.

What "reachable area" actually means

GET /v1/h3/land-cover carries reachable_area_m2 on the response envelope. The maths is:

The approximate (bounding-box) polygon area falling inside the requested cells, summed over distinct polygons and each pro-rated by the share of its cell footprint you asked for. The endpoint never sees your isochrone — it only knows the cells you sent. It covers every matching polygon in the per-cell top-N arrays, so limit never truncates it; polygons beyond the top-N cut are absent, which can bias it either way.

This is more accurate than "is the polygon inside the isochrone yes/no" — it correctly attributes a sliver of park near the isochrone edge as a partial contribution.

To turn the absolute into a share, divide it by the total area of the cells you asked for:

open_space_pct = reachable_area_m2 / sum(reachable cell area)

"73% open space" then means 73% of the reachable footprint, by area, sits inside an open-space polygon — parks, forests, gardens, recreation grounds together.

Edge cases worth knowing

  • Massive polygons are filtered out. Country boundaries, EEZ marine areas, and any polygon larger than 5,000 km² are dropped before cell-level aggregation. They'd swamp every query they intersected without adding useful information. The largest park or forest you'll see is still well below this cap.
  • Tiny polygons get res-9 only. Polygons under 70 m in extent (small ponds, garden plots) are aggregated at resolution 9 only, not resolution 10. The res-10 hex is smaller than the polygon itself, so the math gets noisy. Resolution-9 queries see them; res-10 queries see them missing — a deliberate trade between precision and pollution.
  • Polygons can move between rebuilds. Overture's land layer is itself a moving target; a park's mapped boundary can be refined or simplified between releases. The last_refreshed on /v1/stats tells you which snapshot you're reading; if you cache polygon results, key them on it.
  • Water bodies are not ingested. Lakes, rivers, ponds, reservoirs, and canals don't appear as polygons — Overture's coverage at our source resolution is too patchy to ship reliably (e.g. the Thames and several central-London lakes are missing in places). Wetlands still arrive via the land wetland sub-class, so a marsh or fen will show up; a lake or river will not.

Where next