Skip to content

JSON Configuration

AIS-catcher (v0.41+) supports extensive configuration through JSON files. This guide describes the JSON structure, key settings, and common patterns.

To start AIS-catcher with a JSON configuration file, use the -C option followed by the path to your config.json file:

AIS-catcher -C config.json
This loads and applies the settings from the JSON file.

Basic Structure

A JSON configuration file always starts with the configuration header:

{
    "config": "aiscatcher",
    "version": 1
}

Where:

  • config: Identifies the configuration type. Must be "aiscatcher".
  • version: Configuration version. Currently, only 1 is supported.

This is the absolute minimal structure (just the first two keys). If no receiver is configured, AIS-catcher will use the default behaviour for selecting an input device.

To select the RTL-SDR as an input device:

{
    "config": "aiscatcher",
    "version": 1,
    "receiver": [
        {
            "input": "rtlsdr"
        }
    ]
}

Note: older configurations allowed receiver selection at the root level (e.g. input, serial). This is legacy and may disappear in a future release. Prefer defining receivers in the receiver array. 1

Important Notes

  • JSON keys are case-sensitive and must be lowercase.
  • CLI setting names are not case-sensitive.
  • Define receivers in the receiver array (even for a single receiver).
  • Device sections (e.g. rtlsdr, airspy, hydrasdr) configure the device, but do not select it. Use input (and optionally serial) inside each receiver object.
  • active is optional in any section; if omitted, it is assumed to be true.
  • Outputs like udp are arrays to support multiple output channels.

Configuration Keys

Configuration keys are grouped below by purpose. The complete list of keys the managed hub edits, with types, defaults and ranges, is on Configuration Keys.

General Overview

General (mostly optional) settings define fundamental aspects of AIS-catcher's operation.

Root-level keys

Key Type Description Documentation
General
config string "aiscatcher"
version number 1
sharing boolean Enable community feed sharing Community Feed
sharing_key string Community feed key Community Feed
screen number Screen output mode (0-5), one for all receivers Console Output
verbose_time number Verbose update interval in seconds, one for all receivers Console Output
Receiver array
receiver array List of receiver objects (recommended even for a single receiver) 1 Receiver configuration
stations array Where the antennas stand: a number, name, position and altitude for each, and a vessel or GPS when they move Stations
tracking object How the tracker keeps ships: backup file and interval, history, table size Tracking and services. A server whose filter names stations (stations, or id on the command line) shows those stations alone: their markers, pages and figures
services array Servers reading the tracker: port, address, what each serves and its filter Tracking and services
webhooks array Addresses each event is posted to Webhooks
mqtt_state object The station's state on an MQTT broker, for Home Assistant Home Assistant
Output channels
server array Web viewer configuration Web Viewer
udp array UDP output configuration UDP Output
tcp array TCP output configuration (client) TCP Output
tcp_listener array TCP output configuration (server) TCP Output
http array HTTP output configuration HTTP Output
mqtt array MQTT output configuration MQTT Output

Receiver configuration (receiver array)

The root-level receiver key contains an array of receiver objects. This is the recommended structure going forward.

Receiver object keys

Each entry in the root-level receiver array is a receiver object. These keys live inside each receiver object:

Key Type Description Documentation
input string Selects the input device type for this receiver (e.g. rtlsdr, airspy, hydrasdr, spyserver, ...) Input Overview
description string A name for the receiver, shown in the viewer's receiver list and statistics
station number The number of the station in stations whose antenna this receiver uses Stations
lat, lon number The receiver's position, when it names no station Stations
serial string/number Receiver identifier (recommended; also used to target per-receiver CLI overrides in some setups)
verbose boolean Enable verbose output for this receiver Console Output
meta string Metadata tags (T/D/M) for this receiver Console Output
own_mmsi number Own MMSI of receiver station
<device section> object Device-specific configuration object matching input (e.g. rtlsdr, airspy, hydrasdr, ...). See examples in Input Device Settings. Input Overview
model object Decoder model configuration for this receiver Model
Multi-receiver example

Example with two receivers:

