Fishing Vessel Tracking API: Fleet Positions and Analytics

Fishing Vessel Tracking API: Fleet Positions and Analytics

Fisheries teams, coastal states, and maritime startups often need an exact, real-time picture of where fishing vessels are, where they’ve been, and which ports they’re interacting with. By the end of this guide, you’ll be able to integrate fleet-wide fishing vessel tracking, nearby vessel safety checks, voyage analytics, and port congestion intelligence using a single, consistent REST API with predictable JSON responses.

Why this API fits fishing operations

Fishing fleets change positions quickly, operate near coastlines with dense traffic, and depend on fast decisions—e.g., diverting to a less congested port, documenting time-at-sea for compliance, or dispatching tenders to the nearest boat. The vessels-api.com platform exposes:

Illustration: Fishing Vessel Tracking API: Fleet Positions and Analytics
  • 18 REST endpoints for search, live tracking, fleet operations, port intelligence, and IMO CII scoring.
  • One API key via X-API-Key header and one base URL (no OAuth or per-endpoint differences).
  • Global AIS coverage with near real-time refresh.
  • Consistent JSON envelope: {status, success, message, data} for every response.
  • 7-day free trial on all plans and a model that scales from a few boats to enterprise fleets.

For fishing-specific workflows, we’ll go deep on five endpoints:

  • GET /vessels/track — live AIS and up to 168 hours of history
  • GET /vessels/nearby — collision-avoidance and safety checks
  • GET /vessels/analytics — voyage rollups for vessels or fleets
  • POST /vessels/fleet — batch tracking for dashboards
  • GET /ports/congestion — anchorage vs. berth snapshot and wait-time statistics

Authentication and base URL

All requests go to https://vessels-api.com/api/V1 and require a single header:

  • X-API-Key: YOUR_API_KEY

Every response follows the envelope {status, success, message, data}, which makes error handling easier across endpoints. Common statuses include 200 (OK), 400 (invalid parameter), 401 (missing/invalid key), 404 (not found), 422 (out of range), 429 (rate limit), and 500 (server error).

Track a fishing vessel with live AIS and route context

Use GET /vessels/track to pull a fishing vessel’s current position, up to 168 hours of track history, the active route, and predicted ETA. You can query by IMO or MMSI. For operational UIs, set hours to the shortest window you need to keep payloads light; for backfills, go up to 168.

Official cURL example and JSON

The following sample is provided as-is and demonstrates a 48-hour track retrieval for a documented MMSI. Copy and run it with your key.

curl -H "X-API-Key: YOUR_API_KEY" "https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48"
{
"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:27+00:00",
"age_minutes": 5095940,
"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": "2026-04-30T09:00:00+00:00",
"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
}
}

Key fields to use in fishing operations:

  • current_position.latitude/longitude (decimal degrees, WGS84), speed_knots, course_degrees. Timestamps are UTC ISO-8601.
  • navigational_status (integer AIS NavStatus). For UIs, treat unknown/null safely.
  • route.departure_port, destination_port, eta for logistics context.
  • last_port_visits for audit/compliance timelines and buyer documentation.
  • position_history (when present) holds chronological track points over the hours window you requested.

Python example: plot last known position

This sample calls the same endpoint and extracts map-ready coordinates and timing. It uses only documented fields.

import requests
from datetime import datetime, timezone

API_KEY = "YOUR_API_KEY"
URL = "https://vessels-api.com/api/V1/vessels/track"
params = {
"mmsi": "258785000",
"hours": "48"
}
headers = {"X-API-Key": API_KEY}

r = requests.get(URL, headers=headers, params=params, timeout=30)
r.raise_for_status()
payload = r.json()

if not payload.get("success"):
raise RuntimeError(f"API error: {payload.get('message')}")

data = payload["data"]
pos = data.get("current_position", {}) or {}
lat = pos.get("latitude")
lon = pos.get("longitude")
speed = pos.get("speed_knots")
ts_utc = pos.get("timestamp_utc")

print(f"Lat: {lat}, Lon: {lon}, Speed(kn): {speed}, Time(UTC): {ts_utc}")

route = data.get("route") or {}
print(f"Route: {route.get('departure_port')} → {route.get('destination_port')} ETA: {route.get('eta')}")

# Simple stale-data guard for dashboards:
if ts_utc:
seen = datetime.fromisoformat(ts_utc.replace("Z", "+00:00"))
age_minutes = (datetime.now(timezone.utc) - seen).total_seconds() / 60.0
if age_minutes > 60:
print(f"Warning: AIS older than 60 minutes ({age_minutes:.1f} min). Show 'stale' badge.")

Find vessels near a fishing ground or tender

