# Eurostat API: Watch & Export EU Statistics by Dataset Code (`mouadapi/eurostat-statistics`) Actor

Eurostat statistics as flat rows (one per value) for any dataset code and filters, or only values new or revised since your last run; failed and unchanged rows are never charged. Only EU, EFTA and candidate-country values are returned (Eurostat's terms). Not affiliated with or endorsed by Eurostat.

- **URL**: https://apify.com/mouadapi/eurostat-statistics.md
- **Developed by:** [COMPASS DEV](https://apify.com/mouadapi) (community)
- **Categories:** Business, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 value returneds

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

Returns Eurostat statistics as flat rows, one per value, for any dataset code and filters, or only the values that are new
or revised since your last run, and is never charged for failed or unchanged rows. Values for countries outside the EU, EFTA
and the official EU candidate countries are left out, free: Eurostat's reuse terms do not allow selling them.

Give it Eurostat queries (a dataset code such as `une_rt_m`, with filters such as `geo=FR&sex=T`); get one row per value
with the dataset, the country or region, the period, the value and its flag, the unit, every other dimension, a link to
that value's data and a citation of the dataset's DOI. Built for spreadsheets, dashboards and AI agents that need
Eurostat's data without handling JSON-stat. *Not affiliated with or endorsed by Eurostat.*

### What it does

- **Any Eurostat dataset** by its code (find codes in the Eurostat Data Browser), with Eurostat's own filters:
  `dimension=code` pairs (repeat a dimension for several codes) and the time filters `sinceTimePeriod`,
  `untilTimePeriod` and `lastTimePeriod`.
- **Export mode:** every value, one flat row per value.
- **Watch mode** (give a watch list name in `stateName`): remembers every value and returns only:
  - `baseline`: the first run of the list;
  - `new`: a value the list did not have (a new period, for example);
  - `changed`: Eurostat revised a value or its flag (`previousValues` gives the old ones);
  - values already seen are free and left out (`includeUnchanged: true` returns them as free rows).
  - A watch run with nothing new or changed returns **exactly one free `no_data` row** that says so.
- **Eurostat's reuse terms, applied for you:**
  - values for countries outside the EU, EFTA and the official candidate countries (for example the United States, Japan
    or China) are left out, free;
  - so is a value whose partner, citizenship, country of birth or other country code is outside that list, totals such
    as TOTAL, WORLD or EXT_EU27_2020 included (they are not on the list);
  - a dataset that names sources other than Eurostat is refused (one free `no_data` row);
  - trade datasets (`ext_…`) are refused.
- **The values as published:** never recalculated or rounded. Every row cites Eurostat, the dataset's DOI and the date.
- **You are never charged for failed results:** failed, no_data and unchanged rows are free.

### Quick start

```json
{ "queries": ["une_rt_m?geo=FR&geo=DE&sex=T&age=TOTAL&unit=PC_ACT&s_adj=SA&lastTimePeriod=3"] }
```

GDP since 2020 for two countries:

```json
{ "queries": ["nama_10_gdp?geo=FR&geo=DE&unit=CP_MEUR&na_item=B1GQ&sinceTimePeriod=2020"] }
```

Only new and revised values (schedule it; the first run is the baseline):

```json
{ "queries": ["une_rt_m?geo=FR&geo=DE&sex=T&age=TOTAL&unit=PC_ACT&s_adj=SA&lastTimePeriod=3"], "stateName": "unemployment" }
```

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `queries` | list of strings | — (prefilled with two examples) | Eurostat queries, one per line: a dataset code, optionally `?` and filters. Never a URL |
| `mode` | `watch` or `export` | — | Empty: watch when `stateName` is given, otherwise export. An explicit mode wins |
| `stateName` | string | — (prefilled `example-watchlist`) | Watch list name. Watch mode without a name uses the list `default` |
| `includeUnchanged` | boolean | `false` | Watch: also return values already seen (free) |
| `maxItems` | integer 1–100,000 | `1000` | Most charged values per run; in watch mode the rest come in the next run |

Field name from other tools: `datasets` (→ `queries`).

### Output

```json
{
    "status": "ok",
    "attempts": 1,
    "error": null,
    "input": "une_rt_m?geo=FR&sex=T&age=TOTAL&unit=PC_ACT&s_adj=SA&lastTimePeriod=2",
    "mode": "export",
    "watchList": null,
    "dataset": "une_rt_m",
    "datasetLabel": "Unemployment by sex and age - monthly data",
    "geo": "FR",
    "geoLabel": "France",
    "period": "2026-08",
    "value": 8.2,
    "flag": null,
    "unit": "PC_ACT",
    "unitLabel": "Percentage of population in the labour force",
    "dimensions": "{\"freq\":\"M\",\"s_adj\":\"SA\",\"age\":\"TOTAL\",\"unit\":\"PC_ACT\",\"sex\":\"T\"}",
    "dimensionLabels": "{\"freq\":\"Monthly\",\"s_adj\":\"Seasonally adjusted data, not calendar adjusted data\",\"age\":\"Total\",\"unit\":\"Percentage of population in the labour force\",\"sex\":\"Total\"}",
    "seriesKey": "une_rt_m:M.SA.TOTAL.PC_ACT.T.FR",
    "datasetUpdated": "2026-10-01T11:00:00+0200",
    "doi": "10.2908/UNE_RT_M",
    "changeType": null,
    "changedFields": null,
    "previousValues": null,
    "url": "https://ec.europa.eu/eurostat/api/dissemination/statistics/1.0/data/une_rt_m?freq=M&s_adj=SA&age=TOTAL&unit=PC_ACT&sex=T&geo=FR&time=2026-08",
    "source": "Source: Eurostat, https://doi.org/10.2908/UNE_RT_M, accessed 2026-10-02.",
    "license": "Eurostat reuse policy: commercial reuse authorised with the source acknowledged; values for countries outside the EU, EFTA and candidate countries are left out",
    "licenseUrl": "https://ec.europa.eu/eurostat/help/copyright-notice",
    "scrapedAt": "2026-10-02T17:00:00.000Z"
}
```

| Status | Meaning | Charged? |
|---|---|---|
| `ok` | A value returned | Export: yes. Watch: `baseline`, `new` and `changed` yes; `unchanged` no |
| `no_data` | No value for the filters, every value left out under Eurostat's terms (or a dataset from other sources), or nothing new since the last run | No |
| `failed` | Invalid query (a URL, a trade dataset, a bad filter), an unknown dataset, a query Eurostat finds too big, or no answer after retries (`error` says why) | No |

The key-value store holds `RUN_REPORT` (counts, charged and free rows, values left out and why, stop reason) and, when
something fails, the raw response (`SNAPSHOT_*`).

### Use it from AI agents

One clear main input, `queries`; every row has `status`, `error`, `url` and `scrapedAt`. Call it through the Apify API,
the Apify MCP server (`mouadapi/eurostat-statistics`) or x402 agentic payments. Copy-paste call (your Apify token in
`APIFY_TOKEN`):

```bash
curl -s -X POST "https://api.apify.com/v2/acts/mouadapi~eurostat-statistics/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries": ["une_rt_m?geo=FR&geo=DE&sex=T&age=TOTAL&unit=PC_ACT&s_adj=SA&lastTimePeriod=3"]}'
```

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('mouadapi/eurostat-statistics').call({ queries: ['une_rt_m?geo=FR&sex=T&age=TOTAL&unit=PC_ACT&s_adj=SA&lastTimePeriod=3'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Output fields

| Field | Type | Description |
|---|---|---|
| `status` | string (or null) | ok = a value returned (charged in export mode and for baseline, new and changed rows; free when unchanged); no_data = nothing to return (no value for the filters, every value left out under Eurostat's terms, or nothing new since the last run) (free); failed = invalid query or no answer (free) |
| `attempts` | integer (or null) | Requests made for this query (retries included) |
| `error` | string (or null) | Why a row is no_data or failed (Eurostat's own message when it gives one); null on ok rows |
| `input` | string (or null) | The query as given in the input |
| `mode` | string (or null) | watch or export |
| `watchList` | string (or null) | Watch list name (watch mode); null in export mode |
| `dataset` | string (or null) | Eurostat dataset code |
| `datasetLabel` | string (or null) | The dataset's title at Eurostat |
| `geo` | string (or null) | Eurostat geo code: a country, region (NUTS) or EU or euro-area aggregate; only EU, EFTA and candidate countries are returned (Eurostat's terms); null when the dataset has no geo dimension |
| `geoLabel` | string (or null) | The geo code's name |
| `period` | string (or null) | The period of the value as Eurostat writes it (2023, 2026-08, 2026-Q2 …) |
| `value` | number (or null) | The value as Eurostat publishes it (never modified), in the unit given |
| `flag` | string (or null) | Eurostat's flag for the value (p provisional, e estimated, b break in series …); null when none |
| `unit` | string (or null) | The unit dimension's code; null when the dataset has no unit dimension |
| `unitLabel` | string (or null) | The unit's name |
| `dimensions` | string (or null) | Every dimension's code except geo and time, as JSON (one string column) |
| `dimensionLabels` | string (or null) | The same dimensions' names, as JSON |
| `seriesKey` | string (or null) | The dataset and every dimension's code except time: the series the value belongs to |
| `datasetUpdated` | string (or null) | When Eurostat last updated the dataset (ISO 8601) |
| `doi` | string (or null) | The dataset's DOI, for citing it |
| `changeType` | string (or null) | Watch mode: baseline (first run of the list), new (a value the list did not have), changed (Eurostat revised the value or its flag) or unchanged (free); null in export mode |
| `changedFields` | string (or null) | Watch mode: tracked fields that changed, comma-separated (value, flag) |
| `previousValues` | string (or null) | Watch mode: the changed fields' previous values, as JSON |
| `url` | string (or null) | The value's own data URL at the Eurostat API (every dimension fixed to its code) |
| `source` | string (or null) | The citation Eurostat's terms ask for: Eurostat, the dataset's DOI and the access date |
| `license` | string (or null) | Eurostat's reuse terms, and what is left out under them |
| `licenseUrl` | string (or null) | Eurostat's copyright notice |
| `scrapedAt` | string (or null) | When the row was made (ISO 8601) |

### Pricing

Pay per event: one `observation` event per returned value (export: every value; watch: `baseline`, `new` and `changed`
rows). `no_data`, `failed` and unchanged rows are free, and so are the values left out under Eurostat's terms.

| Plan | Price per 1,000 values |
|---|---|
| Free | $1.50 |
| Bronze | $1.30 |
| Silver | $1.15 |
| Gold (and higher) | $1.00 |

Apify also charges its small per-run start event. There are no usage fees on top.

### Limits

- One request per query, one at a time, at most one a second (Eurostat publishes no rate limit, so this is ours). If
  Eurostat answers HTTP 429, the run pauses 60, 120 and 240 seconds on the same connection, then stops with free `failed`
  rows. No other IP or proxy is ever tried.
- Eurostat answers a costly query (a whole large dataset) as too big, or prepares it asynchronously: the query fails free
  with Eurostat's message. Filter it (fewer countries, a time filter) and run it again.
- At most 100 filters and 1,500 characters per query (Eurostat refuses longer addresses), and at most 20,000 values read
  per query.
- Only the countries Eurostat's terms allow are returned (the EU, EFTA and the official candidate countries, their
  regions, and EU, euro-area, EEA and EFTA aggregates). The candidate list follows the EU's; a value for another code is
  left out, even when Eurostat publishes it.

### Known issues

- None known yet.

### FAQ

**Why are values for the United States (or Japan, China …) missing?** Eurostat's reuse terms do not allow selling data
for countries outside the EU, EFTA and the official candidate countries, so this Actor leaves them out, also when the
country is a partner, a citizenship or a country of birth. The run report
counts them. They are free to use, non-commercially, from Eurostat itself.

**Why did a watch run return one `no_data` row?** Nothing was new or revised since the last run of the watch list; the
row says how many values were unchanged. It is free.

**Where do I find dataset codes and dimension codes?** In the Eurostat Data Browser: the code is under each dataset's
title, and each dimension's codes are in its filter list.

### Data and licence

- Source: the Eurostat dissemination API (statistics endpoint, JSON-stat 2.0), documented at
  https://ec.europa.eu/eurostat/web/user-guides/data-browser/api-data-access/api-introduction.
- Terms: Eurostat's copyright notice (https://ec.europa.eu/eurostat/help/copyright-notice): commercial and non-commercial
  reuse of its statistics is authorised provided the source is acknowledged, with exceptions this Actor leaves out. Every
  row cites Eurostat, the dataset's DOI and the access date.
- This Actor is not affiliated with, endorsed by or provided by Eurostat, and Eurostat bears no responsibility for it or
  for the use of these data. It returns the values as published.

# Actor input Schema

## `queries` (type: `array`):

One query per line: a Eurostat dataset code (e.g. une_rt_m), optionally followed by ? and filters: dimension=code pairs (geo=FR\&geo=DE\&unit=PC_ACT) and time filters (sinceTimePeriod=2020, untilTimePeriod=2024, lastTimePeriod=3). Find codes in the Eurostat Data Browser. Never a URL; trade datasets (ext\_…) are refused.

## `mode` (type: `string`):

Empty: watch when a watch list name is given, otherwise export. "watch" returns only values that are new or revised since the last run of the watch list; "export" returns every value. An explicit mode wins.

## `stateName` (type: `string`):

Name of your watch list (kept in your own storage between runs). Giving a name turns on watch mode. Watch mode without a name uses the list "default".

## `includeUnchanged` (type: `boolean`):

Watch mode: also return values already seen, as free rows.

## `maxItems` (type: `integer`):

Most values returned and charged per run. In watch mode the rest come in the next run.

## Actor input object example

```json
{
  "queries": [
    "une_rt_m?geo=FR&geo=DE&sex=T&age=TOTAL&unit=PC_ACT&s_adj=SA&lastTimePeriod=3",
    "nama_10_gdp?geo=FR&geo=DE&unit=CP_MEUR&na_item=B1GQ&sinceTimePeriod=2020"
  ],
  "stateName": "example-watchlist",
  "includeUnchanged": false,
  "maxItems": 1000
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with one row per value (dataset, geo, period), or per query when nothing is returned

## `runReport` (type: `string`):

Summary of the run (counts, charged and free rows, stop reason)

# 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 = {
    "queries": [
        "une_rt_m?geo=FR&geo=DE&sex=T&age=TOTAL&unit=PC_ACT&s_adj=SA&lastTimePeriod=3",
        "nama_10_gdp?geo=FR&geo=DE&unit=CP_MEUR&na_item=B1GQ&sinceTimePeriod=2020"
    ],
    "stateName": "example-watchlist"
};

// Run the Actor and wait for it to finish
const run = await client.actor("mouadapi/eurostat-statistics").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 = {
    "queries": [
        "une_rt_m?geo=FR&geo=DE&sex=T&age=TOTAL&unit=PC_ACT&s_adj=SA&lastTimePeriod=3",
        "nama_10_gdp?geo=FR&geo=DE&unit=CP_MEUR&na_item=B1GQ&sinceTimePeriod=2020",
    ],
    "stateName": "example-watchlist",
}

# Run the Actor and wait for it to finish
run = client.actor("mouadapi/eurostat-statistics").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 '{
  "queries": [
    "une_rt_m?geo=FR&geo=DE&sex=T&age=TOTAL&unit=PC_ACT&s_adj=SA&lastTimePeriod=3",
    "nama_10_gdp?geo=FR&geo=DE&unit=CP_MEUR&na_item=B1GQ&sinceTimePeriod=2020"
  ],
  "stateName": "example-watchlist"
}' |
apify call mouadapi/eurostat-statistics --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mouadapi/eurostat-statistics"
        }
    }
}
```

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/V8yzKl3OuPXeGZVWT/builds/b72bF2NBdOIJF3JUn/openapi.json