{
    "config": "aiscatcher",
    "version": 1,
    "receiver": [
        {
            "input": "airspy",
            "serial": "airspy",
            "airspy": {
                "sample_rate": "3000K"
            }
        },
        {
            "input": "rtlsdr",
            "serial": "ais",
            "rtlsdr": {
                "bandwidth": "192k"
            }
        }
    ]
}

In this example, each receiver selects a device via input, is optionally named via serial, and is configured via its device section (e.g. rtlsdr, airspy, hydrasdr).

Stations (stations array)

Step-by-step guide

Locate your station on aiscatcher.org walks through this with screenshots: in the control panel, in the configuration file and on the command line.

A station is where an antenna stands. Every ship's distance and bearing, and the range figures, are measured from the station that heard the ship, so receivers at different places each measure from their own. The viewer's own lat and lon are only used for a receiver that has no position.

Each entry of stations has a number and may have a name, a position and an altitude:

Key Type Description
id number Unique; what a receiver names in its station key. 0 is the default station: where every receiver stands that names none
name string Shown in the viewer; Station <id> when left out
lat, lon number Decimal degrees; both or neither
alt number Height of the antenna in metres
mmsi number The vessel the station is on: it is wherever that vessel last reported, and gps does not apply
gps boolean Whether GPS sentences move the station; off unless set to true. Its lat and lon are then where it stands until the first fix
share_loc boolean Whether the station's position may leave this machine. Off unless set: no server, API or map then shows where it is, nor which vessel it rides, nor how far or in which direction a vessel it heard lies from it. The station's own range figures (furthest vessel, maximum distance, radar) still go to its owner: a browser on the station itself, a signed-in control panel, or an API key with system scope. Which vessels a station hears still hints at its general area

A message that names a station itself, as a feed from a hub does in its tag block, counts at that station when stations lists it, else at the input's.

Stations are optional. A receiver that names none stands at the default station, 0: list it to give it a name and a position like any other, or leave it out and it is made when the run starts, named after the one receiver standing on it when that has a description, else after the viewer's station, and placed where a receiver with lat and lon of its own is, else where the viewer section puts it (lat, lon, alt, share_loc, use_gps, own_mmsi). A receiver may also say "station": 0. Once the file has a stations list, every message carries the number of its station as station_id, 0 included. An engine of a receiver may carry a station of its own ("settings": { "station": 2 }, -go station 2 on the command line), so two decoders of one input are told apart: each then has its own figures, and Plots → Compare sets one against the other.

{
    "config": "aiscatcher",
    "version": 1,
    "stations": [
        { "id": 1, "name": "Harbour mast", "lat": 52.10, "lon": 4.27, "alt": 20 }
    ],
    "receiver": [
        { "input": "rtlsdr", "serial": "ab", "station": 1 },
        { "input": "rtlsdr", "serial": "cd", "station": 1, "channel": "CD" },
        { "input": "udpserver", "udpserver": { "port": 10110 }, "description": "Pier" }
    ]
}

Here the two dongles share the antenna on the harbour mast, and the UDP input stands at the default station, named after it. The log lists what each receiver became:

Receiver 1: station 1 "Harbour mast" at 52.099998, 4.270000
Receiver 2: station 1 "Harbour mast" at 52.099998, 4.270000
Receiver 3: station 0 "Pier", no position

In managed mode the Stations page edits this list. Its first entry is the default station, always there under number 0, which cannot be deleted; every other station is numbered from 1. An input picks its station from the list on its own page, or creates one there. A file from before the default station was listed keeps working: the panel shows it from the viewer section's station, lat, lon, share_loc, use_gps and own_mmsi, and moves them into stations the first time Stations is saved.

A station that moves. A receiver on a boat, or one with a GPS attached, does not stay where the file puts it. A station's position comes from one source at a time: the vessel its mmsi names, else GPS when gps is true, else its lat and lon.

  • A station with an mmsi rides that vessel: each position the vessel reports, heard by any receiver, moves the station there.
  • A station with "gps": true moves with the GPS sentences ($GPRMC, $GPGGA and the like) arriving on the inputs of the receivers that name it. When no receiver names it, GPS on any input moves it.
  • The default station, when the file does not list it, moves with GPS on the inputs standing on it unless the viewer's use_gps is off; listed, it follows its own gps like any other.
  • The position in the file is where a moving station starts, until the first fix. Ships are measured from where the station was when it heard them. The last fix is kept in the tracking backup, so a restart does not send a station back to its configured position.

