Ferry Near a Port

Ferry Near a Port

You need to answer a deceptively simple question in production: “Is a ferry near a port, what is it doing, and when will it berth or depart?” By the end of this post, you’ll be able to build that view with a live map tile, a list of ferries inside a radius of a port, current AIS status, ETA, and a feed of port arrivals/departures—using vessels-api.com’s REST API.

What “ferry near a port” means, technically

For ferry operations teams, dispatchers, terminal operators, and apps showing commuter modalities, “near a port” typically translates into one or more of the following:

Illustration: Ferry Near a Port
  • Ferries within X nautical miles of a port’s coordinates
  • Ferries already in-port and their current navigational status
  • Inbound ferries expected to arrive with ETA and origin
  • Live vessel course and speed to validate an ETA against reality

Vessels API provides these via a consistent JSON envelope across endpoints: {status, success, message, data}. You authenticate the same way for all endpoints using the X-API-Key header against a single base URL: https://vessels-api.com/api/V1.

Core endpoints for a ferry-near-port workflow

  • GET /vessels/nearby — discover ferries around a port’s coordinates
  • GET /vessels/track — confirm live position, route, and ETA
  • GET /ports/data — retrieve a port’s identifying data and live counts
  • GET /port/expected-arrivals — see inbound ferries with ETA and origin
  • GET /port/activity — recent arrivals/departures for operations feeds

1) Get the port coordinates and a quick operational snapshot

Start by resolving a port and its coordinates for your geospatial center. You can then fan out into “nearby” queries and activity feeds.

GET /ports

Use this to load or cache the catalog for lookups and UX pickers. It returns a list of 248 ports with coordinates and timezones.

curl -H "X-API-Key: YOUR_API_KEY" "https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48"

Key fields you’ll need:

  • port_id — your stable identifier for subsequent calls
  • latitude, longitude — center for geo queries
  • timezone — useful for UI/UX when rendering local times

GET /ports/data

Query a single port to show live vessel counts and metadata next to the map.

Response fields to display:

  • data.port_id, data.name, data.country, data.timezone
  • data.vessels_in_port — current number in-port
  • data.vessels_expected — count of vessels inbound

Tip: Cache this response for short intervals (e.g., 60–120 seconds) to reduce map thrash and calls while keeping counts fresh.

2) Find ferries within X nautical miles of the port

Once you have a port’s latitude/longitude, query for nearby vessels filtered by ship_type=ferry. The API returns position, speed, and a distance in nautical miles from the center point.

GET /vessels/nearby

Sample JSON (abbreviated for clarity):

{
    "status": 200,
    "success": true,
    "message": "OK",
    "data": {
        "vessel": {
            "imo": "9122556",
            "mmsi": "258785000",
            "name": null
        },
        "current_position": {
            "latitude": 53.33708,
            "longitude": 7.17993,
            "speed_knots": 0,
            "course_degrees": 212,
            "heading_degrees": null,
            "navigational_status": 5,
            "timestamp_utc": "2017-01-24T04:07:16+00:00",
            "age_minutes": 5151440,
            "destination": null,
            "eta": null
        },
        "predicted_eta": null,
        "position_history": [],
        "route": {
            "departure_port": "HERACLIO",
            "departure_time": "2026-04-27T21:35:36+00:00",
            "destination_port": "HERACLIO",
            "eta": null,
            "distance_nm": null,
            "avg_speed_knots": 17.1
        },
        "last_port_visits": [
            {
                "port_id": "156",
                "port_name": "EMDEN",
                "arrival_time": "2026-07-30T13:00:10+00:00",
                "departure_time": null,
                "duration_hours": null
            },
            {
                "port_id": "10",
                "port_name": "HERACLIO",
                "arrival_time": "2026-04-20T12:00:00+00:00",
                "departure_time": "2026-04-23T08:00:00+00:00",
                "duration_hours": 68
            }
        ],
        "weather": null
    }
}

What to use:

  • vessels[].distance_nm — to sort ferries by proximity
  • vessels[].speed_knots and course_degrees — to infer approach trajectories
  • vessels[].position.timestamp_utc — UTC ISO 8601 timestamps for latency checks

3) Confirm a ferry’s live track, route, and ETA

