Skip to content
← Home

Telemetry · Geospatial · 2026

ADS-B Aircraft Tracker: RF to Spatial Archive

I built a 1090 MHz receiver, decoder, PostGIS archive, and browser interface around an RTL-SDR and Raspberry Pi. It records aircraft broadcasts without a paid feed or third-party server.

Tom Shanks

Loading contacts
One receiver, Denver
Drag to rotate
Scroll to re-plot by altitude

60,000 archived positions. Scroll for altitude; drag to rotate. Denver International shapes the eastern lobes, while terrain limits reception to the west. Component, data packer and the 472 KB contact field are public: spatial-fields/adsb-field

Messages ingested
1,128,113
Aircraft indexed
520K
Peak measured range
131.92 km

System architecture

An RTL-SDR and Raspberry Pi 3B receive and decode 1090 MHz ADS-B around the clock. A Dockerized Python service writes each message to PostGIS and recovers cleanly after a restart or network outage.

PostGIS turns latitude and longitude into queryable geometry: aircraft near a point, coverage by bearing, and repeated routes over time. A public 520,000-aircraft index resolves broadcast hex codes into registration, operator, and aircraft type.

Scheduled materialized views precompute traffic density, receiver coverage, and route-pattern queries. The dashboard reads those views instead of scanning millions of raw messages.

FastAPI serves statistics, positions, routes, and range data to a React and Leaflet dashboard. Docker Compose runs the stack in WSL2.


Stack

Hardware

RTL-SDR USB receiver (1090 MHz) · Raspberry Pi (decoder host)

Decoding & ingest

dump1090 (Mode S / ADS-B decoder) · Python ingest service

Data

PostgreSQL + PostGIS · 520K-row aircraft metadata index · materialized views

API

FastAPI (Python) · statistics, positions, routes, receiver range, corridor density, hourly traffic, and aircraft detail

Frontend

React + Vite · Leaflet.js

Deployment

Docker Compose · WSL2 Ubuntu · systemd user services · local network access only


Status and access

The receiver and ingest stack run continuously. The dashboard stays on my local network, and the contact archive remains in the local database.

Source available on request.