← back to dashboardMethodology →

User guide

Port Flow gives a real-time view of maritime flows across 51 strategic ports (ARA, bunkering, LNG export). This page explains how to read the dashboard, who benefits, and how to integrate the data into your pipelines.

Who it's for

Read the dashboard in 30 seconds

  1. Port selector top-right — switch the observed port. The native name shows in parentheses when the active language differs (e.g. Antwerp (Antwerpen), Hamburg, الفجيرة).
  2. Language selector next to it — 8 business languages: FR, EN, NL, DE, ES, AR (with auto RTL), ZH, JA.
  3. All / Tankers toggle — instantly filters the map and counters to the 5 tanker sub-classes (crude, product, chemical, LNG, LPG).
  4. KPI row — total vessels, stationary (congestion proxy), underway, moored, inbound/h, active voyages tracked.
  5. Map — color = AIS category, size = state. Dashed rectangles are named zones (anchorage, berth, channel).
  6. Active voyages — table sorted by predicted ETA. The "broadcast ETA" column is what the crew entered; compare against the model's deltas.
  7. ETA precision — our model's RMSE vs the broadcast ETA's RMSE. This is the main quality indicator.
  8. Anomalies — vessels at anchor abnormally long for their class. Critical to monitor for congestion or operational oddities.
  9. 6-hour flow — inbound / outbound / stationary over the last 6 hours. Short-term trend.

ETA precision page

Accessible via the ETA precision button or /precision. Public view aimed at demonstrating model quality to prospects. Three key indicators: model RMSE, broadcast RMSE, % gap. List of the 50 most recent closed voyages with error in hours (green < 1h, amber < 3h, red beyond). Methodology at the bottom. 7/30/90-day window filter.

API integration

Public API at /api/v1, authenticated via bearer token. OpenAPI spec at /api/v1/openapi.json.

# Generate an API key from /account (Starter plan and above),
# then use it as a Bearer token:

# List ports
curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://portflow.uk/api/v1/ports

# Rotterdam snapshot
curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://portflow.uk/api/v1/ports/rotterdam/snapshot

# Active tanker voyages
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://portflow.uk/api/v1/ports/rotterdam/voyages/active?tankersOnly=1"

Available endpoints: /ports, /ports/{id}/snapshot, /ports/{id}/vessels, /ports/{id}/voyages/active, /ports/{id}/voyages/closed, /ports/{id}/anomalies, /webhooks.

Webhooks (alerts)

Subscribe to an event to receive an HMAC-SHA256-signed POST when a threshold is crossed.

# Subscribe to congestion > 30 stationary vessels at Rotterdam
curl -X POST -H "Authorization: Bearer your-secret-token" \
  -H "content-type: application/json" \
  -d '{
    "url": "https://your-app.example/hooks/port-flow",
    "port": "rotterdam",
    "event": "congestion.threshold",
    "threshold": 30
  }' \
  https://portflow.uk/api/v1/webhooks

# Response — keep the secret to verify the signature
{ "id": "sub_…", "secret": "…", "url": "…", … }

Headers on every delivery: X-Port-Flow-Event and X-Port-Flow-Signature: t=<ts>,v1=<hex> (HMAC-SHA256 of the timestamp-prefixed payload). Receiver-side verification: hmac_sha256(secret, "{ts}.{body}").

Supported events: congestion.threshold / congestion.cleared, anomaly.detected, voyage.arrived.

Known limitations

Deployment checklist

  1. Create an aisstream.io.
  2. cp .env.example .env.local, fill in AISSTREAM_API_KEY and PORT_API_TOKENS.
  3. npm install && npm run dev.
  4. Check the AIS Live banner top-right (green = stream incoming).
  5. Wait 60s + a few minutes for voyages to start opening (depending on traffic).
  6. The /precision page will show numbers after the first closed voyages (predicted ETA + actual arrival).