Guides › Distance

Distance - Port-to-Port Voyage, Distance & Round-Trip Economics Analyzer

The Distance page (route /routes) answers one question in depth: for a single origin→destination port pair, how far is it, how long does the voyage actually take, and what does the round trip cost? It fuses a computed reference sea distance (routed through real ocean lanes and canals, not a straight line over land) with the real observed transit times of tracked vessels that have sailed that exact pair - broken down by ship size, ISO week, month of year, and individual voyage - and adds a separate round-trip economics block that turns the head-haul + back-haul into days, fuel, CO₂ and a break-even freight rate.

What this page is for and how the data is built

Despite the menu label Distance, this is really a port-pair voyage analyzer. It fuses two independent data sources:

A subtlety to understand before trusting the numbers: legs are collapsed into "macro" cargo voyages by _macro_legs_for_ship(). A port stop counts as a real cargo event only when the ship's load state changes across it (Ballast→Laden or vice-versa, inferred from draught). If a ship stops mid-trip for bunkers, a canal-transit wait, or a refresher call without changing load state, that stop is merged into the longer journey and its sea-days are summed in. So Tubarão→Qingdao stays one voyage even when the ship paused in Singapore for bunkers. There is also a raw-leg fallback: if the macro pass finds nothing for the exact pair you picked (because that port was a mid-chain call that got merged away), the page re-runs against the raw physical legs so every route offered in the dropdown still returns its voyages.

Two more behaviours worth knowing. Anchorages are folded into their berth port: a voyage that ended "at the Antwerp anchorage" still counts toward the Port-A→Antwerp pair and uses the full berth-to-berth distance. And pure bunker/transit hubs are excluded from the route chips and observed-pair counts entirely (you can still type-and-pick them above for a point-to-point distance) (_NONLOAD_PORTS - Singapore, Zhoushan, Fujairah, Gibraltar, Suez/Panama anchorages, etc.), because they are waypoints, not cargo endpoints.

The grey explainer note (read this first)

Just above the headline summary sits a muted explainer line. It is worth reading once because it sets expectations for the whole page:

"Transit = days underway between the two ports (derived voyage legs). Distance is computed through real ocean lanes (Suez / Panama / etc.) when available, otherwise great-circle. Data grows with coverage & time; free DMA backfill is Baltic/North-Sea only, so Mediterranean routes fill in slowly from live tracking."

The port pickers (From / To) and the Swap button

The filter bar at the top opens with the two core controls:

How to use it: type the load port in From and the discharge port in To (or click a route chip below to pre-fill a busy observed lane), read the distance and transit, then use Swap to compare the laden head-haul against the ballast return.

Quick-pick route chips, the empty-state, and URL deep-linking

