Overview
Overpass is a query API for OpenStreetMap. Instead of downloading a whole country extract and sorting the mess out later, you can request a narrow slice of data: schools inside a district, clinics within a buffer, bridges along a corridor, or all waterways crossing a project area.
That makes it useful for early-stage screening, rapid map assembly, and situations where you need transparency on exactly which tags were asked for.
Why it matters
- It keeps your first extraction lean.
- It exposes the tag logic directly, which makes assumptions reviewable.
- It works well when you need quick thematic pulls before committing to a heavier pipeline.
- It is often the simplest bridge between an idea and a usable GeoJSON layer.
When to use
Use Overpass when:
- The area of interest is relatively bounded.
- You know the feature classes you are looking for.
- You need a reproducible query that can be rerun later.
- You want to inspect OSM tagging rather than inherit a pre-processed black box.
Avoid using it as your only acquisition path when:
- The study area is country-scale or larger.
- You need every road, building, or relation in a large region.
- The workflow will become a scheduled production job better served by
.pbfextracts and local processing.
Inputs
Typical inputs are:
- An area of interest defined as a bounding box, polygon, district name, or admin relation.
- A feature theme such as schools, health facilities, waterways, substations, or settlements.
- A tag strategy that reflects local mapping patterns rather than one idealized tag.
Workflow and method
- Define the spatial frame.
- Define the tag families that represent the feature class.
- Run a narrow query first and inspect returned tags.
- Expand tag coverage only after reviewing what the first result actually contains.
- Export to GeoJSON or JSON and normalize field names in the next pipeline stage.
Live extraction sketch
const temaneAmenities = await FileAttachment("../../data/examples/temane-amenities.geojson").json();
const temaneRoads = await FileAttachment("../../data/examples/temane-roads.geojson").json();
const temanePower = await FileAttachment("../../data/examples/temane-power.geojson").json();
({
amenities: temaneAmenities.features.length,
roads: temaneRoads.features.length,
power: temanePower.features.length
})
const overpassSampleQuery = buildOverpassQuery({
bbox: [-22.25, 34.95, -21.5, 35.35],
filters: ['["amenity"="place_of_worship"]', '["power"="substation"]'],
timeout: 90
});
overpassSampleQuery
Run it locally
The repo now contains an actual Overpass query file and a fetch script:
queries/temane_amenities_power.overpassqlscripts/overpass/fetch_osm_overpass.sh
./scripts/overpass/fetch_osm_overpass.sh \
queries/temane_amenities_power.overpassql \
data/osm/temane_amenities_power_raw.json
After that raw fetch, the next local step is to normalize or export the JSON into GeoJSON for the pages and downstream scripts.
Run it in the browser
Inside Observable Framework, the browser-side version is simply a JavaScript cell that constructs the query text, lets you inspect it, and can be paired with a fetch if you want an in-browser demo:
const browserQuery = buildOverpassQuery({
bbox: [-22.25, 34.95, -21.5, 35.35],
filters: ['["amenity"="place_of_worship"]', '["power"="substation"]'],
geometryTypes: ["node", "way", "relation"],
out: "center tags"
});
browserQuery
renderCountBars([
{label: "Amenity points", value: temaneAmenities.features.length},
{label: "Road segments", value: temaneRoads.features.length},
{label: "Power features", value: temanePower.features.length}
], {title: "Sample extraction counts from the Temane source layers"})
renderGeojsonMap({
title: "Temane extraction preview",
subtitle: "Roads, power, and amenity points from the local example dataset.",
layers: [
{data: temaneRoads, stroke: "#d7b97a", strokeWidth: 1.2, opacity: 0.8},
{
data: temanePower,
stroke: (feature) => feature.geometry.type === "LineString" ? "#8db49a" : "#f1d391",
fill: (feature) => feature.geometry.type === "Point" ? "#f1d391" : "none",
pointRadius: 3.4,
strokeWidth: 1.1,
opacity: 0.95
},
{data: temaneAmenities, fill: "#e08bb6", stroke: "#ffffff", pointRadius: 4.5, strokeWidth: 0.8}
]
})
renderFeatureTable(temaneAmenities.features, [
{label: "OSM id", value: (feature) => feature.properties?.["@id"]},
{label: "Amenity", value: (feature) => feature.properties?.amenity},
{label: "Name", value: (feature) => feature.properties?.name ?? feature.properties?.religion}
], {title: "Sample returned features", limit: 6})
Bounding box versus area
Both approaches work, but they behave differently.
| Approach | Good for | Strengths | Weaknesses |
|---|---|---|---|
| Bounding box | Fast exploratory pulls and corridor windows | Simple, explicit, easy to automate | Returns features outside the true study boundary if the bbox is loose |
| Area / relation | Named admin units or well-known regions | Better semantic tie to a place | Depends on OSM relation quality and can be slower or inconsistent |
Bounding box pattern
Use a bbox when the study area is defined by a project extent, a buffer, or a provisional review window.
Area pattern
Use an area query when the unit matters semantically, such as a district or municipality you will reference in reporting.
Tag strategy
A good tag strategy is broader than one tag but narrower than a kitchen sink query.
For example, a school search may need to consider:
amenity=schoolamenity=collegebuilding=schooloffice=educational_institution
Not every one of these belongs in every analysis. The point is to review what is locally used in OSM and then decide which tags should count as a receptor, which should be flagged as possible matches, and which should be excluded.
Query design patterns
Pattern 1: multiple tags for the same concept
Pattern 2: paired feature and transport context
Use this when you want both a receptor and the network that serves it.
Pattern 3: candidate settlements
Tools, code, and export use
Common working flow:
- Draft and test the query in Overpass Turbo.
- Review tags and geometry types in the JSON response.
- Export as GeoJSON for immediate inspection.
- Rename the file with an area, theme, and date stamp.
- Normalize schema in your pipeline so later stages do not depend on raw OSM field variability.
Recommended file pattern:
moz_temane_osm_school-clinic_raw_2026-03-19.geojson
moz_temane_osm_school-clinic_clean_2026-03-19.geojson
Outputs
Expected outputs from an Overpass pull include:
- Raw response JSON or GeoJSON.
- A short note on the exact query used.
- A cleaned derivative layer with harmonized fields.
- A QA note on suspicious tags, obvious duplicates, and missing expected features.
Common pitfalls
- Querying only nodes and forgetting ways or relations.
- Assuming one canonical tag captures the whole feature class.
- Treating OSM names as authoritative spellings without local verification.
- Using area queries against poorly mapped admin relations and not checking what the relation actually covers.
- Exporting the raw pull straight into reporting maps without a cleaning pass.
Limitations
Overpass is only as good as the underlying mapping. Some places have rich feature coverage and weak attributes; others have settlement names but almost no public-service tags. It also does not solve conflation, deduplication, or project-specific classification on its own.