A standalone, cross-platform ADS-B receiver in a single Go binary.
Plug in an RTL-SDR dongle, run one command, and watch aircraft on a live map — or stream the data to Virtual Radar Server, an aggregator, or your own code.
No dump1090. No readsb. No librtlsdr. No Python. One binary, no setup.
squitter -location 51.4775,-0.4614 -map carto -enrichsquitter -demo -location 51.4775,-0.4614Then open http://localhost:8080.
That synthesises real 1090 MHz signals, pushes them through the actual demodulator, and decodes them back — the same code path a real dongle uses. It is the fastest way to tell whether a silent screen is your antenna or your build.
Existing ADS-B software is excellent but fragmented and mostly Windows- or Linux-first: a C decoder here, a Python multilateration client there, a web UI somewhere else, and a stack of setup steps before anything appears on screen. squitter is one program that does the whole chain — radio to screen to feed — and runs the same way everywhere.
RTL-SDR ──▶ demodulator ──▶ Mode S decode ──▶ tracker ──┬──▶ web UI
1090 MHz 2.4 MSPS CRC + CPR aircraft │ terminal view
state ├──▶ Beast :30005
├──▶ AVR :30002
└──▶ SBS-1 :30003
Everything from raw samples onward is implemented here: the pulse-position demodulator, the 24-bit CRC with single-bit error correction, Compact Position Reporting, altitude decoding including the legacy Gillham code, and the output encoders.
By default it is a radar scope: range rings drawn about your antenna, no network, nothing to configure.
| Input | Action |
|---|---|
| scroll | zoom |
| drag | pan |
| click | select an aircraft, and put it in the URL so it can be linked to |
m |
toggle the map background |
c |
return to the antenna and refit the range |
Esc |
clear the selection |
Setting -location is worth doing. Without it, a position needs a matched pair
of even/odd frames; with it, single frames can be resolved against your known
location, which roughly doubles the usable position rate and lets obviously
wrong decodes be rejected.
Pass -map to put real geography under the traffic.
squitter -location 51.4775,-0.4614 -map carto-map |
Key needed | Notes |
|---|---|---|
carto |
— | Dark basemap; the one that suits the display |
carto-light |
— | The same, light |
osm |
— | Standard OpenStreetMap raster |
mapbox |
-map-key |
-map-style takes a style ID, default dark-v11 |
google |
-map-key |
-map-style takes roadmap, satellite or terrain |
| a URL template | — | Anything containing {z}, {x} and {y} |
squitter -map mapbox -map-key pk.eyJ1... -map-style satellite-v9
squitter -map google -map-key AIza... -map-style terrain
squitter -map 'https://tiles.example.com/{z}/{x}/{y}.png'Tiles are fetched by squitter, not by your browser. That keeps the key on the machine you control rather than shipping it to every client, lets one cache serve every browser and every pan back over ground already covered, and is the only way Google's tiles work at all, since they need a session token minted with the key.
The radio carries an ICAO address and, sometimes, a callsign. It never says what the aircraft is, who operates it, or where the flight is going.
squitter -location 51.4775,-0.4614 -enrichThat fills in registration, ICAO type, manufacturer, operator, country and a photograph, plus the airline, the origin and destination airports, and the IATA flight number a passenger would recognise — BA547 rather than the BAW547 the transponder actually transmits.
The data comes from adsbdb, which is free, needs no account, and is open source if you would rather run your own:
squitter -enrich -enrich-url http://localhost:8008It is off by default, and deliberately so. A receiver that quietly reports every aircraft it hears to a third party is not what you get from a program that otherwise only listens. Turning it on tells adsbdb which aircraft you can see.
Lookups never touch the receive path: nothing blocks on the network, results
and misses are both cached, failures back off, and a database that is slow or
unreachable costs you the labels rather than the decoder. Registration and type
travel in the feed under readsb's own field names (r, t, desc, ownOp),
so tar1090 pointed at squitter picks them up without changes.
In demo mode the invented callsigns resolve to real routes, but the invented ICAO addresses are random, so registrations mostly come back unknown — and the occasional coincidental hit will pair an airline callsign with an entirely unrelated airframe.
| Format | Default port | Who reads it |
|---|---|---|
| Beast binary | 30005 | ADS-B Exchange, adsb.lol, airplanes.live, FR24 — the only format aggregators accept |
| AVR hex | 30002 | Anything line-oriented; easiest to pipe into your own code |
| SBS-1 BaseStation CSV | 30003 | Virtual Radar Server, PlanePlotter, adsbSCOPE |
| JSON | 8080 | /data/aircraft.json in the tar1090/SkyAware schema |
All four run at once. Each is a plain TCP or HTTP server — connect as many clients as you like.
Feeding an aggregator is then just:
nc localhost 30005 | nc feed.adsbexchange.com 30004Or point an existing viewer at the JSON:
curl -s localhost:8080/data/aircraft.json | jq '.aircraft[] | {flight, alt_baro, r_dst}'| Path | What it serves |
|---|---|
/ |
The web view |
/data/aircraft.json |
Current traffic, readsb schema |
/data/receiver.json |
Receiver position and version |
/data/map.json |
Whether a map is configured, and its attribution |
/tiles/{z}/{x}/{y} |
Map tiles, proxied and cached |
Receiver
| Flag | Default | Description |
|---|---|---|
-location lat,lon |
— | Antenna position; enables distance, range checks and single-frame decoding |
-device n |
0 |
SDR device index |
-gain dB |
-1 |
Tuner gain; -1 selects automatic |
-sample-rate hz |
2400000 |
Sample rate |
-frequency hz |
1090000000 |
Centre frequency |
-list |
— | List attached dongles and exit |
Display
| Flag | Default | Description |
|---|---|---|
-web addr |
:8080 |
Web interface; "" disables |
-map provider |
— | Map background; see the table above |
-map-key key |
— | API key, for mapbox and google |
-map-style s |
— | Mapbox style ID, or Google map type |
-enrich |
off | Look up registration, type, operator and route |
-enrich-url url |
adsbdb.com | An adsbdb-compatible service of your own |
-quiet |
— | No terminal display |
Outputs
| Flag | Default | Description |
|---|---|---|
-beast addr |
:30005 |
Beast binary; "" disables |
-avr addr |
:30002 |
AVR hex; "" disables |
-avr-timestamps |
off | Use the @ timestamped AVR variant |
-sbs addr |
:30003 |
SBS-1 CSV; "" disables |
Demo and diagnostics
| Flag | Default | Description |
|---|---|---|
-demo |
— | Simulate traffic instead of using a radio |
-demo-aircraft n |
14 |
How many aircraft to simulate |
-demo-noise f |
0.02 |
Noise floor, 0 to 1 |
-log level |
warn |
debug, info, warn, error |
go install github.com/sirsjg/squitter/cmd/squitter@latestOr from a clone:
git clone https://github.com/sirsjg/squitter.git
cd squitter
go build ./cmd/squitterGo 1.24 or newer. No C toolchain needed on Linux or Windows. On macOS the USB backend links against IOKit, which ships with the OS — still nothing to install.
Everything except macOS is pure Go, so release binaries cross-compile from any machine:
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o squitter-pi ./cmd/squitter
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o squitter.exe ./cmd/squitterWorking and tested: demodulator, Mode S and ADS-B decoding, aircraft tracking, all four output formats, both user interfaces, the map and enrichment layers, and the simulator.
squitter -list shows attached dongles.
The decoders are validated against captured reference transmissions and by round-tripping through the encoder — position decoding is exact to within CPR's own 5 metre quantisation everywhere on the globe.
The demodulator decodes every frame down to about 20 dB SNR, degrades from there, and runs around 11× faster than real time on one modern desktop core (comfortable on a Raspberry Pi, with room to spare on anything larger). Improving weak-signal performance is the most worthwhile next piece of work: dump1090 squeezes more out of marginal aircraft than this does.
The USB driver is the newest and least proven part: it has never run against a real dongle. It is a from-scratch port of librtlsdr's register sequences, with a fake USB transport in the tests that asserts the whole open sequence produces the expected register trace. That catches transcription errors, not reality-contact errors.
If a dongle behaves oddly, start there. A good bring-up sequence that isolates USB from everything else:
squitter -list # does enumeration work at all?then confirm streaming works before trusting any tuner register, since the chip's test mode emits an incrementing byte counter instead of samples.
Known suspects, in order: the macOS asynchronous transfer plumbing; the Linux usbfs ioctl numbers, which were derived from first principles rather than checked against a running kernel; the whole Windows backend; and the sign convention on the intermediate frequency, which would give a mirrored spectrum that still looks like a live noise floor.
Google's tile session handling is the other path never exercised against a real account. The keyless providers and Mapbox have been.
- A 1090 MHz filtered dongle with an LNA roughly doubles useful range over a bare RTL-SDR. The antenna matters more than any of this software.
- The RTL-SDR Blog V4 uses a different crystal frequency from earlier models. squitter detects it; a decoder that does not will tune 1.8× off frequency and hear nothing while appearing to work.
- On Windows you still need Zadig to bind the WinUSB driver. That is a driver binding requirement, not a library dependency.
- MLAT. Beast timestamps are emitted at the correct reference point (end of bit 56) so the data is usable, but there is no multilateration client.
- ASTERIX CAT021, the Eurocontrol surveillance format used by ATC systems.
- UAT (978 MHz), used by smaller aircraft in the US.
- Mode S formats that carry no address of their own (DF0/4/5/16/20/21) are decoded only for aircraft already identified from a self-validating frame, since a corrupted frame otherwise conjures a plausible but fictitious aircraft.
Aircraft and route data from adsbdb. Map tiles from OpenStreetMap, CARTO, Mapbox or Google, depending on what you configure — each is displayed with its own attribution.
MIT.

