Home → Blog

You need a reliable way to programmatically check port congestion for Port Klang so your transportation planning can account for berth availability and flow-through risk. By the end of this guide, you’ll be able to query the FreightPulse API for Port Klang (MYPKG), parse the lagged IMF PortWatch congestion signal in Python, and ship it to production with sensible caching and monitoring.

What this API returns and what it does not

The FreightPulse port congestion signal for Port Klang is derived from IMF PortWatch (UN Global Platform AIS data), updated daily but lagged by roughly 6–7 days. It measures the last 7 days’ average port calls compared to a 90-day baseline for the same port and classifies congestion qualitatively (e.g., low, moderate, high). It does not provide live AIS vessel wait times or anchorage delays.

Illustration: API to Check Congestion at Port Klang

Important constraints for transportation workflows:

Endpoint, method, authentication, and rate limits

Endpoint:

Port code:

Authentication:

Documentation and onboarding:

Quickstart: run the cURL for Port Klang

Copy-paste the following to fetch Port Klang congestion. It uses the documented header and port code.

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

Official sample JSON response for Port Klang (copy of the live example):

{
"success": true,
"data": {
"results": [
{
"port": "Port Klang",
"locode": "MY PKG",
"country": "Malaysia",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 33.3,
"baseline_avg_portcalls_per_day": 31.8,
"ratio_vs_baseline": 1.05
}
},
{
"port": "Pelabuhan Sungai Udang",
"locode": "MY PKG",
"country": "Malaysia",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 2,
"baseline_avg_portcalls_per_day": 1.9,
"ratio_vs_baseline": 1.07
}
}
],
"global_summary": {
"ports_high_congestion": 0,
"ports_moderate": 2,
"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": "a94e3560-4f62-4631-acfb-9d608229a913"
}
}

Field highlights you’ll actually use:

Python integration: fetch, parse, and normalize Port Klang

The snippet below calls the same endpoint, validates the success envelope, extracts Port Klang’s congestion, ratio_vs_baseline, and as_of, and emits a compact record suitable for your transportation ops pipeline.

import os
import requests
from datetime import datetime, timezone

API_URL = "https://freightpulsehq.com/api/v1/port-congestion"
PORT_CODE = "MYPKG"

def fetch_port_klang_congestion(api_key: str) -> dict:
headers = {"X-API-Key": api_key} if api_key else {}
params = {"port": PORT_CODE}
resp = requests.get(API_URL, headers=headers, params=params, timeout=20)
resp.raise_for_status()
payload = resp.json()

# Validate envelope
if not isinstance(payload, dict) or not payload.get("success"):
raise RuntimeError("Unexpected response envelope or success flag false")

data = payload.get("data", {})
results = data.get("results", [])
if not results:
raise RuntimeError("No results returned for Port Klang (MYPKG)")

# Prefer the record whose 'port' equals 'Port Klang'
record = None
for item in results:
if item.get("port") == "Port Klang":
record = item
break
if record is None:
# Fall back to the first record if specific port match is not present
record = results[0]

metrics = record.get("metrics", {})
congestion = record.get("congestion")
ratio = metrics.get("ratio_vs_baseline")
as_of = record.get("as_of")

if congestion is None or ratio is None or as_of is None:
raise RuntimeError("Missing required fields: congestion, ratio_vs_baseline, or as_of")

# Normalize date to ISO date (assumed UTC day)
try:
as_of_date = datetime.strptime(as_of, "%Y-%m-%d").date().isoformat()
except Exception as e:
raise RuntimeError(f"Invalid as_of date format: {as_of}") from e

# Return a compact transport-facing record
return {
"port_code": PORT_CODE,
"port_name": record.get("port"),
"country": record.get("country"),
"congestion_level": congestion,
"ratio_vs_baseline": ratio,
"recent_avg_portcalls_per_day": metrics.get("recent_avg_portcalls_per_day"),
"baseline_avg_portcalls_per_day": metrics.get("baseline_avg_portcalls_per_day"),
"as_of": as_of_date,
"source": data.get("meta", {}).get("source"),
"data_lag_days": data.get("meta", {}).get("data_lag_days")
}

if __name__ == "__main__":
api_key = os.getenv("FREIGHTPULSE_API_KEY", "")
result = fetch_port_klang_congestion(api_key)
print(result)

Notes for transportation deployments:

Data model and field semantics for transportation planning

