# UN Comtrade Trade Data Scraper — Import/Export Stats (`devilscrapes/un-comtrade-trade-data-scraper`) Actor

Resolve human country names, ISO codes, or HS codes and query UN Comtrade's free keyless preview API for import/export trade statistics — one flat row per reporter, partner, period, commodity, and flow.

- **URL**: https://apify.com/devilscrapes/un-comtrade-trade-data-scraper.md
- **Developed by:** [DevilScrapes](https://apify.com/devilscrapes) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

<p align="center">
  <img src=".actor/icon.svg" width="160" alt="UN Comtrade Trade Data Scraper — Devil Scrapes">
</p>

## UN Comtrade Trade Data Scraper — Import/Export Stats

**$0.20 per run + $0.0025 per result row — about $2.70 per 1,000
results.** Pay only for results that land, no credit card required to try.

UN Comtrade's free preview API answers real trade statistics, but only if
you already know its numeric reporter/partner codes and raw HS digit
strings. This Actor does that lookup work for you: type `United States`,
`USA`, or `840` and get the same answer, then get back a flat, labelled row
with names filled in even where the raw API leaves them null — no second
live lookup call, no code-table spreadsheet open in another tab.

### 🌍 What this scrapes

UN Comtrade's public **Preview API** (Comtrade Plus `public` tier,
`comtradeapi.un.org/public/v1/preview/...`) — the same free, keyless
endpoint family that powers Comtrade Plus's own quick-look UI. Every
combination of reporter country, partner country, period, commodity, and
trade flow you request comes back as one flat row with trade value, net
weight, and quantity fields, when Comtrade reports them.

### 🔥 Features

- **Human-friendly input resolution** — country name, ISO2, ISO3, or
  numeric code; plain `import`/`export`/`both` words; HS code, `TOTAL`, or
  a free-text commodity description — all resolved locally against an
  embedded reference table, no second network call per lookup.
- **Bounded multi-dimensional fan-out** — query multiple reporters,
  partners, periods, and commodities in a single run (capped at 200
  combinations so a run never gets away from you on cost).
- **Null-free labels** — `reporter_name`, `partner_name`, and
  `hs_description` are always filled from the embedded reference table,
  even when Comtrade's own API response leaves those fields null.
- 🛡️ **We rotate browser fingerprints** (curl-cffi impersonation across
  Chrome, Firefox, and Safari profiles) on every request.
- 🔁 **We retry with exponential backoff** on `408/429/5xx` and honour
  `Retry-After`, up to 5 attempts per combination.
- 🧱 **One bad combination never crashes the run.** A transport error or
  an unresolved country name is logged and skipped; every other
  combination still lands in the dataset.
- 🧊 **A zero-match combination still succeeds.** A narrow filter that
  matches nothing finishes with a clear status message, not a failed run
  and a wasted charge.

### 💡 Use cases

- **Trade and supply-chain analysis** — pull import/export flows for a
  reporter-partner pair across multiple years without leaving a
  spreadsheet full of numeric country codes.
- **Customs and commodity research** — check trade value and volume for a
  specific HS chapter or heading across several partner countries in one
  run.
- **Sourcing and procurement due diligence** — compare a candidate
  supplier country's export profile against its declared trade partners.
- **Academic and journalistic trade datasets** — build a clean,
  reproducible reporter/partner/period/commodity table without
  hand-resolving Comtrade's numeric codes first.

### ⚙️ How to use it

1. List one or more `reporters` and `partners` — names, ISO codes, or
   numeric codes all work.
2. Set `periods` (years for annual, `YYYYMM` for monthly) and
   `commodities` (HS codes, `TOTAL`, or free text).
3. Pick `flow` (`import`, `export`, or `both`) and `frequency` (`annual`
   or `monthly`).
4. Run the Actor — the dataset fills with one row per resolved
   reporter × partner × period × commodity × flow combination.

No API key. No account. Just the countries, periods, and commodities you
want.

### 📥 Input

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `reporters` | array of strings | yes | `["United States"]` | Reporting countries — name, ISO2, ISO3, or UN numeric code. |
| `partners` | array of strings | yes | `["World"]` | Trade partner countries — same accepted formats; `World`/`0` = all partners. |
| `periods` | array of strings/numbers | yes | `[2023]` | Years (annual) or `YYYYMM` (monthly), matched against `frequency`. |
| `commodities` | array of strings | yes | `["TOTAL"]` | HS code, `TOTAL`, or a free-text description. |
| `flow` | select | yes | `both` | `import`, `export`, or `both` (fans out into separate rows per direction). |
| `frequency` | select | yes | `annual` | `annual` or `monthly`. |
| `proxyConfiguration` | object | no | Apify Proxy on | Kept on despite the keyless API — the preview tier is documented as rate-limited. |

Example input:

```json
{
  "reporters": ["United States"],
  "partners": ["World"],
  "periods": [2023],
  "commodities": ["TOTAL"],
  "flow": "export",
  "frequency": "annual",
  "proxyConfiguration": { "useApifyProxy": true }
}
```

### 📤 Output

One row per resolved reporter × partner × period × commodity × flow
combination:

