Hong Kong Port Throughput Scraper: Container & Cargo avatar

Hong Kong Port Throughput Scraper: Container & Cargo

Pricing

from $1.20 / 1,000 throughput observation scrapeds

Go to Apify Store
Hong Kong Port Throughput Scraper: Container & Cargo

Hong Kong Port Throughput Scraper: Container & Cargo

Scrape Hong Kong's official monthly port container throughput, split by Kwai Tsing terminals vs mid-stream, direction and laden/empty, plus the companion seaborne and river cargo tonnage series.

Pricing

from $1.20 / 1,000 throughput observation scrapeds

Rating

0.0

(0)

Developer

Arman Hossain

Arman Hossain

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Hong Kong Port Throughput Scraper: Container, Seaborne & River Cargo

Hong Kong Port Throughput: Monthly container, seaborne and river cargo series with the year-on-year change already paired

Pulls Hong Kong's official monthly port statistics: container throughput split by Kwai Tsing terminals vs mid-stream handling, inward vs outward, and laden vs empty, plus the companion seaborne and river cargo tonnage series. The source publishes each level figure alongside its own year-on-year percentage change as two separate rows; this Actor pivots them back together so one dataset row carries both the physical figure and its year-on-year move.

The source is the Census and Statistics Department of the Hong Kong SAR, published as structured JSON. There's no browser, no proxy and no login required to use this Actor.

Agent skill: SKILL.md

https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/hong-kong-port-throughput-scraper.md

What you get

FieldWhat it holds
tableIdThe source table id, e.g. 410-55294
seriescontainer-throughput, seaborne-cargo, river-cargo, or a title-derived label for any other table id you pass in
tableTitleThe table's own title, in the language you requested
measureCodeThe source's internal measure code (e.g. PORT_CONTAINER_TP)
locationCode, locationKwai Tsing Container Terminals vs "other than Kwai Tsing" (mid-stream), or null for the cargo tables, which don't carry this split
cargoModeCode, cargoModeSeaborne or River, or null for the container table, which doesn't carry this split
directionCode, directionInward, outward, or the aggregate total
containerTypeCode, containerTypeLaden, empty, or the aggregate total (container table only, null elsewhere)
shipmentTypeCode, shipmentTypeDirect shipment, transhipment, or the aggregate total (cargo tables only, null elsewhere)
freqM (monthly) or Y (annual)
periodYYYYMM for a monthly row, YYYY for an annual row
unitThe physical unit of figure, e.g. ('000 TEUs) or ('000 tonnes)
figureThe level value, in the unit above
figureFlagThe source's own flag on the level figure: p (provisional), [§3] (rounds to a negligible change) or N.A.
yoyChangePctThe year-on-year percentage change for the same dimension combination and period
yoyChangeFlagThe source's flag on the year-on-year figure, same vocabulary as figureFlag
provisionaltrue if either the level or the year-on-year figure is still provisional
scrapedAtRun timestamp

RUN_SUMMARY in the key-value store holds per-table counts, the filters you used, each table's own title/source/footnotes, and any table id that failed.

Use cases

  • Kwai Tsing vs mid-stream tracking. Watch how much of Hong Kong's container volume is handled at the main Kwai Tsing terminals versus mid-stream and river operations, a split most free trade-statistics sources don't break out.
  • Port competitiveness modelling. Feed monthly TEU throughput and its year-on-year move into a model tracking Hong Kong against Shenzhen and Guangzhou.
  • Laden/empty balance. Compare laden vs empty container flows by direction to read import/export imbalance.
  • Cargo mode mix. Compare the seaborne and river cargo tonnage series to see how much of total throughput moves by river trade.
  • Provisional-to-final tracking. Re-run monthly and diff on figureFlag/yoyChangeFlag to see when a provisional figure firms up.

Quick start

The default run, monthly data across all three built-in tables, capped at 150 rows per table:

{}

Just container throughput, a wider monthly window:

{
"tableIds": ["410-55294"],
"frequency": "M",
"maxRecordsPerTable": 500
}

Annual container figures for a specific stretch of years:

{
"tableIds": ["410-55294"],
"frequency": "Y",
"periodFrom": "2015",
"periodTo": "2025"
}

Input

FieldTypeDefaultNotes
tableIdsarrayall three built-in ids410-55294 (container throughput), 410-55111A (seaborne cargo) and 410-55112A (river cargo) are documented by name. Any other table id published in the same id=NNN-NNNNN shape is still read, with reduced dimension detail if it uses dimension names this Actor doesn't already recognise.
frequencystringMM for monthly, Y for annual, ALL for both.
periodFromstring""Earliest period to keep, as YYYY-MM, YYYYMM or YYYY. Applied after fetching. Empty means the full history.
periodTostring""Latest period to keep, same format. Empty means the most recent published period.
maxRecordsPerTableinteger150Cap on saved rows per table, most recent periods first. The source has no server-side pagination or date filter, so every run downloads each table's complete history regardless of this setting; the cap only bounds what gets saved and charged.
langstringenen, tc (Traditional Chinese) or sc (Simplified Chinese). Only affects tableTitle and the location/cargoMode/direction/containerType/shipmentType labels; the *Code fields stay the same in every language.

