# UK Trade Data API — HMRC Imports & Exports by Commodity (`nexgensignal/uk-hmrc-overseas-trade-observations`) Actor

HMRC Overseas Trade Statistics as data: UK imports and exports by commodity code (HS/CN8), partner country, UK port and month, with value in £, net mass and supplementary units. Filter by commodity, country, flow and months. No API key. Part of NexGen Signal — official-source data products

- **URL**: https://apify.com/nexgensignal/uk-hmrc-overseas-trade-observations.md
- **Developed by:** [NexGen Signal](https://apify.com/nexgensignal) (community)
- **Categories:** News, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $33.50 / 1,000 uk trade observations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 🚢 UK Trade Data API — HMRC Imports & Exports by Commodity

Get HMRC's Overseas Trade Statistics as clean JSON — UK imports and exports of goods by 8-digit commodity code (with HS chapter, heading and subheading names), partner country, UK port and month, with trade value in pounds, net mass in kilograms and supplementary units — straight from HMRC's UK Trade Info API.

Give one or more commodity codes (HS2, HS4, HS6 or CN8), then filter by partner country, flow (EU / non-EU imports and exports) and months. With no months, the latest 12 published months are read. Newest month and largest value first.

The unit of output is one **trade row**: one month, flow, commodity, partner country and port. You pay per row delivered; a run that finds nothing costs nothing.

### Who buys this and for what job

- **Exporters, importers and trade-finance teams** sizing UK trade in a product by country and port.
- **Market-research and sales teams** spotting which countries buy or supply a commodity.
- **Logistics and port analysts** tracking volumes through UK ports.
- **Economists and policy analysts** following UK goods trade month by month.

Buyers usually search for this as **"uk trade data"** or **"hmrc import export data"**.

### 📊 Sample Output

![Table of HMRC overseas trade rows for beer (HS 2203) with France: month, flow, CN8 code, UK port and value in pounds.](https://api.apify.com/v2/key-value-stores/IXCaMKjxSmUTLHhmq/records/uk-hmrc-overseas-trade-observations.png)

| month | flow | commodity_cn8 | port_name | value_gbp | net_mass_kg |
|---|---|---|---|---|---|
| 2026-07 | EU Imports | 22030001 | Eurotunnel(Folkstone | 591205 | 1153004 |
| 2026-07 | EU Exports | 22030009 | Dover/Eurotunnel | 570698 | 436416 |
| 2026-07 | EU Exports | 22030009 | Immingham | 421153 | 288090 |
| 2026-07 | EU Exports | 22030001 | Dover/Eurotunnel | 370772 | 214196 |
| 2026-07 | EU Exports | 22030010 | Dover/Eurotunnel | 346309 | 234538 |
| 2026-07 | EU Imports | 22030009 | Hull | 74514 | 73814 |

Rows from live run `eg6cpvghUx0E0KeBr` on Apify (the Store example: HS 2203 (beer) with France, latest 12 months, 10 rows). Notice the newest month first, largest value first, and the UK port on every row.

### ✅ What you get

Every field of each record:

- `record_id` — oTS:<month>:<flow>:<commodity>:<country>:<port>:<suppression>; stable, use it to upsert.
- `month` — month (YYYY-MM).
- `flow_type_id` — 1-4.
- `flow` — eU Imports, EU Exports, Non-EU Imports or Non-EU Exports.
- `commodity_cn8` — 8-digit Combined Nomenclature code.
- `commodity_description` — CN8 description.
- `hs2_code` — HS chapter.
- `hs2_description` — HS chapter description.
- `hs4_code` — HS heading.
- `hs4_description` — HS heading description.
- `hs6_code` — HS subheading.
- `hs6_description` — HS subheading description.
- `country_code` — partner country (two-letter code).
- `country_name` — partner country name.
- `port_code` — UK port code.
- `port_name` — UK port name.
- `value_gbp` — trade value in pounds sterling.
- `net_mass_kg` — net mass in kilograms (null where not declared).
- `supplementary_units` — supplementary units for the commodity (e.g. litres, items), where declared.
- `suppression_index` — hMRC suppression index (0 = not suppressed).
- `source` — publisher statistics.
- `source_url` — aPI query used.
- `licence` — licence notice.
- `attribution` — source line.
- `observed_at` — when this run read it (UTC).

### ⚙️ Sample inputs

**1. The Store example — beer trade with France**

```json
{
  "commodityCodes": ["2203"],
  "countries": ["FR"],
  "maxRecords": 10
}
```

Read 340 rows for August 2025 to July 2026 and returned the 10 largest of the newest month in run `eg6cpvghUx0E0KeBr`; $0.50 on the Free plan.

**2. Car imports from Germany**

```json
{
  "commodityCodes": ["8703"],
  "countries": ["DE"],
  "flows": ["imports"],
  "maxRecords": 40
}
```

Read 1,123 rows and returned 40 in run `g0bzEobySmBtKow7a`.

**3. Spirits exports to the US**

```json
{
  "commodityCodes": ["2208"],
  "flows": ["non_eu_exports"],
  "countries": ["US"],
  "maxRecords": 20
}
```

Read 735 rows and returned 20 in run `xmK3PWC1ic5OmXuiq`.

Input fields:

| Field | Meaning |
|---|---|
| `commodityCodes` | Required. HS chapter (22), heading (2203), subheading (220300) or 8-digit CN code (22030001). |
| `countries` | Two-letter codes, e.g. FR, US, CN. Leave empty for all. |
| `flows` | imports, exports, eu_imports, eu_exports, non_eu_imports, non_eu_exports. Default: imports and exports. |
| `monthFrom` | e.g. 2025-01. Default: 12 months back from the latest published month. |
| `monthTo` | e.g. 2026-07. Default: the latest published month. |
| `maxRecords` | Stop after this many rows (each is charged once). |

### 🧾 JSON sample record

```json
{
  "record_id": "OTS:202607:1:22030001:1:382:0",
  "month": "2026-07",
  "flow_type_id": 1,
  "flow": "EU Imports",
  "commodity_cn8": "22030001",
  "commodity_description": "Beer made from malt, in bottles holding <= 10 l",
  "hs2_code": "22",
  "hs2_description": "Beverages, spirits and vinegar",
  "hs4_code": "2203",
  "hs4_description": "Beer made from malt",
  "hs6_code": "220300",
  "hs6_description": "Beer made from malt",
  "country_code": "FR",
  "country_name": "France",
  "port_code": "EUT",
  "port_name": "Eurotunnel(Folkstone",
  "value_gbp": 591205,
  "net_mass_kg": 1153004,
  "supplementary_units": 1153004,
  "suppression_index": 0,
  "source": "HMRC Overseas Trade Statistics (OTS), UK Trade Info API",
  "source_url": "https://api.uktradeinfo.com/OTS?$filter=(Commodity/Hs4Code%20eq%20'2203')%20and%20MonthId%20ge%20202508%20and%20MonthId%20le%20202607%20and%20(Country/CountryCodeAlpha%20eq%20'FR')&$expand=Country($select=CountryName,CountryCodeAlpha),Commodity($select=Cn8Code,Cn8LongDescription,Hs2Code,Hs4Code,Hs6Code,Hs2Description,Hs4Description,Hs6Description),Port($select=PortName,PortCodeAlpha)",
  "licence": "Contains public sector information licensed under the Open Government Licence v3.0. Source: HM Revenue & Customs, UK Trade Info, Overseas Trade Statistics. © Crown copyright.",
  "attribution": "Source: HM Revenue & Customs (HMRC), Overseas Trade Statistics (uktradeinfo.com)",
  "observed_at": "2026-10-12T04:09:01Z"
}
```

### 🔧 How it works

1. **Robots check.** `api.uktradeinfo.com/robots.txt` is requested on every run. It returns HTTP 404, so no robots policy is published; that is recorded. A robots file that disallowed the API would stop the run with nothing charged.

2. **Respect the rate limit.** HMRC allows 60 requests a minute; the actor waits at least 1.2 seconds between requests.

3. **Query OTS.** The actor finds the latest published month, counts the rows that match your filter, then reads them in pages of 40,000 (HMRC's page size) with country, commodity and port names expanded. A filter matching more than 200,000 rows is refused before anything is charged; narrow it.

4. **Sort, deliver, then charge.** Rows are sorted newest month and largest value first and pushed in batches, each charged after delivery.

5. **Receipt.** `RUN_RECEIPT` records the robots result, the months read, rows matching and read, and delivered and charged counts.

No login, API key, proxy or bot workaround. HMRC's trader (company) endpoints are never called.

### 💰 Pricing example

Per trade row delivered, no start fee, no monthly charge:

| Apify plan | Price per trade row |
|---|---|
| Free | $0.05 |
| Bronze | $0.045 |
| Silver | $0.04 |
| Gold, Platinum, Diamond | $0.0335 |

- 10 records (the Store example): $0.50 on the Free plan, $0.335 on Gold.
- 1,000 records (the default cap): $50 on Free, $45 on Bronze, $40 on Silver, $33.50 on Gold.

**Coverage and size.** UK overseas trade in goods by CN8 commodity, partner country, UK port and month; the latest month published on 12 Oct 2026 was July 2026. Values are in pounds sterling and net mass in kilograms, as HMRC's OTS tables state; supplementary units depend on the commodity (e.g. litres, items). Flows are EU / non-EU imports and exports as HMRC classifies them. Some trade is suppressed by HMRC (`suppression_index`).

### ⚖️ Legal & ToS

Data: HM Revenue & Customs, Overseas Trade Statistics, from the UK Trade Info API (api.uktradeinfo.com). UK Trade Info states its content is Crown copyright published under the Open Government Licence v3.0, except where otherwise stated. Every record carries the OGL attribution in `licence` and a source line in `attribution`. Not affiliated with or endorsed by HMRC.

Aggregate trade by commodity, country and port — no personal data, and the API's trader endpoints (company names and addresses) are never called. The API's robots file returns 404 (no policy), recorded on every run. One public API, declared User-Agent, HMRC's rate limit respected, no login, key, proxy or form.

### ❓ FAQ

**Why must I give a commodity code?**
OTS is very large; a commodity code keeps queries fast and bills only what you asked for.

**Are values in pounds?**
Yes. HMRC publishes OTS values in pounds sterling and net mass in kilograms.

**What do EU and non-EU flows mean?**
They are HMRC's four flow types; use `imports` or `exports` for both.

**How fresh is it?**
As fresh as HMRC's monthly release; the receipt shows the latest published month.

### 🆘 Troubleshooting

- **"Invalid input: … trade rows match"** — the filter is too broad; use a longer commodity code, fewer months or add countries.
- **0 records for a country** — use two-letter codes, e.g. DE, US, CN.
- **Rows with port 'Not Collected' or 'Estimates'** — those are HMRC's own categories, delivered as published.
- **SOURCE UNAVAILABLE message** — the source did not answer after four tries; nothing was charged — run again later.
- **CAPPED message** — your maximum total charge was reached; raise it in the run options.
- **Run failed with "Invalid input"** — a filter value is malformed; the message names the field. Nothing was charged.

### 🔗 Related Actors

- [UK Tariff Commodity Records — HS Codes & Taxonomy](https://apify.com/nexgensignal/uk-tariff-commodity-records) — UK tariff commodity codes.
- [Sweden Trade by Partner & Month - SCB](https://apify.com/nexgensignal/se-trade-partner-month-observations) — Swedish trade by partner.
- [Australia International Goods Trade - ABS](https://apify.com/nexgensignal/au-international-goods-trade-observations) — Australian goods trade.
- [US Exports by Destination & Mode — CFS Export Freight](https://apify.com/nexgensignal/us-export-freight-mode-records) — US exports by destination and mode.
- [UK CPIH Inflation Time Series - ONS](https://apify.com/nexgensignal/uk-cpih-time-series-observations) — UK inflation.

🏢 **About NexGen Signal** — official-source data products from government and regulator publications. Browse the catalog: [apify.com/nexgensignal](https://apify.com/nexgensignal)

### ⭐ Found this useful?

If this actor saved you time, a rating on its Apify Store page helps other buyers find it.

Part of NexGen Signal — official-source data products.

# Actor input Schema

## `commodityCodes` (type: `array`):

Required. HS chapter (22), heading (2203), subheading (220300) or 8-digit CN code (22030001).

## `countries` (type: `array`):

Two-letter codes, e.g. FR, US, CN. Leave empty for all.

## `flows` (type: `array`):

imports, exports, eu_imports, eu_exports, non_eu_imports, non_eu_exports. Default: imports and exports.

## `monthFrom` (type: `string`):

e.g. 2025-01. Default: 12 months back from the latest published month.

## `monthTo` (type: `string`):

e.g. 2026-07. Default: the latest published month.

## `maxRecords` (type: `integer`):

Stop after this many rows (each is charged once).

## Actor input object example

```json
{
  "commodityCodes": [
    "2203"
  ],
  "countries": [
    "FR"
  ],
  "flows": [],
  "maxRecords": 10
}
```

# Actor output Schema

## `results` (type: `string`):

The delivered (and billed) records.

## `receipt` (type: `string`):

Robots result, source files, rows read, delivered and charged counts.

# 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 = {
    "commodityCodes": [
        "2203"
    ],
    "countries": [
        "FR"
    ],
    "maxRecords": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgensignal/uk-hmrc-overseas-trade-observations").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 = {
    "commodityCodes": ["2203"],
    "countries": ["FR"],
    "maxRecords": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("nexgensignal/uk-hmrc-overseas-trade-observations").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 '{
  "commodityCodes": [
    "2203"
  ],
  "countries": [
    "FR"
  ],
  "maxRecords": 10
}' |
apify call nexgensignal/uk-hmrc-overseas-trade-observations --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexgensignal/uk-hmrc-overseas-trade-observations"
        }
    }
}
```

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/fqvncloJkhuI7zZpI/builds/Hg7dQZ7zzfeJBU7Yc/openapi.json
