tutorial |

What a Port Event Actually Is (And Why Your Timestamps Are Lying to You)

Ask someone when a ship "arrives" at a port and you'll get an answer that sounds obvious. It arrives when it gets there. When it docks. When the cargo comes off. When the captain stops driving.

Container ship in Singapore harbor at dusk with other vessels in the background

All of these are different events. And if you're building anything that depends on knowing where ships are and what they're doing — a logistics dashboard, an emissions tracker, a demurrage calculator, a trading signal — the difference between them is the difference between software that works and software that quietly lies to you.

This is a piece about what a port event actually is, why the timestamp on it is more philosophically loaded than it has any right to be, and how to pull clean data out of an API without tripping over the assumptions baked into the question.

The fridge magnet version

Here's the mental model most people start with: ships sail around, and every so often one of them enters a port. The port notices. A row gets written somewhere. That row is a "port event."

That model is wrong. Not approximately wrong — wrong in a way that will burn you the first time you trust it.

In reality, no port "notices" anything. There is no welcome desk at the edge of Singapore harbor. What actually happens is this: commercial vessels of any size that matters — the rule is nominally 300 gross tons on international voyages, 500 GT on domestic ones, plus all passenger ships, but the operational answer is "anything commercially significant" — are required by SOLAS to broadcast their position, speed, heading, and identity. Fishing fleets and pleasure craft are mostly invisible. The protocol is called AIS (Automatic Identification System), broadcasting on two dedicated VHF channels (161.975 and 162.025 MHz) in the maritime band — pure digital TDMA, not voice, distinct from the channels humans actually talk on. Smaller vessels often carry the lighter Class B variant voluntarily.

Coastal stations receive these broadcasts within roughly 40–60 nautical miles of shore; satellites fill in the open ocean, with gaps depending on constellation coverage and how badly signals collide in busy lanes. The aggregate raw stream runs into the hundreds of millions to over a billion messages per day globally — scattered across the planet with no semantic meaning attached. Each message carries an MMSI, a nine-digit identifier that is the actual join key if you ever want to correlate a port event back to the raw position stream.

A "port event" is something a computer infers from that stream. It's a derived fact, not a recorded one.

Overhead view of vessel traffic clustered around Singapore port

Inferring a thing that didn't actually happen

To turn position fixes into port events, you need two things: a definition of what a port is in geographic terms, and a rule for when a ship has interacted with it.

The first one sounds easy and isn't. Ports aren't points; they're sprawling, irregular regions that include anchorages outside the breakwater, terminal berths inside it, sometimes a river pilot boarding area many kilometers offshore, and frequently a chunk of open sea where ships wait — sometimes for days, sometimes for weeks — for a berth to free up. Singapore's anchorage zones extend well into the strait. Houston's ship channel runs roughly fifty nautical miles from open water to the inner turning basin, serving a string of independently operated terminals that are colloquially "the port" but legally several different things.

So the first decision is: where does the port end? Serious port-event systems use polygons — hand-drawn or algorithmically refined boundaries, layered: an outer "port limits" polygon, inner anchorage polygons, and individual berth polygons. A vessel crossing one of these boundaries generates a candidate event. The providers who skip the layering and use a single outer polygon are selling you noise — every anchorage stay becomes "arrived," every drift across the line becomes a fresh port call.

The second decision is what counts as a crossing. A naive "is the ship inside the polygon?" check produces nonsense: GPS noise causes vessels at the edge to flicker in and out, generating dozens of fake arrival/departure pairs per hour. Real systems apply hysteresis (you have to be inside for N minutes before it counts) and speed thresholds — a moored ship reports near-zero speed-over-ground, though you have to filter the AIS sentinel codes near 102 knots. The standard reserves 1023 (102.3 knots) for "SOG unavailable" and 1022 (≥102.2 knots) as an overflow marker; both will otherwise inject impossible speeds into your data.

What comes out the other end is a clean event stream: arrival, berth, departure. Each one with a timestamp.

And the timestamps are where it gets interesting.

Why sub-minute matters