FreightPulse wraps responses in an envelope: success (boolean), data (object), and sometimes meta (request metadata). Your planner likely needs a single congestion signal (categorical) and a numeric confirmatory signal (ratio_vs_baseline) to drive alerting and routing heuristics.

FreightPulse meta explains methodology and lag explicitly. Ensure dispatchers and schedulers understand it is not a live vessel-wait metric and should be combined with tactical sources if your SOP requires real-time anchorage conditions.

Caching, staleness, and operations

Because the dataset updates daily and is lagged ~6–7 days, an hourly polling cadence is unnecessary. A 12–24 hour refresh is usually sufficient for transportation planning that revises port calls daily or intra-day only when thresholds breach.

Transport calendars and weekends: since the source is daily and not tied to exchange trading days, expect updates on weekends but continue to treat as lagged. Use the as_of date rather than system time to anchor your operational decisions.

Validation tests with canonical JSON examples

The following blocks are complete JSON response examples you can paste into unit tests or contract tests. They are the official Port Klang sample repeated to verify parsing, envelope validation, and field extraction across code paths (e.g., selecting the Port Klang record among multiple results).

Example 1: Baseline parsing of Port Klang congestion

{
"success": true,
"data": {
"results": [
{
"port": "Port Klang",
"locode": "MY PKG",
"country": "Malaysia",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 33.3,
"baseline_avg_portcalls_per_day": 31.8,
"ratio_vs_baseline": 1.05
}
},
{
"port": "Pelabuhan Sungai Udang",
"locode": "MY PKG",
"country": "Malaysia",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 2,
"baseline_avg_portcalls_per_day": 1.9,
"ratio_vs_baseline": 1.07
}
}
],
"global_summary": {
"ports_high_congestion": 0,
"ports_moderate": 2,
"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": "a94e3560-4f62-4631-acfb-9d608229a913"
}
}

Example 2: Selecting the specific Port Klang record when multiple results exist

{
"success": true,
"data": {
"results": [
{
"port": "Port Klang",
"locode": "MY PKG",
"country": "Malaysia",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 33.3,
"baseline_avg_portcalls_per_day": 31.8,
"ratio_vs_baseline": 1.05
}
},
{
"port": "Pelabuhan Sungai Udang",
"locode": "MY PKG",
"country": "Malaysia",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 2,
"baseline_avg_portcalls_per_day": 1.9,
"ratio_vs_baseline": 1.07
}
}
],
"global_summary": {
"ports_high_congestion": 0,
"ports_moderate": 2,
"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": "a94e3560-4f62-4631-acfb-9d608229a913"
}
}

Example 3: Contract test for envelope and meta presence

{
"success": true,
"data": {
"results": [
{
"port": "Port Klang",
"locode": "MY PKG",
"country": "Malaysia",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 33.3,
"baseline_avg_portcalls_per_day": 31.8,
"ratio_vs_baseline": 1.05
}
},
{
"port": "Pelabuhan Sungai Udang",
"locode": "MY PKG",
"country": "Malaysia",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 2,
"baseline_avg_portcalls_per_day": 1.9,
"ratio_vs_baseline": 1.07
}
}
],
"global_summary": {
"ports_high_congestion": 0,
"ports_moderate": 2,
"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": "a94e3560-4f62-4631-acfb-9d608229a913"
}
}

Use these fixtures to:

FAQ

Is this a live AIS wait time or queue length metric?
No. It is based on IMF PortWatch and reflects the last 7 days’ average port calls vs a 90-day baseline. It is lagged ~6–7 days and is updated daily. It does not measure vessel wait or anchorage time.

What is the authentication method?
Pass your API key in the X-API-Key header. Without a key, guests are limited to 100 requests per day per IP.

What fields should I store for Port Klang?
At minimum: congestion, metrics.ratio_vs_baseline, as_of, and the source/meta block to capture methodology and lag information. Optionally store recent_avg_portcalls_per_day and baseline_avg_portcalls_per_day for context.

How often should I poll?
Daily is typical. Because data is lagged, a 12–24 hour refresh interval with caching is recommended for transportation planning.

Can I use this to quote a freight rate or a “today” price?
Do not use this congestion signal to quote freight rates or assert today’s live conditions. It is not a fare or a real-time wait duration.

Ready to integrate Port Klang congestion into your transportation stack? Create an account to get an API key and start testing: Register. For full parameter and response details, see the Documentation.