UN Comtrade Scraper: Global Trade Flows by Commodity avatar

UN Comtrade Scraper: Global Trade Flows by Commodity

Pricing

from $0.37 / 1,000 flow scrapeds

Go to Apify Store
UN Comtrade Scraper: Global Trade Flows by Commodity

UN Comtrade Scraper: Global Trade Flows by Commodity

Scrape UN Comtrade for international trade statistics: imports and exports by reporter, partner, HS commodity code, value and quantity. No login, no proxy, no browser.

Pricing

from $0.37 / 1,000 flow scrapeds

Rating

0.0

(0)

Developer

Arman Hossain

Arman Hossain

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

2 days ago

Last modified

Share

UN Comtrade Scraper: Annual imports and exports by reporter, partner and HS commodity, trade value, net weight and quantity, aggregated so the totals actually add up

UN Comtrade Scraper pulls annual international trade statistics from UN Comtrade, who imports and exports what, from whom, in which HS commodity category, with trade value, net weight and quantity.

Comtrade is the authoritative record of merchandise trade, compiled from what governments themselves report. This Actor reads its public preview endpoint directly: no browser, no proxies, no login, no subscription key.

On authentication. UN Comtrade's full API (/data/v1/get/.) requires a paid subscription key. This Actor is built entirely against the free public preview tier (/public/v1/preview/C/A/HS), which is open, verified by direct probe with no credentials. The preview tier returns at most 500 rows per request; see Limits and behaviour for how that is worked around and when it bites.

Agent skill: SKILL.md

https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/un-comtrade-scraper.md

What you get

Output fieldMeaning
reporterCode, reporterNameThe country doing the reporting (UN M49 code plus resolved name)
partnerCode, partnerNameThe trading partner; code 0 is Comtrade's "World" aggregate
periodCalendar year
flowCodeM = imports, X = exports
cmdCode, cmdDescHS commodity code plus its resolved description
tradeValueReported trade value in USD
netWeightNet weight in kg, where reported
qty, qtyUnitQuantity and its unit (u items, kg, l, , …)
scrapedAtRun timestamp

A RUN_SUMMARY record in the key-value store holds per-run counts, the filters used, any request that failed, and how many requests hit the 500-row ceiling.

Common use cases

  • Map supply-chain dependencies. Pull one HS code across every reporter and see which countries actually supply it.
  • Track tariff and sanction impact. Compare the same reporter/partner/commodity across years either side of a policy change.
  • Size an export market. Total imports of your product category by country, straight from customs data.
  • Trade-balance analysis. Request flow: "M,X" and both directions arrive in one pass.
  • Commodity concentration risk. AG2 expands to all 97 two-digit headings, giving a full profile of a country's trade in one request.

Quick start

One country's total trade with the world:

{
"reporters": ["842"],
"commodityCodes": ["TOTAL"],
"years": ["2022"],
"flow": "M,X"
}

Full commodity profile, all 97 HS chapters:

{
"reporters": ["842"],
"commodityCodes": ["AG2"],
"years": ["2021", "2022"],
"flow": "M",
"maxResults": 500
}

Bilateral flows for a specific product:

{
"reporters": ["276", "842"],
"partners": ["156", "826"],
"commodityCodes": ["8703", "27"],
"years": ["2021", "2022"],
"flow": "M,X",
"maxResults": 200
}

Input

FieldTypeDefaultNotes
reportersarray-Required. UN M49 numeric country codes. A label like 842 - USA is accepted; the code is extracted.
partnersarray["0"]Partner country codes. Empty means partner 0, the World aggregate, which is what you want for a country's total trade.
commodityCodesarray["TOTAL"]TOTAL, AG2/AG4/AG6 for every 2-/4-/6-digit heading, or specific codes like 8703.
yearsarray(current year − 2)Calendar years. One request per year, the preview tier accepts only one period per call.
flowstringMM imports, X exports, M,X both.
maxResultsinteger5000Total cap on saved flows. 0 = no limit.

Country codes

Comtrade uses UN M49 numeric codes, not ISO letters.