For collision avoidance, tender dispatch, or SAR workflows, GET /vessels/nearby returns all vessels within a radius in nautical miles of any lat/lon. You can filter by ship_type when you only want fishing vessels or to exclude non-relevant traffic.

cURL example: 30 NM around a fishing ground

Response structure highlights:

  • data.center, data.radius_nm, data.total
  • data.vessels[].position.latitude/longitude/timestamp_utc (UTC ISO-8601)
  • distance_nm from the center point for quick sorting (“closest first” UIs)
  • ship_type if you want to include only fishing craft in the display or alerts

Implementation tips:

  • Set radius to the smallest viable value (default 50 NM, max 200) to reduce payload.
  • Use limit to cap results for low-power devices and map clustering.
  • Cache for 15–60 seconds if your UI auto-refreshes; the feed updates near real-time.

A single request for the whole fishing fleet

Fleet dashboards should avoid N serial calls. POST /vessels/fleet lets you fetch the latest positions and routes for multiple vessels in one body. This is the backbone of an operations map, catch logistics board, or watcher service for regulatory zones.

cURL example: batch two vessels

Response structure highlights:

  • data.fleet.total_vessels, vessels_at_sea, vessels_in_port for top-line KPIs.
  • data.vessels[] with per-vessel position and route, ready to render in cards or map markers.

Implementation tips:

  • Batch your vessel list server-side and push updates to the client via WebSocket or SSE to minimize browser churn.
  • Store last seen positions to detect and alert on off-course movements or extended zero-speed events.

Voyage analytics for effort, port calls, and time in port

Fishing operators often need high-level effort metrics for resource planning and compliance (e.g., port calls and time in port across a season). GET /vessels/analytics aggregates statistics for a vessel, a port, or a fleet over selectable windows.

Modes and parameters

  • type=vessel requires imo or mmsi.
  • type=port requires port_id (UNLOCODE from the title parentheses in port listings).
  • type=fleet requires mmsi_list (comma-separated list).
  • period can be 24h, 7d, 30d, or 90d.

cURL example: 7-day vessel analytics

Response fields to plug into dashboards and reports:

  • statistics.total_distance_nm — fuel and effort proxy for a fishing window.
  • avg_speed_knots and max_speed_knots — detect unusual transit (e.g., rushing to port).
  • port_calls_count and total_time_in_port_hours — crucial for scheduling and offloading logistics.
  • ports_visited — display-lists for management and buyer traceability.

For fleet mode, aggregate vessel-level totals to daily/weekly summaries in your data store. For trip-level views, pair analytics with /vessels/track position_history to render tracks per route segment.

Port congestion: choose the right landing port

Ice, weather, and traffic can turn a quick discharge into a multi-day queue. GET /ports/congestion provides a real-time snapshot for a port and short-window statistics (e.g., 7d averages) to guide port choice and tender planning. Use only documented UNLOCODEs from the port’s title parentheses such as ARBUE (Buenos Aires), SGSIN (Singapore), or NLRTM (Rotterdam).

cURL example: Buenos Aires 7-day congestion

Response highlights:

  • snapshot.vessels_in_anchorage and snapshot.vessels_at_berth — the now-state.
  • statistics.avg_wait_time_hours_last_7d, max_wait_time_hours_last_7d — a short history view.
  • statistics.avg_berth_time_hours_last_7d, port_calls_count — throughput indicators.

Implementation tips:

  • When toggling ports in the UI, cache the latest results briefly to avoid needless refresh pressure.
  • Overlay congestion with /port/expected-arrivals to anticipate inbound waves.

Designing a fishing fleet dashboard with these endpoints

Minimum viable map

  • Use POST /vessels/fleet as your map data source every 15–60 seconds.
  • For a clicked vessel, call GET /vessels/track with include_route, include_predicted_eta, and a modest hours window (e.g., 24h) to show breadcrumb history.
  • If your fishing grounds are sensitive, poll GET /vessels/nearby around the active nets to see who else is in range. Use ship_type to focus on fishing craft.

Operations and safety panels

  • Show stale-data badges when current_position.timestamp_utc is older than your threshold (e.g., 30–60 minutes) to avoid false precision in the UI.
  • Flag zero-speed events longer than N minutes for potential gear issues or drifting at anchorage.
  • Set guard zones using /vessels/nearby to alert when non-fleet vessels cross into defined polygons (approximate with several circles if needed).

Logistics and compliance

  • Use /vessels/analytics (period=7d or 30d) to report vessel effort, time in port, and port calls to suppliers and buyers.
  • Call /ports/congestion before committing to a landing port; highlight average and max waits.