These apply to the stations of the tracker and the services below, which report each station's position with its source (configured, gps or vessel) and the time of the last fix. The viewer under server keeps its own single position, set by lat, lon, use_gps and own_mmsi as before.

Tracking and services (tracking, services)

AIS-catcher keeps one picture of everything its receivers hear, the tracker, and offers it through services: a list of servers, each a port and what it serves: the web viewer, the API, MCP, the system service, GeoJSON, Prometheus. The tracker is built when the file has a server; without one nothing is kept. The viewer of -N and of a server section is such a server too. Both are part of the standard builds; a build made with cmake -DAPI=OFF leaves them out and refuses these keys.

{
    "config": "aiscatcher",
    "version": 1,
    "stations": [ { "id": 1, "name": "Harbour mast", "lat": 52.10, "lon": 4.27 } ],
    "receiver": [ { "input": "rtlsdr", "station": 1 } ],
    "tracking": { "file": "/var/lib/ais-catcher/tracking.bin", "backup": 10 },
    "services": [
        { "port": 8110, "api": true },
        { "port": 8111, "bind": "0.0.0.0", "ui": false, "api": true,
          "view": { "hidden_buckets": ["bm", "bs"], "seen": 30, "track_time": 3600 } },
        { "port": 8112, "tracking": { "allow_type": "1,2,3", "history": 3600 } }
    ]
}

tracking, all optional:

Key Type Default Description
file string none Backup of ships, statistics, events and station fixes, read at start and written on exit. A backup an earlier version wrote (the file of server, or of -N) is copied once to <file>.before-upgrade, imported, and from then on written over in this version's format. To go back to the earlier version, rename the copy back to the file's name
backup number 10 Minutes between backups to file; 0 writes only on exit
history number 1800 Seconds a ship is kept after its last message
track_time number 3600 Seconds of track kept per ship; 0 is no limit
max_ships number 4096 Size of the ship table
cutoff number 2500 Distance in nautical miles beyond which a ship does not count towards range
track_memory number 1024 Kilobytes of track kept per ship
expire boolean false Forget a ship's details when it leaves
lat, lon number none Where a message from no known station is measured from
places string none A directory of place files: the tracker then keeps every ship's visits, as the viewer does with its own places

Each entry of services, one server:

Key Type Description
port number Required; one server per port. Not on the entry marked main
main boolean Managed mode (-E): the server beside the control panel, on its port, the map always on; one entry, which also takes the viewer's options
active boolean false switches the server off: it keeps its settings, which are still checked, but opens no port and keeps no ships. The main server always serves. On unless set
bind string Address to listen on; 127.0.0.1 unless set, so a server is reachable from other machines only when you say so. Beyond this machine, a server with api, mcp or system needs keys or public
ui boolean The web viewer, on unless set false; with it the viewer's own options (realtime, station, station_link, mbtiles, …), see Web Viewer
api boolean The read API under /api/v1: stations, statistics, vessels with their tracks and visits, places with the ships inside and their visits, aircraft, and events. See API. A server limited to some stations serves no aircraft, as aircraft are not kept by station
mcp boolean The same for an assistant, at /mcp
system boolean Receivers, outputs, health and the log, under /api/v1/system
geojson boolean The ships as GeoJSON at /geojson
metrics boolean Message counts for Prometheus at /metrics; prome says the same
limited boolean The short form for whoever asks: lists of 25 rows at most, vessel rows without the station, one vessel in full without its stations, and 25 data calls an hour from one address. Off unless set
tracking object Ships of the server's own, behind a filter on the messages: the terms of an output's filter (allow_type, block_mmsi, stations, unique, …) and zone or groups_in for the receivers that feed it, with history and track_time for what it keeps. The backup and the places are the site's. Without it the server reads the site's tracker. A server whose filter names stations (stations, or id on the command line) shows those stations alone: their markers, pages and figures
keys array The keys the server accepts, each { "name", "sha256", "scopes" }: see Keys
public boolean Its data is for anyone, without a key; never its system
view object Which ships this server shows of what its tracker keeps, and how far back: stations, mmsi_allow, mmsi_deny, hidden_buckets, hidden_classes, hidden_statuses, speed_min, speed_max, distance_min, distance_max, seen (minutes since heard), validated, repeated, track_time (seconds of track served, at most what the tracker keeps), and place_geometry (false serves places with their marker position only, keeping their outlines on this machine; on unless set). What it leaves out no route of the server sends: the map, the API, MCP and GeoJSON. A view never makes a tracker; only a message filter does (filter on with its terms, or zone, groups_in). Leave it out to show all

