You need reliable fishing vessel tracking you can ship today: find active boats, watch their tracks across fishing grounds, calculate ETAs back to port, aggregate fleet activity, and keep compliance teams informed. By the end of this post, you’ll be able to plug AIS-powered fishing vessel tracking into your app using a single REST API with consistent JSON, one API key, and production-ready examples.
What you’ll build with the Vessels API
This guide focuses on fishing vessel tracking use cases using these endpoints:
- GET /vessels/search — locate target fishing vessels by name, IMO, or MMSI
- GET /vessels/track — live position, last 24–168 hours of AIS, route, and ETA
- GET /vessels/nearby — detect vessels clustered around a fishing ground
- POST /vessels/fleet — snapshot positions and routes for an entire fleet
- GET /vessels/green — CII emissions scoring for ESG and compliance reporting
All endpoints live under https://vessels-api.com/api/V1 and use the X-API-Key header. Responses follow a consistent envelope: {"status", "success", "message", "data"} and timestamps are UTC. Units: knots for speed and nautical miles (nm) for distance.
Core endpoint: Live and historical tracking
Fishing operations are dynamic and coastal coverage varies. For operational awareness, start with GET /vessels/track. It returns the current AIS position, optional route details, up to 168 hours of history, and predicted ETA. You can call it by either IMO or MMSI.
Official cURL: Track documented MMSI 258785000
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:26+00:00",
"age_minutes": 5136380,
"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 in your app:
- data.current_position.latitude/longitude, speed_knots, course_degrees — plot and orient the track line on the map
- data.current_position.timestamp_utc (UTC ISO 8601) — show data freshness and enable caching rules
- data.route.* and data.predicted_eta — estimated return-to-port timelines for landing schedules
- data.last_port_visits — context for recent landings and potential regulatory checks
Python example: Track a fishing vessel and compute stale-position alerts
This script calls the same track endpoint (MMSI 258785000) and flags positions older than 60 minutes.
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}
resp = requests.get(URL, headers={"X-API-Key": API_KEY}, params=params, timeout=20)
resp.raise_for_status()
payload = resp.json()
if not payload.get("success"):
raise RuntimeError(f"API error: {payload.get('message')}")
data = payload["data"]
vessel = data["vessel"]
pos = data["current_position"]
lat = pos["latitude"]
lon = pos["longitude"]
speed = pos["speed_knots"]
course = pos["course_degrees"]
ts = pos["timestamp_utc"] # UTC ISO8601
# Freshness check using provided 'age_minutes' when available
age_min = pos.get("age_minutes")
is_stale = age_min is not None and age_min > 60
print(f"MMSI: {vessel['mmsi']}, IMO: {vessel['imo']}")
print(f"Position: {lat:.5f}, {lon:.5f} at {ts} | speed {speed} kn course {course}°")
print("STALE" if is_stale else "FRESH")
route = data.get("route") or {}
print(f"Route: {route.get('departure_port')} → {route.get('destination_port')} | avg {route.get('avg_speed_knots')} kn")
# Optional: iterate history if present
for fix in data.get("position_history", []):
# fix contains historical lat/lon/timestamp and may include speed/course
pass
Find the right fishing vessels fast
Before tracking, you need to look up the MMSI or IMO of the target vessel. Use GET /vessels/search with fuzzy name search and optional filters (e.g., ship_type to narrow to fishing vessels if available in your data pipeline).
Response fields to wire up:
- data.vessels[].imo, mmsi, name — identifiers for linking to /vessels/track
- data.vessels[].vessel_type, flag, year_built — show quick context in search results
- data.pagination.{current_page, per_page, total, last_page} — build infinite scroll or pagination controls
Implementation detail: cache successful search results for a few minutes client-side to reduce round-trips. Respect HTTP 429 (rate limit exceeded) by backing off and retrying with jitter.
Detect fishing activity clusters near grounds
To identify hotspots or deconflict operations, query all vessels around a point using GET /vessels/nearby. Filter to ship_type if you only want fishing vessels in the picture. Radius is in nautical miles (default 50, max 200).
Key integration notes:
- data.vessels[].position.timestamp_utc is UTC; display local time by converting on the client if needed.
- data.vessels[].distance_nm — order results by proximity to your ground or gear location.
- Limit data to 50–100 vessels per call for map performance; progressively load more as users zoom.
Manage entire fishing fleets in a single call
For regional coordinators or producers chartering several boats, use POST /vessels/fleet. You can request positions and route summaries for many vessels at once. This keeps your dashboard snappy and minimizes HTTP overhead.
What to display:
- data.fleet.vessels_at_sea vs vessels_in_port — at-a-glance operations snapshot
- data.vessels[].position.speed_knots and navigational_status — detect trawling vs transiting patterns
- data.vessels[].route.{destination_port, eta} — plan landing windows and dock resources
Tip: if your frontend supports it, poll fleets every 30–60 seconds for near real-time AIS or adjust per your refresh budget. Use ETags or conditional requests at the edge when feasible.
Compliance: CII emissions scoring for fishing vessels
ESG teams may need periodic emissions reporting even for smaller fishing vessels. GET /vessels/green provides distance, estimated CO2, and an IMO CII score (A–E). Choose period from 24h, 7d, 30d, 1y; default is 30d.
Integrate the following fields:
- data.cii.rating and data.cii.score — display letter grade and numeric score
- data.estimated_emissions.co2_tons and co2_per_nm — normalize against distance
- data.period — show the window of analysis in reports to avoid confusion
If you manage multiple boats, batch by MMSI/IMO in your job queue and persist results to power trend charts without refetching historical periods each time.
Analytics that actually help ops
When you need rollups beyond a single track, GET /vessels/analytics returns aggregated voyage statistics. For fishing, it helps you quantify activity levels, average speeds across trips, and frequency of port calls (for offloading/planning).
Map these fields to UI:
- statistics.total_distance_nm — fuel and effort proxy
- statistics.avg_speed_knots / max_speed_knots — behavior profiling across the week
- statistics.port_calls_count and total_time_in_port_hours — cycle planning
Putting it together: a minimal fishing fleet dashboard
Data flow
- Vessel selection: GET /vessels/search to resolve identifiers and populate a list
- Map: GET /vessels/nearby to render clusters and the operating picture
- Detail pane: GET /vessels/track for the selected vessel with hours=24–48
- Fleet bar: POST /vessels/fleet for aggregate counters and quick statuses
- Compliance tab: GET /vessels/green for CII scorecards
Frontend/UI hints
- Plot great-circle segments between successive points (position_history) and color by speed_knots bands.
- Expose a staleness badge driven by current_position.age_minutes > threshold.
- Use pagination on /vessels/search with per_page ≤ 100 as documented.
- Standardize on UTC in the backend; convert to local timezones in the view.
Error handling and reliability
- Authentication: all requests require X-API-Key. 401 indicates a missing or invalid key.
- Validation: 400 for missing/invalid parameters, 422 for out-of-range (e.g., radius > 200 nm).
- Not found: 404 if a vessel or port is unknown to the index.
- Throttling: 429 for rate limit exceeded; implement exponential backoff with jitter.
- Server: 500 — retry with backoff and surface a user-facing “try again” state.
All responses share the same envelope, so your client can centralize success/error parsing and only switch on payload.data shape by endpoint.
Security and performance checklist
- Do not embed your API key in public clients; proxy via your backend.
- Cache non-live endpoints (search, analytics, green) for minutes to hours as your SLA permits.
- For live maps, poll /vessels/track and /vessels/fleet on a cadence aligned with your UX; near real-time AIS typically benefits from 30–60s refresh on focused views.
- Guardrail inputs: clamp radius to ≤ 200 and limit page sizes to ≤ 100.
Explore the API and tools
- Register — get your API key and start testing in minutes
- Documentation — endpoint parameters, response fields, and examples
- MCP — tools and controls for managing your integrations
FAQ
Q: What identifiers should I store for fishing vessels?
A: Store both IMO and MMSI when available. Most tracking calls accept either, and having both helps with data continuity if one changes or is missing temporarily.
Q: How fresh is the AIS data, and how do I show staleness?
A: Use current_position.timestamp_utc and age_minutes. If age_minutes exceeds your threshold (e.g., > 60), show a stale badge and consider reducing map update frequency for that vessel.
Q: Can I retrieve more than 24 hours of history?
A: Yes. /vessels/track supports hours up to 168 (7 days). For heavier use, pull the last 24–48 hours during interactive sessions and expand to 168 on demand.
Q: How do I filter for fishing vessels only?
A: Use ship_type=Fishing on /vessels/search and /vessels/nearby when applicable in your workflow. You can also pre-filter your fleet list to known fishing MMSIs/IMOs in your own database.
Q: What fields should I log for compliance reports?
A: From /vessels/green, persist period, estimated_emissions.co2_tons, co2_per_nm, and cii.rating/score. From /vessels/track, store last_port_visits and route timestamps to corroborate voyage segments.
Build your fishing vessel tracker today
With a single base URL, one API key, and consistent JSON across endpoints, you can deliver fishing vessel search, live tracking, fleet snapshots, and CII scoring without maintaining multiple data feeds. Start integrating now with the live examples above, explore more parameters in the Documentation, and grab your key from Register. If you manage several environments or teams, check out MCP for operational controls.