After you identify candidates near the port, fetch an authoritative track for a selected ferry. This powers detail side panels and ETA logic.

GET /vessels/track (official sample)

Use the documented fixture for testing and integration scaffolding. Copy this call verbatim to validate auth and JSON envelope handling.

Fields to render:

  • data.current_position.latitude/longitude, speed_knots, course_degrees
  • data.current_position.timestamp_utc (UTC)
  • data.route.departure_port, destination_port, avg_speed_knots
  • data.last_port_visits[] — useful to show service pattern context

Notes:

  • hours defaults to 24 and max is 168. Use include_route, include_predicted_eta, include_weather to tailor payloads.
  • If predicted_eta is returned, prefer it for UI, but always reconcile with live speed/course for sanity checks.

Python example: nearby + track drill-down

This example finds ferries near a port coordinate and then fetches a detailed track for the closest ferry.

import os
import requests
from math import isfinite

API_KEY = os.getenv("VESSELS_API_KEY", "YOUR_API_KEY")
BASE = "https://vessels-api.com/api/V1"

headers = {"X-API-Key": API_KEY}

def ferries_near_port(lat, lon, radius_nm=10):
params = {
"latitude": lat,
"longitude": lon,
"radius": radius_nm,
"ship_type": "ferry",
"limit": 50
}
r = requests.get(f"{BASE}/vessels/nearby", headers=headers, params=params, timeout=20)
r.raise_for_status()
data = r.json()["data"]
ferries = data.get("vessels", [])
ferries.sort(key=lambda v: v.get("distance_nm", float("inf")))
return ferries

def track_by_mmsi(mmsi, hours=24):
params = {"mmsi": mmsi, "hours": hours}
r = requests.get(f"{BASE}/vessels/track", headers=headers, params=params, timeout=20)
r.raise_for_status()
return r.json()["data"]

if __name__ == "__main__":
# Example: center near a port coordinate
center_lat, center_lon = -34.60, -58.38
ferries = ferries_near_port(center_lat, center_lon, radius_nm=12)
if not ferries:
print("No ferries nearby.")
else:
top = ferries[0]
mmsi = top.get("mmsi")
name = top.get("name")
dist = top.get("distance_nm")
print(f"Closest ferry: {name} MMSI={mmsi} at {dist} nm")
detail = track_by_mmsi(mmsi, hours=48)
cp = detail.get("current_position", {})
print("Now at:", cp.get("latitude"), cp.get("longitude"),
"speed_knots:", cp.get("speed_knots"),
"course_degrees:", cp.get("course_degrees"),
"ts:", cp.get("timestamp_utc"))

4) What’s expected to arrive next at the port

Blend real-time tracks with the port’s expected arrivals to anticipate gate flow and terminal loading.

GET /port/expected-arrivals

Sample JSON (abbreviated):

Use eta as UTC for logic; convert to local with the timezone from /ports or /ports/data if showing local UI times. For ferries with short headways, poll more frequently but implement exponential backoff when the list is empty to conserve calls.

5) Recent port activity for operational context

Render a feed that pairs nicely with your nearby map: “what arrived in the last N hours, and what just departed?”

GET /port/activity

Sample JSON (abbreviated):

Use arrivals[].arrival_time and departures[].departure_time as canonical event timestamps (UTC). For ferries operating frequent legs, this list becomes the best source for service reliability analytics, especially when combined with /vessels/analytics for aggregate speeds and port calls.

Optional: Congestion signal for planning

For port-side decisions (berth assignment, terminal ops), query congestion. This endpoint returns a real-time snapshot of vessels in anchorage and at berth, plus wait-time stats over a selectable period.

Fields include data.snapshot.vessels_in_anchorage, data.snapshot.vessels_at_berth and aggregated statistics for the period you request. Pair this with nearby vessel speed patterns to signal potential delays to passengers or cargo handlers.

Production details that save time

  • Authentication: send X-API-Key: YOUR_API_KEY on every request. No OAuth or per-endpoint differences.
  • Envelope: every response uses {status, success, message, data}. Check status for 200 before reading data.
  • Timestamps: all times are UTC ISO 8601. Convert to the port’s timezone from /ports or /ports/data for display.
  • Units: distances are nautical miles; speed is knots; course/heading in degrees.
  • Limits: /vessels/nearby radius defaults to 50 NM, max 200 NM. limit defaults to 50.
  • History: /vessels/track supports hours up to 168 (7 days).
  • Pagination: for /vessels/search, paginate with page and per_page (max 100) if you add search to your UI.
  • Error handling: 401 for invalid/missing key, 404 when a vessel/port isn’t found, 429 for rate limits. Back off and retry per your queue policy.