Nothing is required. Running with no input returns recent monthly data across all three built-in tables.

Output example

A record from 410-55294, showing the Kwai Tsing vs mid-stream split:

{
"tableId": "410-55294",
"series": "container-throughput",
"tableTitle": "Port container throughput by main cargo handling location",
"measureCode": "PORT_CONTAINER_TP",
"locationCode": "NCT",
"location": "Other than Kwai Tsing Container Terminals",
"cargoModeCode": null,
"cargoMode": null,
"directionCode": "Out",
"direction": "Outward",
"containerTypeCode": "Laden",
"containerType": "Laden",
"shipmentTypeCode": null,
"shipmentType": null,
"freq": "M",
"period": "202605",
"unit": "('000 TEUs)",
"figure": 98,
"figureFlag": "p",
"yoyChangePct": -4.4,
"yoyChangeFlag": "p",
"provisional": true,
"scrapedAt": "2026-08-21T22:49:51.330Z"
}

A record from 410-55111A, showing the cargo-mode dimension the container table doesn't have:

{
"tableId": "410-55111A",
"series": "seaborne-cargo",
"tableTitle": "Seaborne cargo throughput by month",
"cargoModeCode": "S",
"cargoMode": "Seaborne",
"locationCode": null,
"location": null,
"shipmentTypeCode": "TS",
"shipmentType": "Transhipment",
"freq": "M",
"period": "202605",
"unit": "('000 tonnes)"
}

Table ids and what they return

Each id maps to one JSON table on the source, keyed by dimension code plus a description pair, a frequency, a period and two rows per combination: a level figure and a year-on-year percentage change, which this Actor merges into one output row.

Table idSeriesDimensions besides direction/period
410-55294container-throughputLocation (Kwai Tsing terminals vs mid-stream), container type (laden/empty)
410-55111Aseaborne-cargoShipment type (direct shipment/transhipment)
410-55112Ariver-cargoShipment type (direct shipment/transhipment)

API example

curl -X POST "https://api.apify.com/v2/acts/arman-bd~hong-kong-port-throughput-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tableIds": ["410-55294"],
"frequency": "M",
"maxRecordsPerTable": 200
}'

JavaScript example

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/hong-kong-port-throughput-scraper').call({
tableIds: ['410-55294', '410-55111A', '410-55112A'],
frequency: 'M',
maxRecordsPerTable: 300,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const r of items) {
console.log(`${r.period} ${r.series} ${r.location ?? r.cargoMode ?? 'total'}: ${r.figure} ${r.unit} (${r.yoyChangePct}% YoY)`);
}

Notes

  • The source has no date-range or pagination parameter: every run downloads each requested table's complete history (roughly 5-7 MB per table), and frequency, periodFrom, periodTo and maxRecordsPerTable all filter after the fact. The download size per table is fixed regardless of how narrow these filters are.
  • A level figure and its year-on-year change arrive from the source as two separate rows sharing the same dimensions, frequency and period. This Actor pairs them into one output row. Very early periods can be missing one side (year-on-year needs a prior-year baseline that doesn't exist for the first 12 months of a series), in which case the missing side is null.
  • figureFlag/yoyChangeFlag carry the source's own footnote codes verbatim: p for provisional, [§3] for a change under 0.05%, N.A. for not available. provisional is true whenever either flag contains p.
  • location and cargoMode are mutually exclusive across the three built-in tables: the container table has a location split and no cargo-mode split, the cargo tables have a cargo-mode split and no location split. Every record still carries both fields, null on whichever doesn't apply, so combining tables in one run keeps a single dataset shape.
  • One bad table id is recorded in RUN_SUMMARY.failures while the rest of the run continues. The run only errors out if every requested table id failed.
  • Requests are retried up to three times with linear backoff on a transient error. A table id or language code the source rejects is a permanent failure for that table and is not retried.

FAQ

Do I need an account with the source? No. You supply no credentials.

Can I get quarterly figures? No. The source publishes monthly and annual observations only; frequency accepts M, Y or ALL.

Why is maxRecordsPerTable needed if I only want recent months? The source's API always returns a table's entire history in one response; there is no way to ask it for less. maxRecordsPerTable (and periodFrom/periodTo) filter what gets saved, not what gets fetched.

Can I read a table id this Actor doesn't already know about? Yes, pass it in tableIds. It's read through the same endpoint and pivoted the same way; you'll get generic series/dimension labelling if it uses dimension names outside the ones this Actor maps by name.

How current is the data? Monthly figures typically land two to three months after the reference month, and the latest month or two is marked provisional (figureFlag/yoyChangeFlag of p) until the source finalises it.

Can I plug it into something else? Yes. Apify API, the client libraries, webhooks, scheduled runs, dataset exports to JSON, CSV or Excel, or MCP. The output is structured JSON.