curl -O https://geekychris.github.io/tools/aviation-relay.py
python3 aviation-relay.py # public feeds + aviation weather
python3 aviation-relay.py --receiver http://piaware.local:8080 --beast piaware.local:30005 --raw piaware.local:30002
Flight tracker
Live aircraft near you or any airport — on a map or an offline radar scope, in a sortable table, and as an "overhead now" list — from public ADS-B feeds or your own receiver's aircraft.json, with trails, altitude colours, emergency-squawk alerts and a watchlist.
Added
Works with
- Plane spotter Aviationshares the receiver and relay set up here
How to use it
Pick a Source, say Where (an airport code such as KSFO or LHR, lat, lon, a town — or tap
📍 My location), choose a radius and press ▶ Start. The tool polls the source every few seconds,
and only while the tab is visible.
-
Map — aircraft drawn at their reported track, coloured by altitude (orange low → green → blue → magenta at 40 000 ft; grey on the ground; a red outline for 7500/7600/7700), with range rings around the centre. Trails are built from successive polls (the selected aircraft, all, or none). The map is OpenStreetMap through Leaflet and loads only when this view is open; Radar (offline) draws the same picture with no map tiles, and is used automatically if the map cannot load.
-
Tap an aircraft for its callsign, ICAO address, registration and type (when the feed has them), barometric and geometric altitude, ground speed, vertical rate, track, squawk and what it means, distance and bearing from you, how high it is above your horizon, and when it was last seen. Links go to globe.adsb.lol (and your own tar1090 when you use a receiver); Look up asks adsbdb.com for registration, owner and the route on record — only when you tap it.
-
Table — every aircraft, sortable by any column, downloadable as CSV.
-
Overhead — aircraft more than 20° (or your choice) above your horizon, highest first, with the compass direction to look. Plane spotter does the same with your phone’s compass and camera.
-
Filters — altitude band, type, callsign/hex/registration/squawk search, military only (adsb.lol and adsb.fi flag known military airframes), emergencies only, hide aircraft on the ground; units in feet/knots/nautical miles, metric, or statute miles.
-
Watchlist — callsigns (
UAL1), prefixes (BAW*), registrations (N123AB) or hex addresses. A match in range shows a toast and, if you allow it, a system notification; emergency squawks alert too. The list stays in this browser (JSON export/import) and never goes into a link.
The first visit shows a recorded sample: a real snapshot of traffic around San Francisco from adsb.lol (15 October 2026, ODbL), moved forward by dead reckoning so it animates. It needs no network.
⛶ Full screen (or F) gives the map or radar the whole screen — the browser’s full screen where
it is allowed, otherwise a full-window layer (iPhone). The source panel and the aircraft details
start hidden; ◫ Panels brings them back. Escape leaves.
Sources
| Source | Terms | From this page |
|---|---|---|
adsb.lol ( |
Community feeders; data under the Open Database License (ODbL). Free API — the operator asks for modest use, and plans keys for non-feeders. |
Needs the relay |
adsb.fi open data ( |
Personal, non-commercial use; at most one request per second. |
Needs the relay |
OpenSky Network ( |
Non-commercial; anonymous users get 400 API credits a day and 10 s resolution, so it is polled at most every 30 s and is a fallback. Cite "The OpenSky Network, https://opensky-network.org". |
Needs the relay |
Your receiver ( |
Yours. |
Directly if it sends a CORS header and is reachable without mixed content (below), otherwise through the relay |
Why a relay? A web page may only read another site’s data if that site answers with an
Access-Control-Allow-Origin header (CORS). On 15 October 2026 none of the public ADS-B APIs did —
not for https://geekychris.github.io, not for http://localhost, not for any origin (OpenSky
answers only for its own site), and airplanes.live and adsb.one now refuse API use without contacting
them first. The tool still tries the source directly first, in case that changes; when it is blocked it
says so and offers the recorded sample. If the chosen source fails it falls back to the others and
shows which one answered and its terms.
With the gitwebsite app
If the gitwebsite app (or gw serve) is running on your computer, nothing else is needed: its companion
relays adsb.lol, adsb.fi, OpenSky and aviationweather.gov, and your receiver too once you set its
address in the app’s Companion settings. The tool asks the app first and keeps the relay script and the
direct paths below as fallbacks. In the app’s own preview it connects by itself; from this site press
⚡ Use the gitwebsite app (under Receiver & relay) and approve the 6-digit code in the app. While
it is in use a ⚡ Companion button in the header shows what goes through it, and disconnects.
Relay
Not needed if the gitwebsite app is running (above) — otherwise: aviation-relay.py is a single Python 3 file with no dependencies
(download it, or ⬇ aviation-relay.py under Receiver & relay). It runs
on your computer, listens on http://127.0.0.1:8099, and adds the CORS headers. Browsers treat
localhost/127.0.0.1 as a secure origin, so this https page may call it (Chrome, Edge and Firefox; Safari
may block plain-http localhost — use the HTTPS options below on an iPhone).
Then set Relay address to http://127.0.0.1:8099 and press Test relay. Routes:
/adsblol/…, /adsbfi/…, /opensky/…, /awc/… (aviationweather.gov, for the
aviation weather tool), /receiver/… (your --receiver), and two
WebSockets for the Mode S decoder: ws://127.0.0.1:8099/beast (Beast binary from
port 30005) and ws://127.0.0.1:8099/raw (AVR text from port 30002). It only forwards to those
addresses (it is not an open proxy), caches each answer for 2 s so several tabs don’t multiply the load,
and binds to 127.0.0.1 unless you pass --host. Only this site and local previews (http://127.0.0.1:…, http://localhost:…, such as the gitwebsite app) may read through it, so other web pages you have open can’t see your receiver; add another origin with --allow-origin https://example.org. Chrome may ask whether this site may "access devices on
your local network" the first time — allow it. On a Mac with the python.org installer, the relay finds
root certificates from certifi or /etc/ssl/cert.pem.
Your own receiver
You don’t need one — but a receiver shows every aircraft your antenna hears, with signal strength and message counts, no rate limits, and no one else’s terms. What to buy and run:
-
SDR dongle: an RTL-SDR Blog V4 (general-purpose, ≈ US$40) or a FlightAware Pro Stick Plus (built-in 1090 MHz filter and amplifier — the easiest good result).
-
Antenna: a 1090 MHz antenna — the FlightAware 66 cm antenna, or a home-made quarter-wave ground plane or collinear. Height and a clear view of the horizon matter far more than anything else; keep the coax short (or use a filtered LNA at the antenna).
-
Computer: a Raspberry Pi (3B+, 4, 5 or Zero 2 W) with a good power supply.
-
Software, either:
-
PiAware (an SD-card image with dump1090-fa and the SkyAware map; feeding FlightAware is optional but earns a free account) —
aircraft.jsonis athttp://<pi>/skyaware/data/aircraft.json(andhttp://<pi>:8080/data/aircraft.jsonon older images); or -
readsb + tar1090 (wiedehopf’s install scripts on Raspberry Pi OS, or the adsb.im image) —
aircraft.jsonis athttp://<pi>/tar1090/data/aircraft.json. readsb can also feed adsb.lol, adsb.fi and others.
-
-
Check it works in the receiver’s own map, then type the
aircraft.jsonaddress under Receiver & relay (or just the Pi’s host name to get the usual addresses as buttons) and press Test receiver.
Getting this https page to read it
Two rules apply to a receiver on your network:
-
Mixed content: an https page may not fetch a plain-http address, except
localhost/127.0.0.1.http://piaware.local/…fromhttps://geekychris.github.iois blocked by the browser before the Pi is even asked — the tool spots this and says so. -
CORS: the receiver must answer with
Access-Control-Allow-Origin. lighttpd (PiAware, tar1090) and nginx don’t by default.
Pick one:
-
The relay on the computer you browse from (above):
--receiver http://<pi>and source addresshttp://127.0.0.1:8099/receiver/data/aircraft.json(addtar1090/orskyaware/as in the Pi’s own path). Solves both rules; nothing to change on the Pi. -
HTTPS for the Pi:
sudo tailscale serve --bg 80on the Pi gives ithttps://<pi>.<tailnet>.ts.net/with a real certificate (any device on your tailnet can use it, including your phone away from home); or a reverse proxy with a trusted certificate (Caddy, nginx + Let’s Encrypt DNS challenge). Still add the CORS header below. -
The gitwebsite desktop app preview: the app serves this site on
http://127.0.0.1, so the page isn’t https and only the CORS header is needed.
CORS header for lighttpd (PiAware, dump1090-fa, tar1090) — create
/etc/lighttpd/conf-enabled/89-cors.conf, then sudo systemctl restart lighttpd:
server.modules += ( "mod_setenv" )
$HTTP["url"] =~ "^/(tar1090|skyaware|dump1090-fa|dump1090)?/?data/" {
setenv.set-response-header += ( "Access-Control-Allow-Origin" => "*" )
}
If lighttpd then refuses to start because mod_setenv is loaded twice (tar1090’s own config may load
it), delete the server.modules line. Check with curl -sI http://<pi>/tar1090/data/aircraft.json | grep -i access-control.
For nginx, inside the server { } that serves the map, then sudo nginx -t && sudo systemctl reload nginx:
location ~ ^/(tar1090/|skyaware/)?data/ {
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Private-Network "true" always;
# keep the root/alias from your existing location for the map
}
Access-Control-Allow-Origin: lets any web page you visit read your receiver’s aircraft list (which
is public information anyway — it is what you could feed to an aggregator). Use
https://geekychris.github.io instead of to allow only this site.
Raw and Beast feeds
dump1090 and readsb also serve raw messages: AVR text on TCP port 30002 and Beast binary on 30005.
Browsers can’t open TCP sockets, so a WebSocket bridge is needed: the gitwebsite app’s TCP relay (add
<pi>:30005 to its TCP allow-list), the relay’s --beast/--raw, or
pip install websockify and websockify 8765 <pi>:30005. The Mode S decoder
reads either, live, and decodes every message field by field.
Limits
-
Public feeds come from volunteers' receivers: coverage is patchy away from cities, MLAT positions wander, and some aircraft (blocked or private registrations, many military) are filtered or show only a hex address. Registration and type come from each aggregator’s database and can be wrong.
-
Polling is every 5–60 s (OpenSky at least 30 s); between polls aircraft don’t move on the map. Trails are only as old as this page’s session.
-
"Overhead" elevation uses the geometric altitude when the feed has it (barometric otherwise, which can be a few hundred feet off), a spherical-earth horizon with no refraction, and your location at ground level unless you use GPS.
-
Notifications only fire while this tab is open and polling; this is not an alerting service.
-
For curiosity and hobby use only — not for navigation, air traffic control, or safety decisions.
Related: Plane spotter, Mode S decoder, Aviation weather, Air routes, E6B calculators.
Linking to an example
Share link copies a link with your place, radius, source, view, zoom, units and filters. Your
location (from 📍 My location), the receiver and relay addresses, and the watchlist are never put into
a link; a link with where=gps asks the person who opens it for their own location. Parameters can also be
written by hand, for example /tools/flight-tracker/?place=EGLL&r=40#map.
| Parameter | Meaning | Example |
|---|---|---|
|
airport code (ICAO or IATA), |
|
|
the place’s coordinates and label, if you want to skip the lookup |
|
|
|
|
|
radius in nautical miles (5–250) |
|
|
|
|
|
|
|
|
|
|
|
altitude band in feet |
|
|
search text; type contains |
|
|
military only; emergencies only; hide aircraft on the ground ( |
|
|
seconds between polls |
|
|
a preset below (it picks the tab); other parameters override it |
|
Presets:
-
sfo-sample— the recorded sample around San Francisco (works offline, no relay needed) -
heathrow— 40 nm around London Heathrow from adsb.lol (needs the relay) -
jfk-table— a table of traffic within 30 nm of New York JFK -
schiphol-metric— Amsterdam Schiphol from adsb.fi in metric units -
my-receiver— your own receiver on the radar view -
low-traffic— the sample, only aircraft below 5 000 ft
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser — network requests go only to the services named on this page.