End-to-end flow: ferry near a port dashboard

  1. Resolve port coordinates using GET /ports or GET /ports/data. Center your map and show live in-port counts.
  2. Call GET /vessels/nearby with ship_type=ferry and a reasonable radius (e.g., 8–12 NM) for approach corridors.
  3. For each result, display distance_nm, speed_knots, and navigational_status (e.g., underway vs. moored).
  4. On vessel selection, call GET /vessels/track to pull the current_position and route. Render an ETA if provided; otherwise derive a simple ETA model with distance and recent avg speed.
  5. Complement with GET /port/expected-arrivals and GET /port/activity to show inbound schedules and the latest calls.
  6. Optionally add GET /ports/congestion to flag potential delays when anchorage or wait-time stats spike.

cURL quick-start

Use these three calls to stand up a working prototype quickly:

# 1) Port snapshot for coordinates and live counts
curl -H "X-API-Key: YOUR_API_KEY" "https://vessels-api.com/api/V1/ports/data?port=ARBUE"

# 2) Ferries within 12 NM of the port center
curl -H "X-API-Key: YOUR_API_KEY" "https://vessels-api.com/api/V1/vessels/nearby?latitude=-34.60&longitude=-58.38&radius=12&ship_type=ferry&limit=50"

# 3) Live track of a selected ferry (official sample)
curl -H "X-API-Key: YOUR_API_KEY" "https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48"

JavaScript fetch example: expected arrivals list

async function getExpectedArrivals(portId = "ARBUE") {
const url = `https://vessels-api.com/api/V1/port/expected-arrivals?port=${encodeURIComponent(portId)}`;
const res = await fetch(url, {
headers: { "X-API-Key": "YOUR_API_KEY" }
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
const arrivals = json.data.expected_arrivals || [];
return arrivals.map(v => ({
mmsi: v.mmsi,
name: v.name,
etaUtc: v.eta,
origin: v.departure_port
}));
}

getExpectedArrivals().then(list => {
console.table(list);
}).catch(console.error);

Why teams building ferry ops choose this approach

  • 18 REST endpoints that cover discovery, live tracking, fleet ops, port intelligence, and IMO CII emissions, plus a premium real-time AIS feed.
  • One key, one base URL, consistent JSON structure—drop into any stack quickly.
  • Global AIS coverage and near real-time refresh fit both commuter ferries and long coastal routes.
  • Supports indie prototypes and enterprise dispatch centers with the same API surface.

FAQ

Q: How fresh is position data and what timezone are timestamps in?
A: Timestamps are UTC ISO 8601 and positions refresh near real-time. Use current_position.timestamp_utc and age_minutes to understand latency.

Q: How do I filter only ferries in the nearby query?
A: Pass ship_type=ferry to GET /vessels/nearby. You can also filter by ship_type in GET /vessels/search if you build a search UI.

Q: Can I monitor multiple ferries at once?
A: Yes. Use POST /vessels/fleet with an array of {imo, mmsi} and include_positions/include_routes. It returns batch positions and route snapshots for dashboard tiles.

Q: How do I show ETAs?
A: Prefer predicted_eta when included in GET /vessels/track. Otherwise use route.distance_nm with recent avg_speed_knots, and cross-check with current_position.speed_knots for large deviations.

Q: What happens if I exceed rate limits?
A: The API returns HTTP 429. Implement backoff and cache stable responses (e.g., ports catalog, last-port visits) to stay efficient.

Next steps

Spin up a ferry-near-port map and activity feed in an afternoon: fetch a port center, list ferries within a radius, and drill into tracks and arrivals with the same authentication model across endpoints. Start with the official track sample above, then iterate to production with pagination and caching.

Register for an API key, read the Documentation, and explore the MCP to wire the endpoints into your stack.

Ready to get started?

Get your API key and start tracking vessels in minutes.

Get API Key