OpenStreetMap stores the height of a summit in the ele tag, if a mapper added one. Add elevation=1 to the URL and overpass.ch also returns the height of the terrain at every result, from the Copernicus 90 m elevation model. So you get a height even where ele is missing.
This query finds the named peaks around Zermatt. The table lists them from the highest, with the height from the model next to the ele tag.
The query
[out:json][timeout:25]; node["natural"="peak"]["name"](45.90,7.60,46.10,7.95); out;
Run it
Live result from overpass.ch, cached for up to 12 hours. Map data © OpenStreetMap contributors (ODbL). Heights produced using Copernicus WorldDEM™-90 © DLR e.V. 2010-2014 and © Airbus Defence and Space GmbH 2014-2018 provided under COPERNICUS by the European Union and ESA; all rights reserved. Sea depths: GEBCO Compilation Group (2026) GEBCO 2026 Grid.
How it works
- The query itself is an ordinary Overpass query. The heights come from the URL:
/interpreter?elevation=1adds anelevationfield in metres to every node of a JSON answer, right afterlon. ["name"]keeps named summits only. Unnamed ones are mostly minor tops on a ridge.- Compare the two values. On the peaks here, the model reads a median of about 60 m below
ele: a 90 m grid averages a summit with its slopes, so sharp peaks come out low. The Dufourspitze reads 4,501 m instead of 4,634 m. - Every height uses one elevation lookup from your monthly allowance, here about 170. Overpass requests are counted separately.
Variations
- Prefer the tag and fall back to the model: in Python,
height = el["tags"].get("ele") or el["elevation"]. - Only the highest summits: filter
elein the query, as in peaks higher than 4000 m. - On passes, huts and villages the model is much closer to the truth: see road passes and their height.
Run it from your code
The query is unchanged; elevation=1 in the URL adds the heights. Each height uses one lookup from your elevation allowance.
curl 'https://api.overpass.ch/v1/YOUR_API_KEY/interpreter?elevation=1' \
--data-urlencode 'data@query.overpassql'
import requests
query = open("query.overpassql").read()
r = requests.post("https://api.overpass.ch/v1/YOUR_API_KEY/interpreter",
params={"elevation": 1}, data={"data": query}, timeout=120)
r.raise_for_status()
for el in r.json()["elements"]:
height = el.get("elevation") or el.get("center", {}).get("elevation")
print(el.get("tags", {}).get("name"), height)
const res = await fetch("https://api.overpass.ch/v1/YOUR_API_KEY/interpreter?elevation=1", {
method: "POST",
body: new URLSearchParams({ data: query }),
});
if (!res.ok) throw new Error(await res.text());
const { elements } = await res.json();
for (const el of elements) console.log(el.tags?.name, el.elevation ?? el.center?.elevation);
Save the query as query.overpassql. It works the same in Overpass Turbo, QGIS and JOSM.