In managed mode (-E) the Services tab edits these: the built-in viewer beside the control panel first, then each server of services, with Add server for another. Each server's page switches its services on and off, says whether it listens on this machine or the network, gives its keys (New key makes one, shows it once, and keeps only its SHA-256), and, with the viewer on, the viewer's own settings. A saved server whose port another program has is marked as not listening. Try the API sends a request to any of them as a program would, made on the station itself, with the key given, and shows the answer and the curl line that repeats it; under MCP it lists a server's tools, calls one with its arguments as an assistant would, and gives the line that connects Claude Code to it. How long ships and tracks are kept, and the backup, are under System › Settings › History & backup. The built-in viewer is the entry marked main: it always serves the map, may switch on api, mcp, system, geojson and metrics, and takes keys and public as any server does, following the address the control panel listens on. A saved change to the servers applies at once, also while the receivers are stopped; a server cannot take the control panel's port or the viewer's.

A viewer under server, and -N on the command line, is read as an entry of services: the same server, with the same keys. One without a message filter shows the site's ships, and its file, backup and history are the site's tracking; one with filter on, or with zone or groups_in, keeps ships of its own behind that filter, as the viewer always did, while the backup stays the site's. On the command line the switches follow the port: AIS-catcher -N 8100 api on mcp on.

The filter uses the terms of the viewer's own filter (Settings → Filter), under the same names, so a filter you set up in the viewer can be copied here as it stands. It selects from everything the tracker keeps: the server shows nothing outside it, in any list, count or event.

Term Type Description
stations array Only ships one of these stations heard in the last hour; 0 is a ship no listed station heard
hidden_buckets array Groups left out: am, as (class A moving, stationary), bm, bs (class B), aton, base, sarte, air
hidden_classes array Ship classes left out, by number: 2 cargo, 3 class B, 4 passenger, 5 special, 6 tanker, 7 high-speed, 8 fishing, 0 everything else
hidden_statuses array Navigational statuses left out, 0 to 15; 15 is also a status not reported
speed_min, speed_max number Knots; a ship without a speed falls outside either
seen number Heard within this many minutes; 0 is any age
distance_min, distance_max number Nautical miles from the station that heard the ship
validated string any, yes, no or pending
repeated string any, only (passed on by a repeater) or never
mmsi_allow, mmsi_deny array Only these MMSIs; never these

A request to /api/v1/vessels takes filters of its own, named after the fields of a vessel (?class=cargo,tanker&min_speed_kn=1). They narrow what the server shows and never widen it.

Input Device Settings

AIS-catcher supports various input devices. Each device type has specific configuration options. Below are the supported devices and their respective settings. The documentation of the relevant keys can be found in the Configuration sections. Below we provide a few examples.

RTL-SDR (rtlsdr)

Example
{
    "rtlsdr": {
        "active": true,
        "rtlagc": true,
        "tuner": "auto",
        "bandwidth": "192K",
        "sample_rate": "1536K",
        "biastee": false
    }
}

Full RTL-SDR Documentation

Airspy (airspy)

Example
{
    "airspy": {
        "sample_rate": "3000K",
        "linearity": 17,
        "biastee": false
    }
}

Full Airspy Documentation

HydraSDR (hydrasdr)

Example
{
    "hydrasdr": {
        "sample_rate": "3000K",
        "linearity": 17,
        "biastee": false
    }
}

Full HydraSDR Documentation

Airspy HF+ (airspyhf)

Example
{
    "airspyhf": {
        "sample_rate": "192k",
        "threshold": "low",
        "preamp": false
    }
}
[Full Airspy HF+ Documentation](../configuration/input/airspyhf.md)