Query a well-built port events endpoint for Singapore — say /portevents/port/SGSIN, using the UN/LOCODE — and you should get back events resolved to the second. Not the hour. Not the nearest five minutes. The second.

The demurrage case is the one that matters most, and it gets the least attention. Emissions models get the press; trading signals get the venture money. But the demurrage clock — the meter that charges a charterer for keeping a ship waiting — starts ticking at a contractually defined moment, often tied to Notice of Readiness tendering at the port limits. NOR is a document the master serves, not an AIS event; but AIS-derived port event timestamps are increasingly used as corroborating evidence, and a charterer's lawyer disputing a $40,000-per-day demurrage claim on a Capesize bulker (an illustrative figure — real rates swing widely with the market) will absolutely cross-reference your data against the NOR timing. If your provider rounded to the nearest hour, you have just introduced uncertainty into someone's evidence. (We learned this the expensive way. Five-minute buckets were fine until they weren't.)

Emissions estimates drift quietly across a fleet when timestamps are coarse, and the trading case is the most fragile of all: watching how fast ships cycle through berths at Port Hedland is, in effect, watching iron ore loading throughput in something close to real time. If your berth timestamp is fuzzy by twenty minutes, your derivative is noise.

The reason the data can be sub-minute is that AIS Class A position reports arrive every 2 to 10 seconds for a vessel underway — strictly, every 10 seconds at port-approach speeds (0–14 knots), every 6 seconds in the 14–23 knot range, every 2 seconds above 23 knots, with course changes collapsing the interval to 2–3 seconds across the board. Class B transponders report every 30 seconds when moving, dropping to 3 minutes when slow; newer Class B+ devices match Class A rates. Stationary vessels at anchor with reported SOG ≤ 3 knots drop to once every 3 minutes — though GPS noise will sometimes keep an anchored ship in the faster-reporting mode anyway, which is one reason boundary flicker is so persistent.

In practice? A lot of providers downsample for storage and the precision dies upstream. If all your timestamps end in :00:00, that's your answer.

Ship bridge clock and electronic chart display showing a precise position fix

Querying it without tripping

The endpoint is GET /portevents/port/{unlocode}. UN/LOCODE is the five-character code maintained by UN/CEFACT — two letters of country code, three characters of location, occasionally including digits (GB2WB is a real one). SGSIN is Singapore. NLRTM is Rotterdam. USNYC is New York; though if you're querying the New York/New Jersey container complex specifically, your provider may use USNWK (Newark) for the New Jersey terminals — the boundary varies by data source, and "the port of New York" turns out not to be one thing. UN/CEFACT publishes updates twice a year, so if you're building something that runs unattended for years, track the changes.

The first thing that'll burn you is that the event types aren't interchangeable. An arrival means the vessel crossed into the port limits — it might still be miles from any berth, anchored, waiting. A berth event means it's actually alongside. A departure means it crossed out again. If you want "time spent loading," you want berth-to-departure, not arrival-to-departure. The difference can be days.

Coverage is uneven. Fishing fleets, very small craft, and naval vessels — which are SOLAS-exempt and may suppress AIS in operational contexts, though plenty of warships and auxiliaries transmit routinely in commercial ports — are inconsistent at best. Query a fishing port and the silence is the answer.

Big ports sometimes contain multiple terminals under one LOCODE, so you might see two berth events for the same call if a vessel shifts berth mid-stay — that's correct behavior, not a bug.

And events arrive out of order. Satellite AIS latency means transmissions from quieter ports can be buffered until the next overhead pass; for busy ports the more common cause of late arrivals is provider ingestion batching. Either way: your code should not assume chronological order, and providers that stamp ingestion time instead of transmission time will quietly destroy your analysis.

The thing under the thing

"A ship arrived at a port" is not an observed fact. It's a model. Somewhere between the radio signal and the JSON, a decision was made about where the port ends and what counts as being inside it. That decision is invisible in the response, and it shapes everything downstream.

The nice thing about port events, compared to most derived data, is that the inference layer is unusually well-defined. The polygons exist. The rules are reproducible. The timestamps, done right, are exact to the second.

You just have to remember that the ship didn't arrive. Something decided it had.

← Back to all posts