A Google Elevation API alternative
The Google Elevation API is easy to use but expensive at volume, and its terms restrict what you may do with the results. The overpass.ch elevation API takes the same requests and returns the same JSON, so switching is mostly a change of URL.
locations, path and samples parameters and the response stay the same:
https://maps.googleapis.com/maps/api/elevation/json?locations=46.0207,7.7491&key=GOOGLE_KEY → https://api.overpass.ch/v1/YOUR_API_KEY/elevation?locations=46.0207,7.7491
The same request, the same answer
curl 'https://api.overpass.ch/v1/YOUR_API_KEY/elevation?locations=46.0207,7.7491|35.95,-5.6'
{
"status": "OK",
"results": [
{ "elevation": 1606.3, "location": { "lat": 46.0207, "lng": 7.7491 },
"resolution": 90, "surface": "land", "dataset": "copernicus-glo90" },
{ "elevation": -678.3, "location": { "lat": 35.95, "lng": -5.6 },
"resolution": 460, "surface": "sea", "dataset": "gebco-2026" }
],
"lookups": 2
}
| Google Elevation API | overpass.ch | |
|---|---|---|
locations=lat,lng|… | yes | yes |
Encoded polylines (enc:…) | yes | yes |
path with samples | yes | yes, and each result has its distance from the start |
status, results[].elevation, location.lat/lng, resolution | yes | yes |
| Locations per request | 512, GET only | 10'000 (1,000 on Free); GET, or POST with JSON or a GPX file |
| Route profile with ascent and descent | no | /elevation/profile |
| Land or sea in the answer | no | surface and dataset |
| Errors | HTTP 200 with status such as INVALID_REQUEST | HTTP status codes (400, 401, 429) with error and message |
Code that checks status == "OK" and reads results still works. If your code branches on the Google error statuses, check the HTTP status code instead.
Switching your code
import os
import requests
URL = f"https://api.overpass.ch/v1/{os.environ['OVERPASS_CH_KEY']}/elevation"
def elevations(points): # [(lat, lng), …]
out = []
for i in range(0, len(points), 1000):
r = requests.post(URL, json={"locations": points[i:i + 1000]}, timeout=30)
r.raise_for_status()
out += [res["elevation"] for res in r.json()["results"]]
return out
print(elevations([(46.0207, 7.7491), (45.9763, 7.6586)]))
const res = await fetch("https://api.overpass.ch/v1/YOUR_API_KEY/elevation", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ locations: [[46.0207, 7.7491], [45.9763, 7.6586]] }),
});
if (!res.ok) throw new Error(await res.text());
const { results } = await res.json();
console.log(results.map((r) => r.elevation));
- The key goes into the path, or into an
X-API-Keyheader, instead ofkey=. - Batches: you no longer need to split at 512 locations. Up to 1,000 fit into one request on the free plan, 10'000 on paid plans.
- In the browser: the
ElevationServiceof the Maps JavaScript API cannot be pointed at another server. Call the endpoint withfetchas above, with a key restricted to your own domain in the dashboard.
What it costs
Google bills per request, of up to 512 locations: 5,000 requests a month are free, then USD 5 per 1,000 up to 100,000 requests, with lower rates above. overpass.ch counts lookups, one per location, and the free plan includes 1 million a month.
| Locations per month | In batches of 512 or more | One location per request | ||
|---|---|---|---|---|
| overpass.ch | overpass.ch | |||
| 1 million | free (about 2,000 requests) | Free plan, or Elevation for CHF 5 | about USD 3,575 | Elevation, CHF 5 |
| 10 million | about USD 73 | Elevation, CHF 5 | about USD 11,500 | Medium, CHF 59 |
| 50 million | about USD 465 | Elevation, CHF 5 | about USD 26,700 | Large, CHF 149 |
Google list prices for the Elevation API in October 2026: 5,000 free requests a month, then USD 5.00 per 1,000 up to 100,000, USD 4.00 to 500,000, USD 3.00 to 1 million, USD 1.50 to 5 million and USD 0.38 above. One location per request is the typical case of an app that looks up a point per click or per user. On overpass.ch that case is limited by requests per minute rather than by lookups: 120 a minute on the Elevation plan, 600 on Medium and 1200 on Large. Prices in CHF; the same amounts in EUR. The free plan is for evaluation and prototypes.
If you batch a few hundred thousand locations a month, the free allowance from Google may be enough. The costs differ for single-point lookups and at high volume.
Storing results and showing them on a map
- Google: its Elevation API policies say content should not be pre-fetched, cached or stored, and results shown on a map must be shown on a Google Map. Without a map, you show the Google logo and attribution.
- overpass.ch: you may store the results and show them on any map, for example OpenStreetMap with Leaflet or MapLibre. When you publish or display them, credit the data sources, as described in the documentation and the terms.
Resolution and accuracy
Land heights come from the Copernicus GLO-90 model, a worldwide grid with 90 m spacing; sea depths from the GEBCO grid (about 460 m). Google combines several sources and is often finer, especially in cities and in steep mountains. With 90 m data:
- villages, valleys, roads and rolling terrain are typically within a few metres (Zermatt reads 1,606 m);
- sharp summits read low: the Matterhorn 4,210 m instead of 4,478 m;
- forests and large buildings are part of the surface.
It is a good fit for altitude bands, route profiles, enriching places and analysis over regions. For engineering, aviation or anything where a few metres matter, use a finer, local model. The Elevation API page has more measurements.