HackRF (hackrf)

Example
{
    "hackrf": {
        "sample_rate": "6144k",
        "lna": 8,
        "vga": 20,
        "preamp": false
    }
}

Full HackRF Documentation

SDRPlay (sdrplay)

Example
{
    "sdrplay": {
        "sample_rate": "2304K",
        "agc": true,
        "lnastate": 5,
        "grdb": 40
    }
}

Full SDRPlay Documentation

SoapySDR (soapysdr)

Example
{
    "soapysdr": {
        "active": true,
        "device": "driver=rtlsdr",
        "sample_rate": "1536K"
    }
}

Full SoapySDR Documentation

Serial Port Input (serialport)

Example
{
    "serialport": {
        "baudrate": 38400,
        "port": "/dev/tty0"
    }
}

Full Serial Port Documentation

NMEA2000 (nmea2000)

Example
{
    "nmea2000": {
        "active": true,
        "port": "can0"
    }
}

Full NMEA2000 Documentation

File Input Settings

WAV File (wavfile)

Example
{
    "wavfile": {
        "active": true,
        "filename": "recording.wav"
    }
}

Full WAV File Documentation

Raw File (file)

Example
{
    "file": {
        "active": true,
        "filename": "data.raw"
    }
}

Full File Documentation

Network Input Settings

TCP Client (rtltcp)

Example
{
    "rtltcp": {
        "host": "192.168.1.100",
        "port": 12345
    }
}

Full TCP Documentation

SpyServer (spyserver)

Example
{
    "spyserver": {
        "host": "server.example.com",
        "port": 5555
    }
}

Full SpyServer Documentation

UDP Server (udpserver)

Example
{
    "udpserver": {
        "active": true,
        "port": 10110
    }
}

Full UDP Documentation

ZMQ (zmq)

Example
{
    "zmq": {
        "active": true,
        "endpoint": "tcp://localhost:5555"
    }
}

Full ZMQ Documentation

Output Settings

AIS-catcher supports various output channels. Each output channel has specific configuration options. The documentation of the relevant keys can be found in the Configuration sections with some JSON examples below.

Web Viewer (server)

An entry of server is a server of services, written the way the viewer always was.

Example
{
    "server": [
        {
            "active": true,
            "port": 8100,
            "station": "My Station",
            "share_loc": true,
            "lat": 52,
            "lon": 4.3
        }
    ]
}

Full Web Server Documentation

Database Output (db)

Example
{
    "db": [
        {
            "active": true,
            "type": "postgres",
            "conn_str": "dbname=ais",
            "station_id": 17,
            "position": true,
            "static": true
        },
        {
            "active": true,
            "type": "csv",
            "conn_str": "/var/log/ais"
        }
    ]
}

Full Database Documentation

UDP Output (udp)

Example
{
    "udp": [
        {
            "active": true,
            "host": "192.168.1.235",
            "port": 4002,
            "filter": false,
            "allow_type": "1,2,3,5,18,19,24"
        }
    ]
}

Full UDP Documentation

TCP Output (Client) (tcp)

Example
{
    "tcp": [
        {
            "active": true,
            "host": "5.9.207.224",
            "port": 12,
            "keep_alive": false
        }
    ]
}

Full TCP Documentation

TCP Output (Server) (tcp_listener)

Example
{
    "tcp_listener": [
        {
            "active": true,
            "port": 5012
        }
    ]
}

Full TCP Documentation

HTTP Output (http)

Example
{
    "http": [
        {
            "active": true,
            "url": "http://example.com/ais",
            "interval": 10,
            "response": "json"
        }
    ]
}

Full HTTP Documentation

MQTT Output (mqtt)

Example
{
    "mqtt": [
        {
            "active": true,
            "host": "mqtt.example.com",
            "port": 1883,
            "topic": "ais/messages",
            "username": "user",
            "password": "pass"
        }
    ]
}

Full MQTT Documentation


  1. Legacy configurations may use root-level input / serial to define a single receiver. This still works in some versions, but is discouraged and may be removed in a future release. Prefer putting input (and serial) inside each receiver object under receiver. ↩↩