Under the filter bar sits the chips strip (#chips): up to 24 pre-built buttons of the form Origin → Destination (N), where N is the voyage count for that pair. These are the busiest observed lanes fleet-wide (served by /api/route_ports, which returns the top 80 pairs; the page shows the first 24). Clicking a chip sets both pickers and runs the analysis in one move - the fastest way to land on a high-sample route. Chips have a pill style and highlight on hover.

Note on dates: the page deliberately clears the From/To date fields on load. They share the element IDs #since/#until with the Port page, so a browser could auto-fill a stale value; the Distance page defaults to all dates on purpose, because a stray "today" value would silently filter every voyage out and make a populated route look empty.

Filters: Load state, DWT range, date window, and Segment

The remaining filter-bar controls narrow which voyages feed every table, chart and KPI below. Click Apply to commit them (changing the origin re-runs automatically; everything else needs Apply).

Why it matters: the headline transit number is only as honest as the cohort behind it. A charterer should pin Load=Laden and a DWT band around the candidate vessel before quoting laycan or steaming days.

The headline summary line and the route map

After a run, the summary line (#rt) condenses the route into one sentence, for example: Rotterdam (NLRTM) → Singapore (SGSIN) · Netherlands → Singapore · 8,431 nm sea route · ~26 days at ref speed · 1 bunker/transit stop merged into cargo legs. Read it left to right:

Below the chips, the route map (#routemap, Leaflet/OpenStreetMap, ~300px tall) is hidden until a route with coordinates loads. It draws:

What to look for: a dashed line plus a great-circle tag is your cue to treat the distance/days as a rough floor - the real sea route is at least that long and probably longer.

The route line prefers reality. When a vessel has actually sailed this O→D pair, the map draws that ship’s real track (gold) instead of an idealised line - so it follows the navigable channel and never crosses land, even on short or harbour-to-harbour hops where a generic sea-route graph would otherwise draw a straight line through a peninsula. Hover the gold line for the example ship and date; if no vessel has sailed it yet, the page falls back to the sea-route (or, as a last resort, a dashed great-circle). The header then also shows “~N nm actual” - the distance that example ship really steamed - next to the idealised figure.

The six KPI cards

The card row (#cards) summarises the matched-voyage cohort. Each card shows a big value, a label, and a unit; a missing value renders as an en-dash. All six are computed over the filtered legs:

Tonnage band, weekly and monthly seasonality breakdowns

Three sections slice the same cohort by different dimensions. Every table shares the columns Voyages, Avg (d), Median (d), Min (d), Max (d), Avg speed/kn. Numeric cells are right-aligned; a missing value shows an en-dash.

Cross-read tip: the weekly chart answers "what has this lane been doing lately?"; the monthly chart answers "what does this lane always do at this time of year?" Diverging answers (e.g. recent weeks fast but the month historically slow) are exactly the kind of signal worth pricing in.

Round-trip economics calculator

This section (#rt_cards, #rt_tb) is a distinct tool from the one-way analysis above. It pairs consecutive cargo macro-legs where leg-1 is O→D and the very next leg for the same ship is D→O - one observed round trip - and is served by /api/round_trip. It runs automatically alongside the main analysis, but the two cost inputs are optional and need the Compute button:

The summary cards show: Round-trips (count), Median total days, Median sea days, Median fuel (t), Median CO₂ (t), and RT distance (nm, the full there-and-back). When you supply hire and bunker, two more appear: Med. voyage cost (in $) and Break-even ($/t). Fuel uses each ship's uploaded consumption figures (cons_at_sea/cons_at_port) when available, otherwise segment defaults; break-even is the freight rate at which the round trip washes its face, computed at 90% utilisation.

The per-trip table (up to 50 rows) lists each observed round trip: Ship (linked to its /ship/IMO page), IMO, Depart and Return timestamps, Total (d), Sea (d), Port (d) (waiting + berth time - the part the one-way transit figure excludes), Fuel (t), CO₂ (t), Voyage cost, and Break-even $/t. When no paired O↔D round trips exist yet it shows "No paired O↔D round-trips observed yet."

Why it matters: a one-way transit tells you steaming time; the round-trip block tells an owner or operator the true economic length of the employment (laden out + ballast back + port time) and the freight floor below which the voyage loses money. The Port (d) column is the eye-opener - it quantifies how much non-steaming time the lane really swallows.

The Voyages table (the raw evidence)

The final section Voyages (N) (#tb_legs, count in #c_legs) is the audit trail behind every aggregate above - the individual legs, sorted by departure date, capped at 1,000 rows. Columns:

How to use it: when an average looks off, scan this table to see whether it is driven by one anomalous voyage, by a mix of laden and ballast legs, or by a wide DWT spread. Click through to a suspicious ship to inspect its track. If the route/filters yield nothing it shows "No voyages for this route/filters yet." - a prompt to relax the Load, DWT or date filters rather than a sign the lane is wrong.

Seasonal advice and the cargo-lane bridge

When a researched pair has real voyage history, two chips appear under the header. 📅 Historically fastest/slowest months reads the by-month transit medians (only months with enough observed voyages count) and names the fastest and slowest months with their medians and sample sizes - a first seasonal routing aid that sharpens every month as the lane’s history deepens. 🚢 Active cargo lane appears when the pair is an observed trade lane: it shows the dominant tonnage band, today’s indicative lane rate in $/day, and a one-click jump to the full lane history page. Every query you run also accrues into the route-intelligence layer that future per-owner routing advice will draw on.

More guides