Logistics teams moving containers through Tianjin Xin Gang often ask a specific, technical question: “How congested is the port right now relative to its normal operating baseline?” By the end of this guide, you will be able to query FreightPulse’s Transportation API for Tianjin’s congestion signal, understand how the 7-day average vs 90-day baseline is computed, and integrate the response into your scheduling, ETD/ETA buffers, or carrier allocation logic.
What the Tianjin congestion signal measures and when to use it
The FreightPulse port congestion endpoint for Tianjin Xin Gang provides a standardized congestion level derived from IMF PortWatch. It compares the last 7 days of port calls to a 90-day baseline for the same port. This is a lagged indicator (~6–7 days), updated daily as new AIS-derived aggregates are published. It is not a live vessel wait-time feed, and it does not measure anchorage queues in real time.
Use this signal when you need a consistent, time-series-quality indicator to inform transportation planning, weekly capacity reviews, or near-term risk flags. Do not use it as a live AIS or berth-occupancy proxy. For operations that require minute-by-minute anchorage status, treat this as a complementary macro signal rather than a substitute.
Endpoint overview: GET /api/v1/port-congestion
Endpoint:
- Method: GET
- URL: https://freightpulsehq.com/api/v1/port-congestion?port=Tianjin
- Auth: header X-API-Key: YOUR_API_KEY (guest access without a key is allowed with 100 requests/day per IP)
Core fields returned for Tianjin Xin Gang:
- congestion: categorical level (e.g., low, moderate, high), derived from recent vs baseline port calls
- as_of: the YYYY-MM-DD date for which the aggregated signal is valid (lagged ~6–7 days)
- metrics.ratio_vs_baseline: numeric ratio of the 7-day average to the 90-day baseline (1.0 ≈ normal)
- metrics.recent_avg_portcalls_per_day: recent 7-day average port calls
- metrics.baseline_avg_portcalls_per_day: 90-day baseline port calls
Envelope:
- success: boolean
- data.results: array of per-port entries
- data.global_summary: global rollup counts by congestion category
- data.meta: methodology, data lag, and source notes
ORIGIN CATALOG FACTS (authoritative quick-reference)
- Auth: header X-API-Key: YOUR_API_KEY. Guest without key: 100 requests/day per IP.
- Envelope: {"success":true,"data":{...}}
- Port congestion is IMF PortWatch, lagged ~6-7 days, 7-day avg vs 90-day baseline — not live AIS.
- Do not quote a freight-rates USD fare as today’s price.
- Port: Tianjin Xin Gang (Tianjin)
- curl: curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/port-congestion?port=Tianjin"
- No official congestion JSON is published for Tianjin. Show the curl and field names (congestion, ratio_vs_baseline, as_of). Do not reuse the USLAX 0.85 fixture.
Quickstart: cURL request you can paste into a terminal
Authenticate with an API key in the X-API-Key header. Guests may omit the header, but are limited to 100 requests/day per IP. Replace YOUR_API_KEY with your key if you have one.
curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/port-congestion?port=Tianjin"
Notes:
- Only the port parameter is required here; for this guide we’re querying Tianjin Xin Gang via "Tianjin".
- The response envelope is JSON with success and data fields; parse data.results[0] for Tianjin-specific metrics.
Official JSON example and how to read it
Below is the official sample response for Tianjin. Copy it into your test fixtures if needed. Remember this is a lagged macro signal, not live AIS wait times.
{
"success": true,
"data": {
"results": [
{
"port": "Tianjin Xin Gang",
"locode": null,
"country": "China",
"congestion": "moderate",
"as_of": "2026-09-25",
"metrics": {
"recent_avg_portcalls_per_day": 29.9,
"baseline_avg_portcalls_per_day": 29.7,
"ratio_vs_baseline": 1
}
}
],
"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": "b0502b4e-0227-41b5-a502-6e3555496584"
}
}
What you will actually use in code:
- data.results[0].congestion: the categorical level you can map to color or thresholds in a dashboard.
- data.results[0].as_of: the ISO date for the estimate; be explicit that this is lagged.
- data.results[0].metrics.ratio_vs_baseline: a dimensionless ratio; values near 1 ≈ normal workload.
- data.results[0].metrics.recent_avg_portcalls_per_day and baseline_avg_portcalls_per_day: raw counts per day to support custom thresholds or QA.
JavaScript example: fetch Tianjin congestion and normalize for planning
This example queries the endpoint, extracts Tianjin’s congestion, and converts the ratio_vs_baseline into a simple numeric score you can plug into a scheduling buffer rule. Keep the X-API-Key header as shown.
async function fetchTianjinCongestion() {
const url = "https://freightpulsehq.com/api/v1/port-congestion?port=Tianjin";
const res = await fetch(url, {
headers: {
"X-API-Key": "YOUR_API_KEY"
}
});
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
const json = await res.json();
if (!json.success || !json.data || !Array.isArray(json.data.results) || json.data.results.length === 0) {
throw new Error("Malformed response");
}
const tianjin = json.data.results[0];
const level = tianjin.congestion; // "low" | "moderate" | "high" (categorical)
const asOf = tianjin.as_of; // "YYYY-MM-DD", lagged ~6-7 days
const ratio = tianjin.metrics?.ratio_vs_baseline; // number (dimensionless)
// Example: map congestion to a buffer multiplier for schedules (illustrative only)
const bufferByLevel = { low: 1.00, moderate: 1.05, high: 1.12 };
const multiplier = bufferByLevel[level] ?? 1.00;
return {
port: tianjin.port,
asOf,
level,
ratio,
recentAvg: tianjin.metrics?.recent_avg_portcalls_per_day,
baselineAvg: tianjin.metrics?.baseline_avg_portcalls_per_day,
planningBufferMultiplier: multiplier
};
}
// Usage
fetchTianjinCongestion()
.then(data => {
console.log("Tianjin congestion snapshot:", data);
})
.catch(err => {
console.error("Failed to load Tianjin congestion:", err);
});
Implementation notes:
- ratio_vs_baseline is dimensionless and compares 7-day average to the 90-day mean. Treat 1.0 as normal. Values above 1 indicate relatively higher recent traffic; below 1 indicate relatively lower.
- as_of is a date, not a timestamp; plan your caches around daily refresh cadence rather than hourly polling.
- If you build automated alerts, combine the categorical congestion with the ratio to avoid overreacting to small deviations near 1.0.
Operational guidance: cadence, caching, and integration boundaries
Update cadence and lag:
- Data lag is approximately 6–7 days from the as_of date to the present; the dataset updates daily as IMF PortWatch refreshes.
- Do not equate this to berth or anchorage wait times; it does not report queue duration or live AIS trajectories.
Caching and polling:
- Cache per port at least for several hours, often safely for one day. Align cache invalidation with your daily ETL window.
- If you need historical tracking, persist data.results snapshots keyed by as_of to ensure time-series continuity.
Error handling and envelopes:
- Always check success === true and validate data.results is a non-empty array before accessing fields.
- When success is false or results is empty, fall back to your last known good reading and flag the record as stale.
Units and formats:
- recent_avg_portcalls_per_day and baseline_avg_portcalls_per_day are counts per day (number of port calls), not durations or percentages.
- ratio_vs_baseline is a numeric ratio. Avoid formatting as a percentage unless you apply a 100x transform explicitly in your UI.
- as_of is in YYYY-MM-DD; treat it as local-agnostic. If you timestamp your ingestion, store both the provider date and your UTC ingestion time.
Building production checks for Tianjin integration
1) Schema and content validation
- Confirm the presence of data.results[0].congestion, .as_of, and .metrics.ratio_vs_baseline.
- Ensure ratio_vs_baseline is a finite number and not NaN or null before use in arithmetic.
2) Thresholding and alerting
- Define stable alert thresholds tied to ratio_vs_baseline, e.g., >= 1.15 (higher-than-normal) or <= 0.85 (lower-than-normal), and debounce across multiple days to avoid flapping.
- Overlay the categorical congestion with your thresholds for redundancy.
3) Display and UX
- Show the as_of date prominently to set expectations about the lagged nature of the data.
- Provide a tooltip that cites IMF PortWatch as the source and clarifies it is not live AIS queue time.
End-to-end workflow example for transportation planning
- Daily at 02:00 UTC, call GET /api/v1/port-congestion?port=Tianjin, parse congestion, ratio_vs_baseline, and as_of.
- Store the record in your planning database alongside upcoming vessel calls or bookings tagged for Tianjin Xin Gang.
- Apply a buffer rule to ETAs for Tianjin-destined moves when congestion is moderate or high; for example, add a conservative buffer when ratio_vs_baseline drifts materially above 1.0, but keep the rule transparent since the signal is macro-level.
- Render a dashboard tile that shows the categorical congestion, the ratio, and the difference between recent and baseline port calls to inform routing decisions.
Documentation and onboarding
For endpoint references and integration details, see the official docs and register for an API key:
FAQ
Is this a live anchorage or berth wait-time feed?
No. It is a lagged, daily-updated signal from IMF PortWatch that compares the last 7 days of port calls to a 90-day baseline. It is not live AIS wait-time data.
How often should I poll for Tianjin Xin Gang?
Once per day is typically sufficient because the underlying dataset updates daily and reflects data with a ~6–7 day lag.
What should I display to users?
Show congestion, ratio_vs_baseline, recent and baseline port calls, and the as_of date. Make it clear that the value is lagged and not a real-time queue length.
What happens if my request has no API key?
Guest access is allowed with 100 requests/day per IP. For higher volumes or multi-port coverage, include X-API-Key: YOUR_API_KEY in the header.
Do I need to handle pagination?
For a single-port query like Tianjin, parse data.results[0]. If you query multiple ports in one call, process the results array; the response format shows an envelope but does not require pagination parameters for the single-port use case documented here.
Get a working key and wire Tianjin Xin Gang’s congestion signal into your transportation planning today. Create your account on the Register page, then keep the docs open for field-by-field references at Documentation.