```json
{
  "reporter_code": "842",
  "reporter_name": "United States of America",
  "reporter_iso2": "US",
  "reporter_iso3": "USA",
  "partner_code": "0",
  "partner_name": "World",
  "partner_iso2": null,
  "partner_iso3": null,
  "period": "2023",
  "frequency": "annual",
  "flow": "export",
  "hs_code": "TOTAL",
  "hs_description": "All commodities",
  "trade_value_usd": 2018756349021.0,
  "net_weight_kg": null,
  "qty": null,
  "qty_unit": null,
  "is_preview_capped": false,
  "scraped_at": "2026-09-03T06:58:00Z"
}
```

`trade_value_usd`, `net_weight_kg`, `qty`, and `qty_unit` come back `null`
when Comtrade itself reports none for that combination — never a missing
key, never a crashed row.

### 💰 Pricing

This Actor bills **Pay-Per-Event**, so the invoice matches what you
actually received:

| Event | Price |
|---|---|
| Actor start | **$0.20** per run |
| Result emitted | **$0.0025** per trade-statistics row written to the dataset |

That works out to roughly **$2.70 per 1,000 results**. A combination that
returns nothing costs you nothing extra — no per-row charge without a
per-row result.

### 🚧 Limitations

- The Preview API's free tier caps rows returned per single
  (reporter, partner, period, commodity, flow) combination at roughly
  500 — rows from a capped combination are flagged
  `is_preview_capped: true` and summarized in the run's status message,
  never silently dropped.
- The full cartesian product of your inputs (reporters × partners ×
  periods × commodities × flow-expansion) is capped at 200 combinations
  per run — a larger fan-out fails fast before anything is charged.
- Goods trade only (`typeCode=C`, HS classification) — services trade and
  other classifications (SITC, BEC) are out of scope for this version.
- The embedded country and HS reference tables are static data shipped
  with the Actor and refreshed manually — an unmapped free-text commodity
  description falls back to a literal HS-code lookup, which Comtrade
  itself may reject or return empty for.

### ❓ FAQ

**Do I need a UN Comtrade API key?** No — the Preview API is public and
keyless. You don't need an account either.

**What happens if a combination matches nothing?** The run finishes
successfully with zero rows for that combination and a status message
describing what was searched — you're never charged a per-row fee for
rows that don't exist.

**What does `flow: "both"` actually return?** Two separate row sets — one
for imports, one for exports — never a single ambiguous row. Every
emitted row's `flow` field is unambiguously `import` or `export`.

**Why did my run fail instead of returning nothing?** A run fails loud
only when every requested combination hits a real error (unreachable
endpoint, retries exhausted) — not when a combination simply has no trade
observations. Those two cases are handled differently on purpose.

**Can I query monthly data?** Yes — set `frequency: "monthly"` and give
`periods` as `YYYYMM` strings, e.g. `202301`.

### 🙌 Your feedback

Found an issue or have a feature request for the UN Comtrade Trade Data
Scraper? Reach out via
<https://apify.com/DevilScrapes> — we read
every message and ship fixes fast.

# Actor input Schema

## `reporters` (type: `array`):

Reporting countries — name, ISO2, ISO3, or UN numeric code, e.g. <code>United States</code>, <code>USA</code>, <code>840</code>.

## `partners` (type: `array`):

Trade partner countries — same accepted formats as reporters. <code>World</code> (or <code>0</code>) means all partners combined.

## `periods` (type: `array`):

Years for annual frequency (<code>2023</code>) or <code>YYYYMM</code> for monthly (<code>202301</code>). Must match the selected frequency.

## `commodities` (type: `array`):

HS code (any digit-length prefix), <code>TOTAL</code> for all commodities, or a free-text description resolved to the closest curated HS chapter/heading.

## `flow` (type: `string`):

Direction of trade to fetch.

## `frequency` (type: `string`):

Annual (<code>YYYY</code> periods) or monthly (<code>YYYYMM</code> periods) data.

## `proxyConfiguration` (type: `object`):

Kept on even though the API is public and keyless — the preview tier is documented as rate-limited, and a shared datacenter egress IP is more likely to trip that limit than a rotating proxy pool.

## Actor input object example

```json
{
  "reporters": [
    "United States"
  ],
  "partners": [
    "World"
  ],
  "periods": [
    2023
  ],
  "commodities": [
    "TOTAL"
  ],
  "flow": "both",
  "frequency": "annual",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All dataset items as JSON.

## `datasetItemsCsv` (type: `string`):

Same data exported to CSV.

## `datasetView` (type: `string`):

Open the run dataset in the Console.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "reporters": [
        "United States"
    ],
    "partners": [
        "World"
    ],
    "periods": [
        2023
    ],
    "commodities": [
        "TOTAL"
    ],
    "flow": "both",
    "frequency": "annual",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("devilscrapes/un-comtrade-trade-data-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "reporters": ["United States"],
    "partners": ["World"],
    "periods": [2023],
    "commodities": ["TOTAL"],
    "flow": "both",
    "frequency": "annual",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("devilscrapes/un-comtrade-trade-data-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "reporters": [
    "United States"
  ],
  "partners": [
    "World"
  ],
  "periods": [
    2023
  ],
  "commodities": [
    "TOTAL"
  ],
  "flow": "both",
  "frequency": "annual",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call devilscrapes/un-comtrade-trade-data-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,devilscrapes/un-comtrade-trade-data-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rx60zguBuAIwqDZqd/builds/M8wgg48OixrHsLRAP/openapi.json
