AIS Watchkeeper turns QGIS into a live maritime traffic console. It listens to an AIS receiver — either a USB/serial dongle or a network (TCP) feed — decodes the vessel broadcasts, and plots every ship on the map in real time, with heading, speed vector, track trail and a name learned from the traffic itself.
On top of the live picture it gives you four watchkeeping tools:
Everything runs inside QGIS as a dockable panel. There's no separate application and no cloud service — the feed comes straight off your receiver to your machine. (The one exception is the live bridge/lock lookup in Section 9, which is best-effort and optional.)
The panel at a glance. One dock, six tabs, in the order you'll normally use them:
A ? button in the top-right corner of the panel opens this manual at any time.
AIS Watchkeeper installs like any QGIS plugin from a ZIP, and it carries its own dependencies — you do not need to pip-install anything. The AIS decoder (pyais) and the serial driver (pyserial) are bundled inside the plugin.
Requirements
Steps
Once installed you'll see an AIS Watchkeeper button on the toolbar and an entry under Plugins → AIS Watchkeeper. Either one toggles the dock open and closed — a single click opens the panel, builds its map layers and leaves it ready for a source.
First-run notice. The first time you open AIS Watchkeeper in a QGIS session, a short usage notice appears. It states that the tool receives, portrays and stores AIS messages, and that you — the operator — are solely responsible for complying with the privacy legislation that applies where you use it. Click I do to accept and the panel opens; Decline (or closing the notice) keeps it closed, and no AIS data is received or handled until you accept. The notice appears once per session.
AIS Watchkeeper lives inside QGIS, so a few native QGIS habits make everything else easier. If you're already comfortable in QGIS, skim this and skip ahead.
The Layers panel is the list down the side of QGIS that shows every map layer — the basemap, your live vessels (liveFeedAIS), guard zones (guardZones), coverage, route markers, and so on. You'll need it to turn layers on and off and to edit guard zones and markers.
If it isn't visible: View → Panels → Layers (tick the box). The same menu lists every other panel, including AIS Watchkeeper itself, so you can re-open the plugin from here if you ever close it.
While you're there, also make sure the editing buttons are available: View → Toolbars → Digitizing Toolbar. That's where the pencil and the Add Feature buttons live.
In a watchkeeping setup you often want the map filling one monitor and the AIS Watchkeeper panel on another. The panel is a standard QGIS dock, so:
When floated, the panel is a normal window with its own maximise and minimise buttons, so you can size it freely or throw it full-screen on the second monitor. And whichever way you use it — docked or floated — if the panel is taller than the space it has (a small laptop screen, or a short dock), it grows a vertical scrollbar so nothing is clipped: just scroll to reach the controls lower down.
The same trick works on the Layers panel — handy if you want the map, the layer list, and the plugin spread across two screens.
Three features — guard zones, route reference markers and custom routes — are things you draw on the map using QGIS's own editing tools. They all follow the same five-step pattern, so learn it once:
guardZones for a zone, Route reference markers for a marker, Custom routes for a route).What happens after you finish drawing:
Markers and zones are saved to disk in your profile, so they survive QGIS restarts and plugin upgrades.
Once a guard zone or a marker is drawn, you can change or remove it — same tools for both layers. First select the layer in the Layers panel and Toggle Editing on, then:
Either way, finish with Save Layer Edits and toggle editing off. Nothing is permanent until you save.
Tip — placing a route marker accurately. A marker binds to whichever fairway is nearest to where you drop it, so put it where there's no doubt. Zoom in until the thin fairway lines appear on the chart (around 1:12500 or closer), then drop the marker in the middle of the fairway, right on a routeline. That way it snaps to the route you intended, at the correct distance along it, and lands exactly where you expect on the strip. Drop it loosely between two parallel fairways and it may bind to the wrong one.
This is the first real step: pointing AIS Watchkeeper at your receiver. Open the dock and go to the AIS stream tab — the leftmost one. At the top you choose between three kinds of source:
Pick the radio button that matches what you have. The panel below swaps to show the right fields.
If you're not sure which port or baud is right, don't guess — use Auto-detect (next).
A note on Bluetooth receivers. Most Bluetooth AIS receivers pair with your computer as a virtual serial port. Once they're paired at the operating-system level, they appear in the Port dropdown just like a plugged-in USB device, and you connect to them exactly as above — pick the port, set the baud, Connect.
The exception is receivers that talk over Bluetooth Low Energy (a GATT connection) instead of a serial profile. These never present as a serial port, so they won't appear in the dropdown and aren't supported by AIS Watchkeeper, which speaks only serial and TCP. If your Bluetooth receiver pairs fine but never shows up as a port, it's most likely one of these — contact the plugin developer for support.
The Auto-detect button does the port-and-baud hunt for you. It listens on each serial port in turn, trying the AIS standard 38400 first and then 4800, 9600 and 115200. A port producing valid AIS sentences is the winner; a port spitting garbage is rejected within a second or so, so the scan is quick.
This is the fastest way to get going with unfamiliar hardware.
The plugin connects straight to the TCP NMEA stream and starts decoding. It also tolerates feeds that wrap each sentence in a NMEA TAG block (the \…\ prefix many aggregators and multiplexers add) — those are stripped automatically before decoding, so a feed that used to show nothing now works.
Before it connects a TCP source, AIS Watchkeeper quietly probes the endpoint to see whether it's plain, encrypted, or expecting a login. A normal open feed just connects as above and you'll notice nothing. But if the endpoint looks secured — it offers TLS, or it greets you with a login prompt and sends no data until you authenticate — a login dialog opens, pre-filled from what the probe found:
{user}, {pass} and {token} placeholders — because there's no single standard AIS login, the exact line your server expects is configurable here.Fill in your credentials and connect. You can store them safely: the dialog uses QGIS's own encrypted credential store, so the secret is held in QGIS's master-password-protected database, decrypted only at the moment of connecting, and never written into the plugin's own files. The plugin remembers the non-secret bits per host (the TLS flags, the login template, which stored credential to use) so the next connect pre-fills — but the password itself stays in QGIS's vault.
Once a source is live:
The AIS stream tab, connected to the aisstream.io internet feed: the source panel, the Settings box (speed vector, symbol amplifier, trails, plot-vessels, own position and the toggles), the Voyage-history box, the live "msg/s" rate graph, and the decoded sentence log with running counts.
If you don't have a receiver yet and just want to see AIS Watchkeeper working, choose Internet. A dropdown offers a few free or open online AIS services:
For the two global services the Area radius (nm) box sets how large a box around your position is requested. If you choose a location-based service without a position set, the plugin reminds you to set one first. Your key is stored safely in QGIS's settings, per service, so you paste it only once.
A word of perspective: these internet feeds are for testing, and for coverage where you have no receiver of your own. In your local waters a real antenna hears far more, far sooner. Among free worldwide feeds, aisstream.io and VesselAPI are the genuine options — most other "global" services are paid, or require you to run and share your own receiver.
Attribution. The Norway / Kystverket feed is open data under NLOD 2.0. If you use, store or share it you must credit the source: "Contains data under the Norwegian Licence for Open Government Data (NLOD) distributed by the Norwegian Coastal Administration (Kystverket)" (https://data.norge.no/nlod/en/2.0). The open feed already excludes small fishing (<15 m) and recreational (<45 m) craft, so those vessels are never received or stored. aisstream.io and VesselAPI are used under their own free-tier terms with your personal API key.
The Kystverket licence was reviewed for possible infringement and found to be in compliance: because the restricted small-craft data is excluded from the open feed it is never stored or redistributed, and NLOD 2.0 permits the plugin's storage, sharing and commercial use provided the attribution above is given. This finding is also shown in the app when you select the Kystverket source.
Once a source is live, decoded vessels are written to a map layer called liveFeedAIS and updated continuously. Everything in this section is about that live picture — what the symbols mean and how to tune them. All the tuning controls live in the Settings box on the AIS stream tab, and your choices are saved with the QGIS project, so they come back next time you open it.
Each vessel is drawn as a ship-shaped symbol coloured by type, scaled to the vessel's real length and beam (from its AIS dimensions) and rotated to point the way it's heading — true heading if the vessel reports it, otherwise course over ground. So a 300 m tanker looks like a 300 m tanker, pointing the right way; a small craft looks small. Where a vessel hasn't reported its dimensions yet, a sensible default size is used until it does.
The type comes from the vessel's AIS ship-and-cargo type code. The legend:
| Symbol | Type | AIS code |
|---|---|---|
| Cargo | 70–79 | |
| Tanker | 80–89 | |
| Passenger | 60–69 | |
| High-speed craft | 40–49 | |
| WIG (wing-in-ground) | 20–29 | |
| Fishing | 30 | |
| Towing | 31, 32 | |
| Dredger | 33 | |
| Diving ops | 34 | |
| Military | 35, 59 | |
| Sailing | 36 | |
| Pleasure craft | 37 | |
| Pilot | 50 | |
| SAR | 51 | |
| Tug | 52, 53 | |
| Anti-pollution | 54 | |
| Law enforcement | 55 | |
| Medical transport | 58 | |
| Other | 90–99 | |
| Other identified | remaining codes | |
| ▲ (triangle) | Unidentified — no type reported yet | none |
A vessel shows as a small triangle until it broadcasts a type; once it does, it switches to the matching ship symbol. The triangle still rotates to the vessel's heading, so even unidentified contacts show which way they're pointing.
A speed vector is a line projected ahead of each moving vessel showing where it will be in the next few minutes — the standard way to read who's going where at a glance. Two dropdowns in Settings control it:
Stopped vessels (zero speed) draw no vector.
trails draws a faint dotted line through each vessel's recent positions, so you can see where it has been. The dropdown sets how many past fixes to join: off, 5, 10 or 20. Longer trails give more history but more clutter — 5–10 is a good watchkeeping default.
At a wide zoom, true-to-scale ship symbols can become specks. The symbol amplifier multiplies symbol size — ×1, ×2, ×5, ×10 — without changing anything else, so you can keep small craft visible when zoomed out. It's purely a visual aid; the underlying positions are unchanged. (Drop it back to ×1 when you zoom in close.)
As vessels broadcast their static data (name, callsign, IMO, dimensions), AIS Watchkeeper quietly learns and remembers them per MMSI in a small on-disk register. That's why a vessel that arrived as a bare number gradually gains a name — and why it's already named the next time it appears, even before it re-broadcasts. You read this register in the Vessels tab (Section 8).
Each vessel also carries a label: its name (up to ten characters) on the first line and, on a second line, its heading and speed — for example 351° - 20 kn. The label sits a fixed distance off the vessel on its starboard quarter, joined to the symbol by a short leader line so it's clear which ship it belongs to even in a crowd. Vessels reporting a static status — moored or at anchor — show the name only, since heading and speed carry no meaning there. The Ship labels toggle in the Settings box turns the labels on and off.
A vessel's label, set off on the starboard quarter and joined to the symbol by a short leader line — here the heading-and-speed line reads 69° - 7 kn (the name sits on the line above once it has been learned). The green line is the vessel's COG speed vector.
The Settings box has a plot vessels dropdown that decides which vessels are drawn on the map:
liveFeedAIS layer.Near the connect controls, above the Settings box, is a Show AIS only checkbox — it filters the live sentence log on the tab down to AIS messages, hiding any other NMEA traffic (e.g. GPS sentences) sharing the feed. This affects the on-screen log only, not the map.
Two more switches sit in the Settings box: Bind vessels to fairways connects each vessel to the Dutch fairway network and is the foundation of the Routes features (Section 9), and Audible chime on alarm governs the Guardian's alarms (Section 7).
The Settings box also holds two display selectors — chart light (day / dusk / night, Section 5.8) and units (nautical / metric / imperial, Section 5.9), covered next.
A vessel that stops transmitting doesn't linger forever. If no position is heard from a target for 20 minutes, AIS Watchkeeper removes it from the map, from its trail and from any route binding, keeping the picture current. Whether the removal is noted depends on coverage: if the feed was still live at the time — you were hearing other vessels — the target counts as a genuine lost target and a line is written to the event log; if the whole feed had gone quiet (an outage), the removal is silent, since the vessel simply went out of coverage. A target that starts transmitting again reappears normally.
The chart light dropdown in the Settings box switches the whole display between three brightness modes, the way an ECDIS does:
Choosing a mode changes several things together so the picture stays coherent: the map background, the basemap (dimmed and desaturated for dusk/night — an OpenStreetMap basemap is pre-drawn and can't be recoloured, so it is darkened rather than restyled), the vessel labels (light text on a dark halo at night), the route-leg strip, and the QGIS interface theme itself (dusk uses QGIS's "Blend of Gray", night uses "Night Mapping"). Your choice is remembered between sessions.
Two things worth knowing. Switching the mode changes the whole QGIS window's colours, not just the AIS panel — that's deliberate, so nothing glows white beside a dark chart. And on the next start the map picture is restored to your chosen mode, but the QGIS interface theme is left as you have it until you pick a mode again, so the plugin never overrides your own QGIS theme setting behind your back.
The units dropdown sets the unit system for every readout in the plugin — ship labels, the Vessels tables, the route strip, positions, everything:
51° 20.52' N 003° 49.81' E).Bearings stay in degrees in every system. The one value that does not change is the Routes tab's Bind width, which is always in metres — it's a tuning tolerance you type, not a readout. Switching units re-labels everything live, and your choice is remembered between sessions.
Telling AIS Watchkeeper where your antenna is does two things:
You can run without it — vessels still plot, the Guardian still alarms, and traffic still binds to routes — but coverage and the nearby bearing/distance need it.
On the AIS stream tab, click Set own position… and choose how to give it. AIS Watchkeeper prefers a real GPS fix, but you can always place the point by hand:
lat, lon in decimal degrees (EPSG:4326), e.g. 51.333, 3.833. (Used automatically when there's no map canvas to click.)Automatic from a combined receiver. If your AIS feed itself carries GPS sentences — many combined AIS/GPS receivers interleave their own position on the same serial or TCP stream — AIS Watchkeeper picks up the first valid fix and sets your position from it automatically, once per connection, with no clicking at all. A position you set by hand always takes precedence over this.
Your position then shows on the map as a single home marker (a house symbol, or a bold star as a fallback). To move it, just set it again.
Your receiver position is saved, so it's restored the next time you open the project and coverage resumes accumulating under it automatically — you don't re-enter it each session.
As traffic comes in, AIS Watchkeeper records where it actually hears vessels, building a live picture of your real-world reception — and, just as usefully, your blind spots. It does this on a grid: each small cell counts how many receptions it has collected, split by transponder class.
The coverage layer is added to your project but switched off by default, so it doesn't clutter the live picture. To see it, open the Layers panel (Section 3.1) and tick the coverage layer. Turn it off again the same way.
Coverage is kept separately per source, so different sources never blur together. For a local receiver it is stamped with the antenna position you set, so moving to a new position starts a fresh survey while the old one is kept — you can compare reception from different sites. An internet source is tracked under its own identity instead: a fixed-footprint feed such as Kystverket keeps its own coverage map, and a position-based feed such as aisstream.io is tracked around the position you set. Switching source therefore switches to that source's own coverage picture, rather than overwriting your antenna's.
The Event log tab shows a coverage-status caption, and — when event logging is on — logs each time a vessel first comes into or drops out of coverage. So beyond the map picture, you get a running record of coverage changes over time. The logging side of this is covered next.
The AIS Guardian watches guard zones you draw on the map and raises an alarm when a vessel crosses them — the core watchkeeping function. It also keeps a log of vessel events. Everything here lives on the AIS Guardian tab.
Guard zones (red) drawn around the lock chambers at Terneuzen, watching live traffic; a vessel entering an armed zone raises an alarm and an Event-log entry.
Top to bottom: a green Feed live light, an Edit selected zone… button, the Alarms box (two alarms plus an event-logging switch), and the guard-groups editor.
The AIS Guardian tab — the Feed-live light, the three alarm switches (Alarm 1/2 plus the log-only event switch), and the guard-groups editor with New / Delete / Add MMSI / Remove.
A guard zone is a polygon you draw with QGIS's native editing tools, exactly as described in Section 3.3: select the guardZones layer, Toggle Editing,
Add Polygon Feature, click out the shape, right-click to finish, then
Save Layer Edits.
The moment you finish the polygon, the Guardian's zone form opens:
Two save-time failsafes stop you from creating a zone that can never fire: you can't save a group-targeted zone with no group selected, and you can't save a zone with neither entry nor exit ticked.
To change a zone later, select it on the map ( Select Features) and click Edit selected zone… on this tab.
The Alarms box holds the master switches. A zone only acts when the relevant master switch here is on:
While a vessel is triggering an alarm, its name also turns red in the Vessels → Nearby list (Section 8), so you can spot the offending contact in the list at a glance, not just on the map.
Think of alarming as two-level gating: a zone fires only when the master switch is on and the zone is armed and the vessel is a target. That lets you arm a whole set of zones but silence them all with one master switch, or leave the master on and disarm a single zone.
A few deliberate behaviours make the alarms trustworthy:
A guard group is a named set of MMSIs — a watchlist. The editor at the bottom of the tab lets you create and name groups, and add or remove MMSIs in each. Once a group exists, you can target a zone at it (Section 7.2) so the zone alarms only on those vessels.
The fastest way to populate a group is from the Vessels tab: right-click a vessel and choose Copy to group (Section 8). Use groups for a watchlist of vessels of interest; use All vessels on a zone when you want any intrusion to alarm.
On a real alarm (Alarm 1 or 2), three things happen together:
The log-only events from the third switch (coverage in/out, nav-status) are silent — no chime, no message bar — and appear only in the Event log.
The Vessels tab is a live table of traffic, with three views you switch between using the Nearby / Register / My fleet radio buttons at the top.
Nearby lists every vessel currently being received, measured against your receiver position (Section 6) and sorted nearest first. Columns:
Because it's sorted by distance and refreshes live, the top of the list is always your closest traffic. Click any row to pan and zoom the map to that vessel.
Nearby: traffic sorted nearest-first, each row showing bearing and distance from your position, plus the fairway, flow and route-km from binding (idle vessels show no flow).
If no receiver position is set, Nearby stays empty — Bearing and Distance have nothing to measure from. Set your position (Section 6.2) to populate it.
Register switches the table to the learned vessel database — every vessel AIS Watchkeeper has ever seen and remembered, not just those in range right now. It's backed by vessel_names.xml in your profile, so it persists across sessions and grows over time. Columns:
A search box (active in this view) filters the table as you type, matching across the fields — handy for finding a particular ship in a long history.
Register: the learned ship database — MMSI, name, callsign, vessel ID, length, beam and type — for every vessel ever seen, filtered live by the search box.
My fleet is your own watchlist — the ships you want to keep an eye on regardless of the rest of the traffic. Switch to it with the My fleet radio button; the view lists the vessels you've added, with the same columns as the Register, and its search box filters as you type.
Adding and removing. In any Vessels view (Nearby, Register or My fleet), right-click a vessel and choose Add to my fleet; to drop one, right-click it and choose Remove from my fleet. Your fleet is saved in your profile (my_fleet.json, Section 11.1), so it persists across sessions.
Plotting just your fleet. Set the plot vessels dropdown (Section 5.6) to my fleet and the map draws only these vessels — a clean picture of just your ships, while the feed keeps decoding everything else.
Right-click any vessel row and choose Copy to group → [group] to add that vessel's MMSI to one of your guard groups (Section 7.5). It's the quickest way to build a watchlist: spot a vessel of interest in the list, right-click, done — no typing MMSIs by hand.
The fifth tab, Event log, is the running record. Every alarm (zone entry/exit) and every logged event (coverage in/out, nav-status changes, stream-health summaries) lands here with a timestamp, newest first. Refresh reloads it, and Export writes the whole log to a CSV file for reporting or archiving. A coverage-status caption sits beside the export control.
The Event log: timestamped rows — here a run of LOST TARGET events (a target unheard for 20 minutes while the feed stayed live) with time, MMSI and last position. The coverage caption (bottom) tracks Class A/B cell counts; Refresh reloads and Export CSV saves the log.
This is what sets AIS Watchkeeper apart from a plain plotter: it ties each vessel to the Dutch fairway network, so you can think in terms of fairways and traffic flow rather than just dots on water. Everything in this section depends on Bind vessels to fairways being on (the switch in the AIS stream tab's Settings box, on by default).
As vessels move, AIS Watchkeeper matches each one to the fairway it's actually travelling on, and works out how far along that fairway it is (a kilometre measure) and which way it's heading. Those three facts — fairway name, route-km, flow direction — are what fill the Vessels tab (Section 8) and drive the route strip (Section 9.4).
The matching is deliberately careful, so vessels don't flicker between nearby fairways:
Two related datasets sit behind this, and they show up differently on the map:
The Routes tab is a live table of every fairway that currently has traffic on it, sorted by fairway name so the list stays stable and doesn't jump around as vessel counts change. Columns:
Custom routes you've drawn appear here in blue, tagged (custom), mixed in with the bundled fairways and behaving the same way — counts, bind width, and a leg you can open (Section 9.8).
The Routes tab — every fairway carrying traffic, sorted by name, with Inbound / Outbound / Idle counts and an editable Bind width (m). The default 150 m suits canals; widen a broad tidal fairway so ships sailing off the centreline still bind.
Click any row (except the Bind-width cell) to open that fairway's leg in the route-strip monitor (Section 9.4). The table refreshes every couple of seconds and keeps your selected route highlighted across refreshes.
Tuning bind width. A single fixed tolerance doesn't suit every fairway. The value is the perpendicular distance measured outward from the fairway centreline — not the total corridor width — so the fairway effectively spans that distance on each side of its centreline. A tidal fairway like the Westerschelde mouth is nearly a kilometre wide and ships legally sail well off the centreline, so a tight tolerance would drop them as "off-fairway." Double-click the Bind width (m) cell and widen it — for a fairway where ships run up to ~650 m off the centreline, set roughly 650, which reaches ~650 m to either side. Narrow canals and closely-spaced parallel routes keep the tight default so they don't mis-bind. Widening never steals a vessel that's genuinely closer to another route — the nearest-plus-alignment rule still decides — it just lets an off-centre vessel bind to the fairway it's really on (reading as a slightly lower-confidence bind). Values are saved per route and reload next time.
Seeing the corridor on the chart. To see how wide a route's bind width is, turn on the Route bind-width layer in the Layers panel (Section 3.1) — it's added switched off. When you zoom in, each fairway shows two thin dashed lines, one on each side of its centreline, marking the binding corridor; a vessel between them is within tolerance of that route. Widen a route's Bind width and its corridor visibly fattens, so you can set the tolerance by eye. Like the fairway detail, the corridor only draws when you're zoomed in, to keep the chart clean.
Click a fairway in the Routes tab and its leg opens in a separate window — the strip monitor. It lays the whole fairway out as a straight axis marked in kilometres, and places every vessel on it at its route-km, so you read a winding 100 km fairway as one clean line.
The Hartelkanaal leg as a strip (km 0–20.5). Outbound ▲ to one side, inbound ▼ to the other; bridges branch off by route-km (Hartelbrug, Harmsenbrug, Suurhoffbrug). Where symbols crowd they fan out perpendicular from the axis — slowest nearest the line, fastest furthest out.
How to read it:
Controls on the strip's toolbar:
The strip is wired to the main map: click a ship on the strip and the QGIS map recentres, zooms and flashes that vessel — so you can go from "who's that on the strip" to "show me on the chart" in one click.
When you open a leg, AIS Watchkeeper fetches that fairway's bridges and locks from the Rijkswaterstaat FIS-VNDS service and draws them on the strip as labelled markers rising from the axis: purple for a bridge, orange for a lock, named, positioned by their own route-km.
This is the one place the plugin reaches the internet. The fetch is per-route, cached, time-limited and entirely best-effort: if you're offline or the service hiccups, the strip simply opens without the bridge/lock markers and the live AIS feed is never affected. So bridges and locks need a connection; binding, the strip and everything else work fully offline.
Bridges and locks come from the service, but you can add your own points to the strip — buoys, VTS sector boundaries, berths, anything you want as a landmark along the fairway. You place these with QGIS's native editing as described in Section 3.4 (the Route reference markers layer), and they appear on the strip as teal diamonds, snapped to the nearest fairway and positioned by route-km exactly like the bridges and locks. They also feed the ETA tool below.
The Route CPA button predicts encounters along the fairway — which is what matters on a fairway, where two ships' paths are constrained to the same line.
A head-on route-CPA on the strip — the blue bar marks the predicted meeting point and time (here CPA 16:15), with the two closing vessels either side of it.
The same prediction on the main chart: the meeting bar (routeCPA 16:15) drawn at its real position across the Hartelkanaal, each vessel labelled with its distance-to-go (DTG).
Recalculate re-runs the prediction with the latest positions; Clear removes it. Each picked vessel is also marked with a blue dot on the main chart, so you can pick the two ships out of the traffic and tie the on-strip prediction to the real vessels on the map.
A vessel coupled to the active route-CPA, marked with a blue dot at its position so you can find it among the traffic on the chart. Its green line is the COG speed vector.
The bundled fairway network is the Dutch one. Outside the Netherlands there's no bundled fairway to bind to — so AIS Watchkeeper lets you draw your own. A custom route is just a line you draw down the middle of a waterway and give a name; from then on it behaves like any other fairway — traffic binds to it, it appears in the Routes tab, and it gets its own leg strip with route-km, inbound/outbound, CPA and ETA.
Drawing one. Custom routes live on the Custom routes layer, and you draw them with QGIS's native editing exactly as in Section 3.3: select the layer, Toggle Editing,
Add Line Feature, left-click each vertex down the waterway, right-click to finish, type a name, then
Save Layer Edits and toggle editing off. Draw it down the centre of the channel, the way you'd draw a fairway centreline; vessels bind to it within the same perpendicular tolerance as any route (and you can widen that per route from the Routes tab, Section 9.3).
The direction you draw it sets inbound vs outbound. A custom route has no sea to orient itself by, so it takes its direction from how you draw it: travel in the same direction you drew the line (first vertex → last vertex) counts as inbound, the reverse as outbound. If the counts come out backwards for your waterway, just redraw the line the other way (or reverse its geometry with the Vertex tool).
Custom routes win ties. Where a custom route overlaps or runs close to a bundled fairway, a vessel within tolerance of both binds to your custom route, not the native one — so your own routes take precedence wherever you've drawn them. Everywhere you haven't drawn a custom route, native binding is completely unchanged.
They persist. Custom routes are saved in your profile (custom_routes.gpkg, Section 11.1) and reload every session, and edits take effect live — add, reshape or rename a route, save, and the binding picks it up within a couple of seconds. In the Routes tab they're shown in blue and tagged (custom) so you can always tell your routes from the bundled ones.
AIS Watchkeeper can keep a history of where vessels have been, segmented into voyages, so you can look back at a track later. It is off by default and entirely optional; you turn it on in the Voyage history box on the AIS stream tab.
Tick Record voyage history to start. Two choices shape what is kept:
A voyage begins when a vessel is under way and ends when it moors or anchors, or when it drops out of coverage for more than an hour. Only real ships are recorded — shore stations, aids-to-navigation and obvious decode glitches (impossible position jumps) are filtered out — so the history stays clean. The status line reports fixes received, rows written and any that were filtered.
The Voyage-history box on the AIS stream tab with the Detail dropdown open — the three cumulative levels: 1 Textual, 2 Voyages, 3 Full. The ? button (top-right, circled) opens this manual.
The History tab: the stored-voyages table (vessel, MMSI, start / end UTC, duration, end reason, destination) with the search box, the time window and its last-hour / day / week presets, the map-view area filter, and the Show track / Show all tracks / Clear tracks / Export CSV / Delete history controls. The header shows how much is stored and how many rows are shown.
The History tab is the main way to browse what you have recorded: a sortable table of every voyage (vessel, MMSI, start / end in UTC, duration, end reason, destination), newest first. Three filters narrow it down: a name or MMSI search, an optional time window, and an optional "only voyages crossing the current map view" area filter. Then:
The header shows how much is stored (voyages, vessels, fixes) and the time span.
Two quicker shortcuts also pull a single track straight onto the map without opening the tab:
Retrieved tracks land in an AIS history layer group. If there is no history stored yet, the tab and the shortcuts tell you so rather than drawing an empty map.
Delete history… (in the Voyage history box) permanently clears all recorded history from the active backend — it empties the PostgreSQL tables, or deletes the GeoPackage file — after a confirmation. If recording was on, it resumes into a fresh, empty store.
Everything you create lives in one folder inside your QGIS profile, not in the plugin folder — so it survives plugin upgrades:
<your QGIS profile>/ais_nmea_source/
What's in it:
ais_guardian_zones.gpkg).ais_guardian_store.gpkg).ais_guardian_coverage.gpkg, kept separate to avoid write contention).vessel_names.xml).my_fleet.json, Section 8.3).route_tol.json).markers.gpkg).custom_routes.gpkg, Section 9.8).history/ subfolder (history/ais_history.gpkg); recording to PostgreSQL/PostGIS keeps it in that database instead.To back up your whole setup, or move it to another machine, copy that one folder. (The fairway network itself — data/routes.gpkg and data/fairways.gpkg — ships inside the plugin and isn't something you edit.)
A Bluetooth/USB receiver doesn't appear in the Port dropdown. Most Bluetooth AIS units pair as a serial port and show up normally — click Refresh after pairing. If it still doesn't appear, it's most likely a Bluetooth Low Energy (GATT) device, which isn't supported (Section 4.1); contact the plugin developer.
Connected, but no vessels appear. Check the status counts on the AIS stream tab. If sentences are flowing but the AIS count stays zero, the baud rate is probably wrong (try Auto-detect, or 38400 vs 4800) or the feed isn't AIS (e.g. GPS-only). If AIS is being counted but nothing plots, make sure Plot vessels on map is ticked.
A TCP feed won't connect or asks to log in. The endpoint is secured — fill in the login dialog that appears (TLS, method, credentials) as described in Section 4.4.
Vessels show but don't bind to a fairway. Confirm Bind vessels to fairways is on. A vessel under ~2 knots is treated as idle and detached on purpose. If a moving vessel still won't bind, it may be sailing too far off the centreline — widen that route's Bind width in the Routes tab (Section 9.3).
The Vessels → Nearby list is empty. No receiver position is set; bearing and distance have nothing to measure from. Set it (Section 6.2).
The coverage map isn't visible. It's added switched off — tick the coverage layer in the Layers panel (Sections 3.1 and 6.4).
A route's strip has no bridges or locks. Those come live from the RWS service, so you're offline or it hiccupped. Everything else (binding, the strip, your markers) still works offline (Section 9.5).
QGIS crashes when you unplug a serial receiver (Windows). Hit Full stop before unplugging — it stops the reader cleanly first (Section 4.6).
A guard zone never alarms. Check the chain: the master switch (Alarm 1/2) must be on, the zone must be Armed, it must have entry and/or exit ticked, and if it's targeted at a guard group, that group must contain the vessel (Section 7).
The panel or map feels heavy on a modest laptop. AIS Watchkeeper sizes itself to your machine. At startup it briefly measures how fast this computer draws the map and picks a matching display profile, and it keeps an eye on the draw time while running. On a slower machine it eases off automatically — drawing vessels as light dots when you're zoomed out, thinning labels and trails, and repainting a little less often — and if a heavy feed is clearly overloading the display it steps down one further level on its own. None of this is a setting you manage; it just keeps the live picture responsive. You can lighten the load further by hand: reduce the Area radius on an internet source, or set plot vessels (Section 5.6) to my fleet or off so the map draws fewer ships while the feed keeps decoding everything.
AIS Watchkeeper (ais_nmea_source) is free software under the GNU General Public License v3.0 or later — the full text is in the bundled LICENSE file. Copyright © 2026 W.D. de Pooter; published under the byline Captain Ahab & Cosmo.
It bundles three pure-Python libraries (in libs/, so no pip or internet is needed to install them), each under its own permissive, GPL-compatible licence:
| Library | Version | Licence | Purpose |
|---|---|---|---|
| pyserial | 3.5 | BSD-3-Clause | Serial port discovery and reading |
| pyais | 3.1.0 | MIT | AIS sentence decoding |
| attrs | 26.1.0 | MIT | pyais's runtime dependency |
One further library, networkx (BSD-3-Clause), is used for the routable fairway graph but is not bundled — it's provided by QGIS's own Python. Route matching degrades gracefully if it's absent.
Data. The bundled fairway network (data/routes.gpkg, data/fairways.gpkg) is derived from Rijkswaterstaat FIS-VNDS open vaarweg/route data, and the live bridges and locks are fetched from the same service.
AIS Watchkeeper reads both !AIVDM (other vessels) and !AIVDO (own vessel) sentences, reassembling multi-sentence messages automatically. The message types it uses: