Line of Sight API | Radio path and terrain profile between two points
Access & limitsPublic, no key needed · Medium▾
Open to everyone. A free API key from your profile raises the limits: send it in an X-API-Key header, or as api_key= in the address.
| 5 minutes | Hour | Day | |
|---|---|---|---|
| Without a key | 10 | 60 | 300 |
| With a key | 30 | 200 | 1,500 |
Log in to create a free key on your profile page.
Every answer carries X-RateLimit-Remaining and X-RateLimit-Reset. Over a limit, the answer is error 429 with retry_after in seconds. Refused requests do not count.
Works out whether two points can see each other over the real shape of the ground between them. It walks the great circle from A to B in steps of about one terrain cell, reads the ground height at every step from our elevation store, adds the curvature of the earth, and compares the result with the straight line between the two antennas.
It returns whether the path is clear, where it is blocked if it is not, how much of the first Fresnel zone is clear, and the height each end would need for the line to get through. The ground heights alone are available from the terrain elevation API, and there is a map and chart version of this endpoint in the line of sight tool.
from to
Parameters
| Name | Default | What it does |
|---|---|---|
from | required | Point A as lat,lon in decimal degrees. lat1= and lon1= work too. |
to | required | Point B as lat,lon. lat2= and lon2= work too. |
h1 | 1.5 | Height of the antenna at A above the ground, in metres. |
h2 | 1.5 | Height at B above the ground. Use this for a rocket in the air. |
freq | 868 | Frequency in MHz, used for the Fresnel zone only. |
mode | radio | radio uses 4/3 of the earth radius for atmospheric refraction. optical uses the true radius. |
step | cell size | Sample spacing in metres. Left alone it follows the terrain tier, between 30 and 120 m. |
profile | 1 | Set to 0 to leave out the per sample arrays and get only the verdict. |
corridor | 0 | Set to 1 to add a block of ground either side of the route for 3D use. |
along, across | 280, 170 | Corridor sample counts along the route and across it. Caps are 800 and 400. |
width | 0.8 | Corridor width as a fraction of the route length. |
over | 0.15 | How far the corridor runs past each end, as a fraction of the route length, so the two points sit inside the block rather than on its edges. |
Example
A valley floor in the Lake District looking at Scafell Pike, 16.7 km away on a bearing of 301 degrees, with a handheld at each end:
curl "https://www.altimetercloud.com/cz/api/los/?from=54.3760,-2.9910&to=54.4542,-3.2116&h1=1.5&h2=1.5&profile=0"
{
"success": true,
"distance_m": 16712.4,
"distance_km": 16.712,
"bearing_deg": 301.2,
"step_m": 30.9,
"samples": 542,
"mode": "radio",
"k_factor": 1.3333,
"freq_mhz": 868,
"a": { "lat": 54.376, "lon": -2.991, "ground_m": 75.4, "height_m": 1.5,
"antenna_m": 76.9, "tier": "ultra" },
"b": { "lat": 54.4542, "lon": -3.2116, "ground_m": 970.9, "height_m": 1.5,
"antenna_m": 972.4, "tier": "ultra" },
"clear": false,
"clear_fresnel": false,
"marginal": false,
"clearance_m": -84.2,
"fresnel_pct": -220.4,
"margin_m": 2,
"worst": { "distance_m": 6234.1, "lat": 54.4051, "lon": -3.0868,
"ground_m": 542.0, "sightline_m": 457.8, "clearance_m": -84.2,
"fresnel_r_m": 38.2 },
"blocked_at": { "distance_m": 6234.1, "lat": 54.4051, "lon": -3.0868,
"ground_m": 542.0, "sightline_m": 457.8, "clearance_m": -84.2,
"fresnel_r_m": 38.2 },
"need": { "a_m": 116.3, "b_m": 227.5, "a_fresnel_m": 168.9,
"b_fresnel_m": 330.1, "silly_m": 5000 },
"tiers": { "ultra": 542 },
"datum": "EGM96 mean sea level",
"units": "metres"
}
The numbers above show the shape of the reply. Run the playground below for live figures, since the store is updated from time to time.
What the fields mean
| Field | Meaning |
|---|---|
clear | True when nothing between the two antennas rises above the straight line joining them, with the earth bulge added to the ground. |
clear_fresnel | True when 60 percent of the first Fresnel zone is also clear, which is what a radio link wants rather than a bare line. |
marginal | True when the line clears, but by less than margin_m. Treat it as blocked until you have stood there. |
clearance_m | How far the line passes above the ground at the tightest point. Negative means blocked, by that much. |
fresnel_pct | How much of the first Fresnel zone is clear at its tightest point, as a percentage. 60 or more is good, under 60 costs a few dB. |
margin_m | How much a sharp ridge crest can sit above its cell mean at the coarsest tier on this route: 2 m at 1 arcsec, 5 m at 3, 10 m at 6, 25 m at 18. |
blocked_at | The first sample that breaks the line, or null when the path is clear. worst is always present and is the tightest point either way. |
need.b_m | The height above ground at B that would put the line clear of everything in between. need.a_m is the same for A. A figure above silly_m means the obstruction sits too close to the other end for any height to fix it. |
need.b_fresnel_m | The height for 60 percent Fresnel clearance as well. On flat ground this is always large, because the ground close to a low antenna is inside the zone whatever you do. |
profile | Four arrays of count entries: distance_m along the path, ground_m elevation, curve_m the earth bulge to add to it, and fresnel_r_m the first zone radius there. |
Drawing the profile
The curvature of the earth is carried by adding the bulge to the ground rather than bending the sight line, which is the usual path profile convention and means the sight line can be drawn as a straight line between a.antenna_m and b.antenna_m. So for each sample i:
terrain height to plot = profile.ground_m[i] + profile.curve_m[i]
sea level to plot = profile.curve_m[i]
sight line = a.antenna_m + (b.antenna_m - a.antenna_m) * i / (count - 1)
Fresnel edges = sight line +/- 0.6 * profile.fresnel_r_m[i]
The bulge is d1 * d2 / (2 * k * R) with R the mean earth radius and k the k_factor in the reply: 1 optically, 4/3 for radio.
Errors
{ "success": false, "error": { "code": "413",
"message": "routes are limited to 500 km and this one is 605 km" } }
412 covers bad or missing coordinates and two points in the same place. 413 is a route over 500 km. Line of sight much past 100 km is blocked by the earth itself whatever the ground does, so the cap is generous already.
Limits and honesty
- Heights are bare ground. No trees, no buildings, no masts. A line that clears a ridge by 5 m does not clear the forestry on it.
- Every cell holds the mean height of the ground inside it, so a crest reads lower than it is. That is what
margin_mandmarginalare for. - Elevations are EGM96 mean sea level, so they compare directly with a barometric altitude.
- Sea and anywhere without data read zero.
- This is geometry, not a link budget. It says nothing about transmit power, antenna patterns, receiver sensitivity or interference.
- No rate limit, no key, no logging of who asked. Please keep batch use sensible.
Try it
Crediting AltimeterCloud
Free to use. If you use this API, or anything made from the answers, in a commercial product or service, credit AltimeterCloud with a link to www.altimetercloud.com at the point of use: on the screen, page or printout where the data appears, for example “Data from AltimeterCloud.com”. Any credits the data's own sources ask for, listed on this page, apply as well.
Terrain data credits
The ground heights come from the Terrain Tiles dataset (Mapzen / Tilezen, on AWS Open Data), reduced into resolution tiers by Altimeter Cloud. Wherever you show heights from this API, credit their sources. Each answer carries a short form of the list below in its credits field.
- ArcticDEM terrain data DEM(s) were created from DigitalGlobe, Inc., imagery and funded under National Science Foundation awards 1043681, 1559691, and 1542736
- Australia terrain data © Commonwealth of Australia (Geoscience Australia) 2017
- Austria terrain data © offene Daten Österreichs – Digitales Geländemodell (DGM) Österreich
- Canada terrain data contains information licensed under the Open Government Licence – Canada
- Europe terrain data produced using Copernicus data and information funded by the European Union - EU-DEM layers
- Global ETOPO1 terrain data U.S. National Oceanic and Atmospheric Administration
- Mexico terrain data source: INEGI, Continental relief, 2016
- New Zealand terrain data Copyright 2011 Crown copyright (c) Land Information New Zealand and the New Zealand Government (All rights reserved)
- Norway terrain data © Kartverket
- United Kingdom terrain data © Environment Agency copyright and/or database right 2015. All rights reserved
- United States 3DEP (formerly NED) and global GMTED2010 and SRTM terrain data courtesy of the U.S. Geological Survey
The licences behind each statement are on the terrain tiles attribution page.



