CountryCodeCountryCode
World (aggregate)0Germany276
USA842United Kingdom826
China156Japan392
India699France251

The full list is the public Reporters and partnerAreas reference tables, which this Actor also uses to resolve names.

Output example

{
"reporterCode": 276,
"reporterName": "Germany",
"partnerCode": 156,
"partnerName": "China",
"period": "2021",
"flowCode": "M",
"cmdCode": "8703",
"cmdDesc": "Motor cars and other motor vehicles; principally designed for the transport of persons…",
"tradeValue": 1152703769.201,
"netWeight": 55997483.106,
"qty": 72357.005,
"qtyUnit": "u",
"scrapedAt": "2026-08-06T11:56:24.766Z"
}

API example

curl -X POST "https://api.apify.com/v2/acts/arman-bd~un-comtrade-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reporters": ["842"],
"commodityCodes": ["AG2"],
"years": ["2022"],
"flow": "M"
}'

JavaScript example

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/un-comtrade-scraper').call({
reporters: ['842', '276'],
partners: ['156'],
commodityCodes: ['TOTAL'],
years: ['2021', '2022'],
flow: 'M,X',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const f of items) console.log(`${f.period} ${f.reporterName} ${f.flowCode} ${f.partnerName}: $${f.tradeValue}`);

Limits and behaviour

  • Rows are the aggregate flow, not a breakdown, and that matters. Left alone, the endpoint returns one row per customs procedure × mode of transport × second partner. For German car imports from China in 2021 that is 131 rows summing to $9.2 bn against a true total of $1.15 bn, an 8× overcount for anyone adding up tradeValue. This Actor always requests the "all procedures, all modes, all origins" aggregate, so one row is one flow and the values add up correctly.
  • Names are resolved, not returned. The preview tier answers null for reporterDesc, partnerDesc, cmdDesc and qtyUnitAbbr on every single row. This Actor loads the public Reporters, partnerAreas and HS reference tables once per run and fills those names in. If a reference table is unavailable the run continues with null names rather than failing.
  • One year per request. The preview tier rejects multiple periods outright ("Maximum number of periods for preview is 1"), so work is chunked by year, and by groups of 20 commodity codes, which keeps most requests under the row ceiling.
  • 500 rows per request is a hard ceiling. A request that comes back with exactly 500 rows was truncated; the Actor logs a warning naming the request and counts it in RUN_SUMMARY.requestsTruncated. Split by fewer commodity codes or fewer partners to get the rest.
  • It is slow, by design of the source. The endpoint spends 3-6 s in its query planner before answering. Requests allow 120 s, a 1.5 s pause sits between them, and 429/5xx are retried with exponential backoff, the endpoint throttles with "try again in 2 seconds" under even light load.
  • Failures never abort the run. A rejected request is recorded in RUN_SUMMARY.failures and the rest continue. The Actor only throws if every request fails, which is what happens if the reporter code itself is invalid, and the API's own explanation is passed through in the error.
  • Public data only. No authentication, no personal data, no access-control bypass.

FAQ

Do I need a proxy? No. Proxy configuration is not required to run this Actor.

Do I need a Comtrade subscription key? Not for this Actor. The full /data/v1/get/ API does require one; the preview tier this Actor uses does not. The trade-off is the 500-row-per-request ceiling.

Why is the data two years old? Comtrade publishes annual statistics once member states report and the UN validates them, which typically lags 18-24 months. If you leave years empty the Actor defaults to current year − 2 for exactly that reason.

Why is qtyUnit null? Because the reporter did not record a quantity for that flow, the underlying qtyUnitCode is -1. tradeValue is still present and valid.

Why did I get 500 rows exactly? That is the preview ceiling, not the real answer. Check RUN_SUMMARY.requestsTruncated and narrow the query.

What does partner code 0 mean? "World", the sum of all partners. It is the default, and it is what you want for a country's total imports or exports.

What happens if Comtrade is unavailable? The request is retried with backoff, then recorded in RUN_SUMMARY.failures; the run continues with the remaining requests.

Can I schedule it? Yes, it is designed for scheduled runs, though the source updates annually rather than daily.

Can I integrate it with something else? Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.