Guide

Open-Elevation and Open Topo Data: limits and alternatives

Open-Elevation and Open Topo Data are open-source elevation APIs, and both run a public server you can try without setting anything up.

Both public servers are meant for light use. The Open Topo Data server allows 100 locations per request, one request per second and 1,000 requests a day. Open-Elevation allows 1,000 coordinates a month with a free key, or 500 a month per IP address without one. For more, run your own server or use a hosted API.

Open Topo Data

Open Topo Data is an MIT-licensed server for elevation datasets. Its public API at api.opentopodata.org is free, with these limits:

  • at most 100 locations per request,
  • at most one request per second,
  • at most 1,000 requests a day.

That is up to 100,000 locations a day for a well-batched script, but only 1,000 single-point lookups for an app. The documentation describes the public API as available for testing, without any service guarantees; the project is funded by paid hosting. It offers many datasets, from 8 m in New Zealand to SRTM, ASTER and EU-DEM, chosen in the URL: /v1/srtm90m?locations=….

Open-Elevation

Open-Elevation is a GPL-licensed lookup server with a public API at api.open-elevation.com. Its current plans, as listed on its website in October 2026:

  • without a key: 500 coordinates a month per IP address, from 250 m SRTM data;
  • free key: 1,000 coordinates a month;
  • paid: EUR 5.99 for 3,000, EUR 14.99 for 100,000 and EUR 59.99 for 400,000 coordinates a month, with 90 m data.

Its data is SRTM from NASA, which covers the Earth between 60° north and 56° south. Northern Scandinavia, most of Alaska and Antarctica are outside it. For points without data, the answer is an elevation of 0 with no dataset, so check the dataset field before you trust a zero.

Running your own server

Both projects are open source and run in Docker. What it takes:

  • Data. Download the elevation tiles yourself. For one country, SRTM or Copernicus tiles take a few gigabytes. Our worldwide store, Copernicus GLO-90 (26,475 tiles) plus the GEBCO ocean grid, is 54 GB.
  • A server with fast disk; lookups are cheap, so a small machine handles a lot of traffic.
  • Operations: updates, monitoring, backups, TLS, and access control if it is reachable from the internet.

It pays off when you need a special dataset (lidar at 1 m, a national model) or must keep lookups inside your own network. For worldwide 90 m data it is usually more work than it is worth.

A hosted alternative with the same format

The overpass.ch elevation API answers in the format of Open Topo Data and the Google Elevation API, worldwide on land and at sea:

Locations per requestRequests per minuteLookups per monthPrice
Free plan1'000301 millionfree
Elevation plan10'00012050 millionCHF 5 or €5 a month

Land heights come from Copernicus GLO-90, a 90 m grid that covers the whole Earth, Antarctica and the far north included. At sea the answer is the depth from GEBCO. Every Overpass plan includes elevation lookups too; see pricing.

Switching your code

From Open Topo Data

Drop the dataset from the path and put in your key. locations (including enc: polylines) and samples work the same, and the answer has the same format:

https://api.opentopodata.org/v1/srtm90m?locations=46.0207,7.7491
→ https://api.overpass.ch/v1/YOUR_API_KEY/elevation?locations=46.0207,7.7491

You don't choose a dataset: Copernicus answers on land and GEBCO at sea, and dataset in each result says which. Heights are always interpolated bilinearly, the default in Open Topo Data, and missing data is null. GeoJSON output (format=geojson) is not available.

From Open-Elevation

Open-Elevation uses latitude and longitude; here the points are [lat, lon] pairs or objects with lat and lon, and results have location.lat and location.lng:

import requests

points = [{"latitude": 46.0207, "longitude": 7.7491}, {"latitude": 69.65, "longitude": 18.96}]

r = requests.post("https://api.overpass.ch/v1/YOUR_API_KEY/elevation",
                  json={"locations": [[p["latitude"], p["longitude"]] for p in points]}, timeout=30)
r.raise_for_status()
results = [{"latitude": res["location"]["lat"], "longitude": res["location"]["lng"],
            "elevation": res["elevation"]} for res in r.json()["results"]]
print(results)

The second point is Tromsø, at 69.65° north: outside SRTM, but covered by Copernicus.