Home → Blog

Your team needs a reliable way to check container congestion at Guangzhou (Nansha) without building an AIS pipeline. By the end of this guide you’ll query the FreightPulse Transportation API for CNGGZ, read congestion levels derived from IMF PortWatch (lagged ~6–7 days), and integrate it into a Python workflow that caches and alerts on changes.

What the congestion API returns for Guangzhou (Nansha) (CNGGZ)

The endpoint provides a JSON envelope with a success flag and a data object. For Guangzhou (Nansha), you’ll read these fields from the first result:

Illustration: API to Check Congestion at Guangzhou (Nansha)

Key facts before you integrate:

Quick start: cURL

Use the documented GET endpoint with the port code. Include the API key header exactly as shown.

curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/port-congestion?port=CNGGZ"

Python integration: fetch, parse, and interpret congestion

The following Python example calls the same endpoint, validates the success envelope, reads congestion, ratio_vs_baseline, and as_of, and prints a concise summary you can plug into alerts or dashboards.

import os
import sys
import time
import json
from typing import Optional

import requests

API_URL = "https://freightpulsehq.com/api/v1/port-congestion"
PORT_CODE = "CNGGZ"
API_KEY = os.getenv("FREIGHTPULSE_API_KEY", "YOUR_API_KEY")

def fetch_congestion(port: str) -> dict:
headers = {"X-API-Key": API_KEY}
params = {"port": port}
resp = requests.get(API_URL, headers=headers, params=params, timeout=20)
resp.raise_for_status()
payload = resp.json()
if not isinstance(payload, dict) or not payload.get("success"):
raise ValueError("API did not return success=true")
data = payload.get("data") or {}
results = data.get("results") or []
if not results:
raise ValueError(f"No congestion results for port={port}")
return results[0], data, payload.get("meta")

def summarize(result: dict) -> str:
port_name = result.get("port")
locode = result.get("locode")
as_of = result.get("as_of")
congestion = result.get("congestion")
metrics = result.get("metrics") or {}
ratio = metrics.get("ratio_vs_baseline")
recent = metrics.get("recent_avg_portcalls_per_day")
baseline = metrics.get("baseline_avg_portcalls_per_day")

return (
f"Port: {port_name} ({locode})\n"
f"As of: {as_of} (IMF PortWatch, ~6–7 day lag)\n"
f"Congestion: {congestion}\n"
f"7d avg port calls: {recent} vs 90d baseline: {baseline}\n"
f"Ratio vs baseline: {ratio}"
)

def main():
try:
result, data, meta = fetch_congestion(PORT_CODE)
print(summarize(result))
except requests.HTTPError as e:
print(f"HTTP error: {e}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)

if __name__ == "__main__":
# Simple retry wrapper for transient network issues
for attempt in range(3):
try:
main()
break
except SystemExit as e:
if attempt == 2:
raise
time.sleep(2 ** (attempt + 1))

Notes:

Official sample response for Guangzhou (Nansha)

Below is the official sample you can use to wire up your parser and tests.

{
"success": true,
"data": {
"results": [
{
"port": "Guangzhou (Nansha)",
"locode": "CN GGZ",
"country": "China",
"congestion": "moderate",
"as_of": "2026-10-09",
"metrics": {
"recent_avg_portcalls_per_day": 28,
"baseline_avg_portcalls_per_day": 27.6,
"ratio_vs_baseline": 1.01
}
}
],
"global_summary": {
"ports_high_congestion": 0,
"ports_moderate": 1,
"ports_low": 0
},
"meta": {
"source": "IMF PortWatch (portwatch.imf.org) - UN Global Platform AIS data",
"data_lag_days": "~6-7 (daily updates, not real-time)",
"methodology": "congestion level is an approximation: last 7 days' avg port calls vs 90-day baseline for the same port. Does not measure vessel wait/anchorage time."
}
},
"meta": {
"request_id": "13e05e18-f6f9-4238-99db-44211c2a6159"
}
}

Field highlights you will actually use:

Operational guidance for transportation teams

Because the series is lagged ~6–7 days, use it for planning and network steering rather than “vessel at anchor now” decisions. If you need point-in-time anchorage or berth wait times, you would need a separate AIS stream; this endpoint intentionally focuses on IMF PortWatch aggregates.

Auth, quotas, and envelopes

Authentication is via an HTTP header and a daily guest limit.

For full parameter and schema references, see the Documentation.

Error handling and resiliency

Embedding CNGGZ congestion into transportation workflows

Common patterns for Guangzhou (Nansha):

FAQs

Is this live AIS wait-time data?
No. It is IMF PortWatch aggregates lagged roughly 6–7 days. It compares the recent 7-day average port calls against a 90-day baseline and does not measure anchorage/berth wait times.

What timezone are the dates in?
as_of is a calendar date (YYYY-MM-DD) for the dataset’s reporting day. Treat it as a date without a timezone and cache by that value.

How often should I poll the endpoint?
Daily is sufficient. The underlying data updates daily with a ~6–7 day lag; intra-day polling will not add fresher signal.

Can I combine this with spot freight rates?
Yes, but keep them separate in your UI. Do not present a spot USD rate as “today’s” price using this endpoint—this endpoint provides congestion signals only.

What happens if there are no results for CNGGZ?
Handle an empty results array gracefully and continue using the last cached as_of until the next daily refresh, with an expiration policy you control.

Ready to productionize your Guangzhou (Nansha) congestion checks? Create your key and start integrating today: Register.