You’re planning sailings through Ningbo (CNNBO) and need a concrete, programmatic way to track port congestion so you can adjust booking windows, equipment positioning, or buffers. By the end of this guide you will be able to pull FreightPulse’s IMF PortWatch congestion signal for Ningbo, parse the key fields (congestion, ratio_vs_baseline, as_of), and wire basic alerts or dashboards into your stack.
What this dataset tells you about Ningbo congestion
FreightPulse’s port congestion feed for Ningbo (LOCODE CN NBO, often written as CNNBO in API params) is built from IMF PortWatch using UN Global Platform AIS data. It compares the recent 7-day average of port calls against the port’s own 90-day baseline. This is not a live AIS wait-time product and it does not report anchorage delays or queue lengths. Instead, it’s a stable, lagged indicator of activity that updates daily with approximately a 6–7 day delay.
That design makes the metric reliable for planning windows, trend detection, and capacity balancing where you don’t need minute-by-minute vessel positions but do need a consistent historical benchmark against which to judge whether activity is above or below normal.
How to query FreightPulse for Ningbo (CNNBO)
The congestion endpoint is a simple GET request with one required parameter, the port code:
- Method: GET
- Endpoint: https://freightpulsehq.com/api/v1/port-congestion
- Query parameter: port=CNNBO
- Authentication: send your API key in the X-API-Key header
- Guest usage: without a key, the service allows 100 requests per day per IP
Envelope shape is consistent: {"success": true, "data": {...}}. Inside data, you’ll find results (an array), a global_summary, and meta that describes the source and methodology.
Copy-paste cURL for Ningbo
Authentication uses an HTTP header. Replace YOUR_API_KEY with your key if you have one; otherwise, you can test as a guest subject to the daily IP limit.
curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/port-congestion?port=CNNBO"
Official JSON response example
The following is the official sample for Ningbo. Copy it as-is when building your parser or mock tests.
{
"success": true,
"data": {
"results": [
{
"port": "Ningbo",
"locode": "CN NBO",
"country": "China",
"congestion": "moderate",
"as_of": "2026-10-09",
"metrics": {
"recent_avg_portcalls_per_day": 47.6,
"baseline_avg_portcalls_per_day": 46.8,
"ratio_vs_baseline": 1.02
}
}
],
"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": "47ad5c93-5fef-469d-a27e-2826b7961c2b"
}
}
Fields you will actually use:
- data.results[0].congestion: a categorical label like low, moderate, high.
- data.results[0].as_of: the data date (YYYY-MM-DD). Updates daily but is lagged ~6–7 days from “today.”
- data.results[0].metrics.ratio_vs_baseline: the 7-day average port calls divided by the 90-day baseline. Values above 1.0 indicate above-baseline activity; below 1.0 indicates below-baseline.
- data.results[0].metrics.recent_avg_portcalls_per_day and baseline_avg_portcalls_per_day: the underlying port-call counts used to compute the ratio.
What the Ningbo signal means for planning
Because this metric is derived from port calls, a ratio_vs_baseline near 1.0 suggests activity is roughly normal for Ningbo. Deviations help you decide whether to add slack time or adjust bookings. For example, a sustained ratio of 1.15+ over several days may justify pulling forward cutoffs or rebalancing equipment to avoid bunching. Conversely, a lower ratio suggests less traffic relative to the port’s recent history.
The congestion label (low, moderate, high) is an abstraction of that ratio, helpful for user-facing dashboards. Keep the numeric ratio in your automations; use the label for quick-glance UIs.
End-to-end example in Python
This script queries the same endpoint shown in the cURL and extracts the congestion, ratio_vs_baseline, and as_of fields. It also demonstrates a simple guard against missing fields.
import os
import requests
API_URL = "https://freightpulsehq.com/api/v1/port-congestion"
PORT = "CNNBO" # Ningbo
API_KEY = os.getenv("FREIGHTPULSE_API_KEY", "YOUR_API_KEY") # replace or set env var
def fetch_ningbo_congestion():
resp = requests.get(
API_URL,
params={"port": PORT},
headers={"X-API-Key": API_KEY},
timeout=15
)
resp.raise_for_status()
payload = resp.json()
# Expect the envelope: {"success": true, "data": {...}}
if not payload.get("success"):
raise RuntimeError("API reported success=false")
data = payload.get("data", {})
results = data.get("results", [])
if not results:
raise ValueError("No results for CNNBO")
row = results[0]
congestion = row.get("congestion")
as_of = row.get("as_of")
metrics = row.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 {
"port": row.get("port"),
"locode": row.get("locode"),
"country": row.get("country"),
"as_of": as_of,
"congestion": congestion,
"ratio_vs_baseline": ratio,
"recent_avg_portcalls_per_day": recent,
"baseline_avg_portcalls_per_day": baseline,
"source": data.get("meta", {}).get("source"),
"data_lag_days": data.get("meta", {}).get("data_lag_days"),
}
if __name__ == "__main__":
info = fetch_ningbo_congestion()
print(
f"[Ningbo | {info['as_of']}] congestion={info['congestion']}, "
f"ratio_vs_baseline={info['ratio_vs_baseline']}, "
f"recent={info['recent_avg_portcalls_per_day']}, "
f"baseline={info['baseline_avg_portcalls_per_day']}"
)
Key implementation details that save time
- Authentication: Use the X-API-Key header with YOUR_API_KEY. Without a key, the API supports guest access up to 100 requests/day per IP, which is sufficient for local development and basic monitoring.
- Envelope: Responses use {"success": true, "data": {...}}; always check success before parsing data.results.
- Update cadence and lag: Data is updated daily but lagged by approximately 6–7 days. The as_of field indicates the data date, not necessarily “today.” If you run a daily ingestion, expect one new date per day per port.
- Units: The metrics are in port calls per day (floating-point averages). The ratio_vs_baseline is dimensionless.
- Caching: Since the data is not real-time and backfills daily, a 12–24 hour cache on your side avoids unnecessary requests. In production, many teams fetch once per day after their data window closes.
- Pagination: The example returns a single result for the requested port in data.results; no pagination parameters are shown for this endpoint.
- Error handling: Treat non-200 responses and success=false as retriable or alert-worthy. Keep a simple backoff. If results is empty, your job should log and retry later.
- Downstream normalization: Persist the as_of date alongside the values you compute (alerts, percent changes), so trend lines can be re-built deterministically.
Practical ways to operationalize Ningbo congestion
Most teams wire the ratio_vs_baseline into simple threshold rules and time-series dashboards. Below are compact patterns that are quick to implement and straightforward to reason about.
- Alerting thresholds: Start with soft alerts at 1.10 and hard alerts at 1.20 sustained for 3 consecutive data points (3 days). Require reversion below 1.05 to auto-clear.
- Buffer policies: Translate ratios into operational buffers. For example, when the ratio exceeds 1.15, add a 1–2 day buffer to time-sensitive exports that depend on berth windows. When the ratio is below 0.95 for a week, consider easing buffers to recover velocity.
- Dashboarding: Display congestion (categorical) in a badge and plot ratio_vs_baseline as a line. Keep recent_avg_portcalls_per_day and baseline_avg_portcalls_per_day as tooltips to explain movements to non-technical stakeholders.
- Exception handling: Flag days where the ratio jumps >0.10 day-over-day as anomalies to be reviewed by your network team, even if the absolute level remains “moderate.”
Simple rules for interpreting Ningbo’s fields
- congestion: Human-friendly label that maps from the ratio. Use it for quick indicators and traffic-light UIs.
- ratio_vs_baseline: Your primary automation metric because it is normalized for the port’s own behavior. Use it for alerts and performance targets.
- as_of: The effective data date. Schedule processing jobs using this date to avoid double-counting or missing days.
- recent_avg_portcalls_per_day vs baseline_avg_portcalls_per_day: Keep both to support diagnostics and stakeholder questions about what “1.02” actually means in real activity terms.
Implementation checklist
- Query the CNNBO endpoint daily after your chosen cutoff time.
- Validate the envelope and ensure results[0] exists before parsing.
- Store as_of, congestion, ratio_vs_baseline, recent_avg_portcalls_per_day, baseline_avg_portcalls_per_day.
- Compute and persist a 7-point rolling mean of ratio_vs_baseline for smoother visuals (optional; do not overwrite the raw signal).
- Cache responses for 24 hours in production to minimize calls; refresh after your daily ingestion completes.
- Instrument logs with the request_id found in the top-level meta for support traceability.
Troubleshooting and edge cases
If your request succeeds but results is empty, retry later; data can be temporarily unavailable during upstream refresh. If success=false, treat as a transient condition and back off. If you query without a key and hit the 100 requests/day/IP threshold, you will need to add the X-API-Key header with YOUR_API_KEY to continue. Because the dataset is lagged, do not compare the as_of date to “today” to determine freshness; compare it to the prior as_of you ingested.
Also, remember that this is not a wait-time data product: increased port calls can correlate with congestion, but the metric does not measure vessel queues or time-at-anchor. Keep any SLA commitments framed in terms of activity-relative-to-baseline, not live anchorage durations.
Security and deployment notes
- Do not embed YOUR_API_KEY in client-side code. Terminate API calls on your server or in a job runner.
- Use environment variables for the key in CI/CD. In local development, default to YOUR_API_KEY and rely on the guest 100 requests/day/IP limit until you are ready to wire secrets.
- Log and rotate request_ids for incident reports. Avoid logging payloads in high-volume jobs; capture only fields you need.
FAQ
Is this live AIS congestion?
No. The feed uses IMF PortWatch, updated daily with a ~6–7 day lag. It compares the last 7 days’ average port calls to a 90-day baseline. It does not report live vessel wait times or anchorage queues.
What is the exact port identifier I should pass?
Use port=CNNBO in the query. The response includes locode "CN NBO" and port "Ningbo" for reference.
How should I handle authentication?
Send the API key via the X-API-Key header. Without a key, you can make up to 100 requests per day per IP as a guest.
How often should I poll?
Once per day is typical. The dataset is lagged and updates daily, so more frequent polling does not provide fresher values.
Which fields should I store?
At minimum: as_of, congestion, ratio_vs_baseline. For diagnostics and context, also store recent_avg_portcalls_per_day and baseline_avg_portcalls_per_day.
Ready to wire Ningbo congestion into your planning flow? Create your API key and start integrating today: Register. For endpoint specifics and schema references, see the Documentation.