Analyzing a Fleet (a Group of Vessels)
Combine the 4Wings, Vessels and Events APIs to analyze a fleet of vessels across fishing effort, identity and event history.
This workflow shows how to analyze a fleet — a group of vessels — by combining the 4Wings API, the Vessels API, and the Events API across multiple vessel IDs.
Use Case: Monitoring a Fleet of Tuna Longliners for Compliance
Kwame is a fisheries compliance officer in Ghana, responsible for monitoring a fleet of tuna longliners operating within Ghana's Exclusive Economic Zone (EEZ). His goal is to:
- ✅ Track apparent fishing effort for longliners over the last 12 months.
- ✅ Identify potential vessels in this fleet, their operational patterns, and their activity levels.
- ✅ Retrieve vessel details, including flag state, ownership history, and authorizations.
- ✅ Analyze events such as port visits and encounters (potential transshipment) activities.
APIs Used:
- 4Wings API — Retrieve apparent fishing effort grouped by vessel ID in Ghana's EEZ.
- Vessels API — Get vessel identity, ownership, and compliance details.
- Events API — Identify port visits and potential transshipment activities for vessels in the fleet.
Step 0: Identify the Region of Interest (ROI) — Ghana EEZ
Before making API requests, Kwame must specify the geographic area for analysis using a Region ID:
Options to define the region:
- Using Region ID — Each EEZ has a unique ID in the
public-eez-areasdataset. - Custom Geometries — Users can define a custom area using GeoJSON.
- Find EEZ Region IDs using the Regions dataset — see the Datasets documentation.
- For the Ghanaian EEZ, the region ID is 8400 (
public-eez-areasdataset).
The 4Wings Report API provides flexible output formats, including TIFF (GeoTIFF) for geospatial mapping, JSON for raw data analysis, and CSV.
Important Caveats
- 🚨 The 4Wings API only supports one active report per user at a time.
- 🔴 Sending multiple requests simultaneously results in a 429 Too Many Requests error.
- Report Generation Time & Timeout Risks:
- If a report takes over 100 seconds to generate, it may return a 524 Gateway Timeout error.
- To retrieve a previously requested report, use the last-report endpoint instead. For details, see the 4Wings API documentation.
Step 1: Retrieve Fishing Effort in Ghana's EEZ
Kwame first queries the 4Wings API to get fishing effort for all vessels, grouping them by gear type.
Endpoint: /v3/4wings/report
Filters used:
- Region ID = 8400 (Ghana EEZ)
- Date Range = Last 12 Months
- Grouped by Gear Type
API Request: POST
# Make sure to replace [TOKEN] with your API Access Token.
curl --location --globoff 'https://gateway.api.globalfishingwatch.org/v3/4wings/report?format=JSON&datasets[0]=public-global-fishing-effort%3Alatest&temporal-resolution=ENTIRE&spatial-resolution=LOW&spatial-aggregation=true&group-by=GEARTYPE&date-range=2024-01-01%2C2025-01-01' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [TOKEN]' \
--data '{
"region": {
"dataset": "public-eez-areas",
"id": 8400
}
}'result = await gfw_client.fourwings.create_report(
datasets=["public-global-fishing-effort:latest"],
spatial_resolution="LOW",
temporal_resolution="ENTIRE",
group_by="GEARTYPE",
spatial_aggregation=True,
start_date="2024-01-01",
end_date="2025-01-01",
region={"dataset": "public-eez-areas", "id": 8400},
)gfw_ais_fishing_hours(
spatial_resolution = "LOW",
temporal_resolution = "ENTIRE",
start_date = "2024-01-01",
end_date = "2025-01-01",
region_source = "EEZ",
region = 8400,
group_by = "GEARTYPE"
)// Make sure to replace [TOKEN] with your API Access Token.
const res = await fetch(
'https://gateway.api.globalfishingwatch.org/v3/4wings/report?format=JSON&datasets[0]=public-global-fishing-effort%3Alatest&temporal-resolution=ENTIRE&spatial-resolution=LOW&spatial-aggregation=true&group-by=GEARTYPE&date-range=2024-01-01%2C2025-01-01',
{
method: 'POST',
headers: {
Authorization: 'Bearer [TOKEN]',
'Content-Type': 'application/json',
},
body: JSON.stringify({
region: {
dataset: 'public-eez-areas',
id: 8400,
},
}),
}
)
const data = await res.json()Example API Response:
{
"entries": [
{
"public-global-fishing-effort:v3.0": [
{
"callsign": "JRWC",
"dataset": "public-global-vessel-identity:v3.0",
"date": "2024-01-01,2025-01-01",
"entryTimestamp": "2024-08-08T01:00:00Z",
"exitTimestamp": "2024-10-15T22:00:00Z",
"firstTransmissionDate": "2016-04-20T21:36:13Z",
"flag": "JPN",
"geartype": "DRIFTING_LONGLINES",
"hours": 588.8797222222233,
"imo": "",
"lastTransmissionDate": "2025-01-20T10:17:21Z",
"mmsi": "431100690",
"shipName": "SENSHU MARU NO.3",
"vesselId": "b1dad8628-8c9c-2ee7-258b-3d8fb747f1c8",
"vesselType": "FISHING"
}
]
}
]
}What we've learned from Step 1: Kwame now has apparent fishing effort data, with a potential vessel operating as a longliner in Ghana's EEZ.
You can filter fishing effort or other data by gear type. For more details, check our data caveats and the 4Wings API documentation for the supported gear types.
Step 2: Retrieve Vessel ID for Longliner
Kwame refines his 4Wings API request to group by vessel ID, filtering only for longliners.
Endpoint: /v3/4wings/report
Filters used:
- Region ID = Ghana EEZ
- Gear Type = Drifting Longliner
- Group by = Vessel ID
- Date Range = Last 12 Months
Why use group-by=VESSEL_ID?
Grouping by VESSEL_ID allows individual vessel identification in the response. This is crucial for tracking vessel activity and, more importantly, linking each detected vessel to the Vessels API in the next step. By structuring the query this way, we can fetch vessel details such as flag, name, and ownership records in Step 3 below.
API Parameters:
spatial-resolution(e.g.,HIGH,LOW)temporal-resolution(e.g.,ENTIRE,MONTHLY,YEARLY)- For additional parameters, please refer to the 4Wings API documentation.
API Request: POST
# Make sure to replace [TOKEN] with your API Access Token.
curl --location --globoff 'https://gateway.api.globalfishingwatch.org/v3/4wings/report?format=JSON&datasets[0]=public-global-fishing-effort%3Alatest&temporal-resolution=ENTIRE&spatial-resolution=LOW&spatial-aggregation=true&group-by=VESSEL_ID&date-range=2024-01-01%2C2025-01-01&filters[0]=geartype%20in%20(%27drifting_longlines%27)' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [TOKEN]' \
--data '{
"region": {
"dataset": "public-eez-areas",
"id": 8400
}
}'result = await gfw_client.fourwings.create_report(
datasets=["public-global-fishing-effort:latest"],
spatial_resolution="LOW",
temporal_resolution="ENTIRE",
group_by="VESSEL_ID",
spatial_aggregation=True,
start_date="2024-01-01",
end_date="2025-01-01",
filters=["geartype in ('drifting_longlines')"],
region={"dataset": "public-eez-areas", "id": 8400},
)gfw_ais_fishing_hours(
spatial_resolution = "LOW",
temporal_resolution = "ENTIRE",
start_date = "2024-01-01",
end_date = "2025-01-01",
region_source = "EEZ",
region = 8400,
group_by = "VESSEL_ID",
filter_by = "geartype in ('drifting_longlines')"
)// Make sure to replace [TOKEN] with your API Access Token.
const res = await fetch(
'https://gateway.api.globalfishingwatch.org/v3/4wings/report?format=JSON&datasets[0]=public-global-fishing-effort%3Alatest&temporal-resolution=ENTIRE&spatial-resolution=LOW&spatial-aggregation=true&group-by=VESSEL_ID&date-range=2024-01-01%2C2025-01-01&filters[0]=geartype%20in%20(%27drifting_longlines%27)',
{
method: 'POST',
headers: {
Authorization: 'Bearer [TOKEN]',
'Content-Type': 'application/json',
},
body: JSON.stringify({
region: {
dataset: 'public-eez-areas',
id: 8400,
},
}),
}
)
const data = await res.json()Example API Response:
{
"entries": [
{
"public-global-fishing-effort:v3.0": [
{
"callsign": "",
"dataset": "public-global-vessel-identity:v3.0",
"date": "2024-01-01,2025-01-01",
"entryTimestamp": "2024-04-12T08:00:00Z",
"exitTimestamp": "2024-04-17T05:00:00Z",
"firstTransmissionDate": "2014-02-21T02:59:18Z",
"flag": "CHN",
"geartype": "DRIFTING_LONGLINES",
"hours": 2.750555555555555,
"imo": "",
"lastTransmissionDate": "2025-02-18T23:32:07Z",
"mmsi": "412331032",
"shipName": "",
"vesselId": "f37ebdc1b-be44-0740-7904-49397360e29d",
"vesselType": "FISHING"
}
]
}
]
}What we've learned from Step 2
- Kwame identifies two vessels operating as longliners within Ghana's EEZ.
- The vessel SENSHU MARU NO.3 shows significant activity with 588.88 hours logged.
- Another vessel potentially (MMSI: 412331032) shows apparent fishing effort over a short duration.
- This response is based on AIS self-reported data and should be further validated.
Step 3: Retrieve Vessel Details
Kwame queries the Vessels API to get detailed vessel identity and ownership records.
Endpoint: /v3/vessels/{vessel_id}
Filters used:
- vessel id from 4Wings API
- dataset =
public-global-vessel-identity:latest - includes =
POTENTIAL_RELATED_SELF_REPORTED_INFO— Vessels may change identifiers over time, such as their MMSI, IMO number, call sign, or even their name. This parameter helps users group all vessel ids that are potentially related as part of the same physical vessel based on publicly available registry information.
IMPORTANT: To avoid any misinterpretation of Global Fishing Watch data, please refer to our data caveats for Apparent Fishing Effort, Region source, Vessel ID, and Vessel identity data.
API Request: GET
# Make sure to replace [TOKEN] with your API Access Token.
curl --location --globoff 'https://gateway.api.globalfishingwatch.org/v3/vessels?datasets[0]=public-global-vessel-identity%3Alatest&ids[0]=f37ebdc1b-be44-0740-7904-49397360e29d&includes[0]=POTENTIAL_RELATED_SELF_REPORTED_INFO' \
--header 'Authorization: Bearer [TOKEN]'result = await gfw_client.vessels.get_vessels_by_ids(
ids=["f37ebdc1b-be44-0740-7904-49397360e29d"],
datasets=["public-global-vessel-identity:latest"],
includes=["POTENTIAL_RELATED_SELF_REPORTED_INFO"],
)gfw_vessel_info(
search_type = "id",
ids = c("f37ebdc1b-be44-0740-7904-49397360e29d"),
includes = "POTENTIAL_RELATED_SELF_REPORTED_INFO"
)// Make sure to replace [TOKEN] with your API Access Token.
const res = await fetch(
'https://gateway.api.globalfishingwatch.org/v3/vessels?datasets[0]=public-global-vessel-identity%3Alatest&ids[0]=f37ebdc1b-be44-0740-7904-49397360e29d&includes[0]=POTENTIAL_RELATED_SELF_REPORTED_INFO',
{ headers: { Authorization: 'Bearer [TOKEN]' } }
)
const data = await res.json()Example API Response:
{
"entries": [
{
"registryInfoTotalRecords": 0,
"registryInfo": [],
"registryOwners": [],
"registryPublicAuthorizations": [],
"combinedSourcesInfo": [
{
"vesselId": "f37ebdc1b-be44-0740-7904-49397360e29d",
"geartypes": [
{
"name": "DRIFTING_LONGLINES",
"source": "COMBINATION_OF_REGISTRY_AND_AIS_INFERRED_NN_INFO",
"yearFrom": 2014,
"yearTo": 2025
}
],
"shiptypes": [
{
"name": "FISHING",
"source": "COMBINATION_OF_REGISTRY_AND_AIS_INFERRED_NN_INFO",
"yearFrom": 2014,
"yearTo": 2025
}
]
}
],
"selfReportedInfo": [
{
"id": "f37ebdc1b-be44-0740-7904-49397360e29d",
"ssvid": "412331032",
"shipname": null,
"nShipname": null,
"flag": "CHN",
"callsign": null,
"imo": null,
"messagesCounter": 27862,
"positionsCounter": 27859,
"sourceCode": ["AIS"],
"matchFields": "NO_MATCH",
"transmissionDateFrom": "2014-02-21T02:59:18Z",
"transmissionDateTo": "2025-02-18T23:32:07Z"
}
],
"dataset": "public-global-vessel-identity:v3.0"
}
]
}What we've learned from Step 3
- The vessel MMSI: 412331032 appears to be a drifting longliner flagged under China.
- No public registry data is found for this vessel.
- The vessel's identity information is based on AIS self-reported data, which may not always align with official registries.
- The vessel appears to have been active since 2014, based on self-reported AIS records.
- This vessel's data needs further validation against official public sources.
Understanding the response objects
- registryInfoTotalRecords — No official registry records were found for this vessel.
- registryInfo — Empty, potentially indicating no data from public registries.
- registryOwners — No known ownership records found in public datasets.
- registryPublicAuthorizations — No known authorizations were found.
- combinedSourcesInfo — Provides inferred data based on AIS and other data sources.
- selfReportedInfo — The vessel's self-reported flag, identity, and activity timestamps.
Step 4: Detect Fleet Activity (Port Visits)
Now that Kwame has identified vessels in the fleet, he examines their activity further by querying the Events API. This allows him to detect port visits, encounters (potential transshipment) and apparent fishing activity based on vessel movement patterns.
Endpoint: /v3/events
Filters used:
- Vessel ID from 4Wings API (multiple vessels in the fleet)
- Event Types = PORT_VISIT, ENCOUNTER, FISHING. To obtain other event types, please visit the Events API documentation.
- Time Range = Last 6 months.
- encounter-types = FISHING-FISHING.
- Datasets:
public-global-port-visits-events:latest(Port Visits)public-global-encounters-events:latest(Encounters between vessels)public-global-fishing-events:latest(Fishing activity)
API Request: GET
# Make sure to replace [TOKEN] with your API Access Token.
curl --location --globoff 'https://gateway.api.globalfishingwatch.org/v3/events?vessels[0]=f37ebdc1b-be44-0740-7904-49397360e29d&vessels[1]=b1dad8628-8c9c-2ee7-258b-3d8fb747f1c8&vessels[2]=60f7bb972-2c90-4553-650b-23c38f9521bf&encounter-types[0]=FISHING-FISHING&sort=-start&start-date=2024-08-01&end-date=2025-01-31&limit=200&offset=0&datasets[0]=public-global-encounters-events%3Alatest&datasets[1]=public-global-fishing-events%3Alatest&datasets[2]=public-global-port-visits-events%3Alatest&include-regions=false&types[0]=ENCOUNTER&types[1]=FISHING&types[2]=PORT_VISIT' \
--header 'Authorization: Bearer [TOKEN]'result = await gfw_client.events.get_all_events(
datasets=[
"public-global-encounters-events:latest",
"public-global-fishing-events:latest",
"public-global-port-visits-events:latest",
],
vessels=[
"f37ebdc1b-be44-0740-7904-49397360e29d",
"b1dad8628-8c9c-2ee7-258b-3d8fb747f1c8",
"60f7bb972-2c90-4553-650b-23c38f9521bf",
],
types=["ENCOUNTER", "FISHING", "PORT_VISIT"],
encounter_types=["FISHING-FISHING"],
start_date="2024-08-01",
end_date="2025-01-31",
sort="-start",
limit=200,
offset=0,
)gfw_event(
event_type = c("ENCOUNTER", "FISHING", "PORT_VISIT"),
vessels = c(
"f37ebdc1b-be44-0740-7904-49397360e29d",
"b1dad8628-8c9c-2ee7-258b-3d8fb747f1c8",
"60f7bb972-2c90-4553-650b-23c38f9521bf"
),
encounter_types = "FISHING-FISHING",
start_date = "2024-08-01",
end_date = "2025-01-31",
sort = "-start"
)// Make sure to replace [TOKEN] with your API Access Token.
const res = await fetch(
'https://gateway.api.globalfishingwatch.org/v3/events?vessels[0]=f37ebdc1b-be44-0740-7904-49397360e29d&vessels[1]=b1dad8628-8c9c-2ee7-258b-3d8fb747f1c8&vessels[2]=60f7bb972-2c90-4553-650b-23c38f9521bf&encounter-types[0]=FISHING-FISHING&sort=-start&start-date=2024-08-01&end-date=2025-01-31&limit=200&offset=0&datasets[0]=public-global-encounters-events%3Alatest&datasets[1]=public-global-fishing-events%3Alatest&datasets[2]=public-global-port-visits-events%3Alatest&include-regions=false&types[0]=ENCOUNTER&types[1]=FISHING&types[2]=PORT_VISIT',
{ headers: { Authorization: 'Bearer [TOKEN]' } }
)
const data = await res.json()Example API Response:
{
"metadata": {
"datasets": [
"public-global-encounters-events:v3.0",
"public-global-fishing-events:v3.0",
"public-global-port-visits-events:v3.1"
],
"vessels": [
"f37ebdc1b-be44-0740-7904-49397360e29d",
"b1dad8628-8c9c-2ee7-258b-3d8fb747f1c8",
"60f7bb972-2c90-4553-650b-23c38f9521bf"
],
"dateRange": {
"from": "2024-08-01",
"to": "2025-01-31"
},
"encounterTypes": ["FISHING-FISHING"]
},
"limit": 200,
"offset": 0,
"nextOffset": null,
"total": 0,
"entries": []
}Response objects
- metadata — Specifies the datasets queried, vessel IDs, date range, and event types.
- limit — Maximum number of results returned per request.
- total — Number of events found matching the criteria.
- entries — List of detected events (empty in this case, meaning no matching encounters, port visits, or fishing events were found).
What we've learned from Step 4
No recorded port visits, encounters, or fishing events were found for the queried vessels in the given date range. This could mean:
- The vessels have not been engaged in these activities recently.
- Some events were missed due to AIS data coverage gaps.
- Different filters may need to be applied to refine results.
Caveats & Considerations
- 🚨 A lack of recorded encounters or port visits does not confirm the absence of such activities — AIS coverage, reporting behavior, and dataset updates can impact results.
- 🚨 Further investigation may be required, including manual validation using historical data or consulting additional sources.
Summary of the API Flow
- 4Wings API — Identify fishing effort by gear type in Ghana's EEZ.
- 4Wings API — Retrieve vessel IDs for potential longliners.
- Vessels API — Fetch detailed vessel identity & ownership.
- Events API — Attempt to detect fleet activity (port visits, encounters, and apparent fishing events).