Error handling, units, and pagination

  • Units: positions are decimal degrees (WGS84); speeds in knots; distances in nautical miles; durations in hours. Timestamps are UTC ISO-8601.
  • Always check the top-level {status, success, message}. Do not assume a data payload without success=true.
  • For search and port listings, pagination is supported with page and per_page (max 100). Keep per_page modest to protect client memory.
  • Gracefully handle 429 (rate limit exceeded) by backing off and caching results briefly in your service tier.

Extended examples developers ship

JavaScript: three-call orchestration for a details drawer

When a user clicks a vessel, you can compose a quick information panel with track, analytics, and nearby context. This example shows how to parallelize calls client-side. Keep your API key on a server if you cannot protect it in the client.

async function fetchJSON(url) {
const r = await fetch(url, {
headers: { "X-API-Key": "YOUR_API_KEY" }
});
if (!r.ok) throw new Error("HTTP " + r.status);
const j = await r.json();
if (!j.success) throw new Error(j.message || "API error");
return j.data;
}

async function loadVesselDetail(mmsi) {
const base = "https://vessels-api.com/api/V1";
const trackUrl = `${base}/vessels/track?mmsi=${encodeURIComponent(mmsi)}&hours=24`;
const analyticsUrl = `${base}/vessels/analytics?type=vessel&mmsi=${encodeURIComponent(mmsi)}&period=7d`;

// Use the current position as the center for a small nearby scan:
const trackData = await fetchJSON(trackUrl);
const pos = (trackData.current_position || {});
const lat = pos.latitude, lon = pos.longitude;

const nearbyUrl = lat != null && lon != null
? `${base}/vessels/nearby?latitude=${lat}&longitude=${lon}&radius=10`
: null;

const [analyticsData, nearbyData] = await Promise.all([
fetchJSON(analyticsUrl),
nearbyUrl ? fetchJSON(nearbyUrl) : Promise.resolve({ vessels: [] })
]);

return { track: trackData, analytics: analyticsData, nearby: nearbyData };
}

loadVesselDetail("258785000")
.then(res => {
console.log("Track:", res.track);
console.log("Analytics 7d:", res.analytics);
console.log("Nearby 10 NM:", res.nearby);
})
.catch(err => console.error("Error:", err));

Notes:

  • If current_position is missing or latitude/longitude are null, skip the nearby query.
  • Show a stale-data badge when track.current_position.timestamp_utc is old.
  • Do not leak keys in browser code you cannot control; proxy via your backend when in doubt.

Building ESG and compliance add-ons (optional)

Fishing fleets increasingly require emissions reporting and efficiency scanning for regulatory and buyer programs. The GET /vessels/green endpoint returns an estimated emissions summary and an IMO CII rating (A to E) for a supplied period, based on MEPC.339(76). Although not limited to fishing craft, it fits well into an “environment” tab next to your fleet map.

cURL example: 30-day emissions for a vessel

Use fields:

  • estimated_emissions.co2_tons and co2_per_nm to compare operational periods.
  • cii.score and cii.rating for ESG dashboards.

Production checklist for fishing deployments

  • Normalize UTC timestamps on ingest. Always display timezones explicitly in the UI if you localize for port ops.
  • Back off on 429 and cache last-good results to avoid UI flicker.
  • Use small hours windows on /vessels/track unless you’re rendering history.
  • Guard against nulls in optional fields like heading_degrees, predicted_eta, and weather.
  • When tracking many vessels, prefer POST /vessels/fleet over N parallel GETs.
  • Enable ship_type filtering in nearby scans for narrow situational awareness while fishing.

Frequently asked questions

What refresh rate should I expect for fishing vessel positions?
The feed provides global AIS coverage with near real-time refresh. For dashboards, polling every 15–60 seconds is common; cache results briefly to reduce load.

Can I request more than 168 hours of track history?
No. The documented maximum for the hours parameter on GET /vessels/track is 168. For longer-term analytics, store daily snapshots or use GET /vessels/analytics for aggregated values.

How do I authenticate across all endpoints?
Use the X-API-Key header with your key on every request. There are no per-endpoint authentication differences and no OAuth flows to manage.

How do I identify fishing vessels only?
Use ship_type filters where available (e.g., GET /vessels/nearby) and combine with your own curated fleet list in POST /vessels/fleet for high precision.

Which timezone are timestamps in?
All timestamps are UTC in ISO-8601 format. Convert for local displays as needed, and consider labeling local time alongside UTC for port operations.

Ready to build your fishing fleet map, analytics, and port decision tools on a single, developer-friendly API? Start with the Register page, explore the Documentation, and try queries interactively via the MCP console.

Ready to get started?

Get your API key and start tracking vessels in minutes.

Get API Key

Related posts