# EU Safety Gate Scraper (RAPEX Product Alerts) (`steadfetch/eu-safety-gate-monitor`) Actor

Official EU Safety Gate (RAPEX) weekly reports as JSON: one item per dangerous non-food alert - caseNumber, category, product, riskType, danger, measures, country, report week. Filters: weeksBack, since, categories. Dedup is within-run only: overlapping reports can re-deliver alerts, each charged.

- **URL**: https://apify.com/steadfetch/eu-safety-gate-monitor.md
- **Developed by:** [Steadfetch](https://apify.com/steadfetch) (community)
- **Categories:** News, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 alert delivereds

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?

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

## EU Safety Gate Scraper (RAPEX Product Alerts)

Monitor the European Union's Safety Gate rapid alert system for dangerous
non-food products. This Actor reads the official European Commission XML API and
returns one structured item per product safety alert, ready for compliance,
recall and market-surveillance workflows.

### What it does

- Downloads the official weekly report list from
  `https://ec.europa.eu/safety-gate-alerts/api/download/weeklyReport/list/xml/en`.
- Reads the newest `weeksBack` weekly reports (1-52) and maps every alert to a
  stable JSON item.
- Optionally filters by report publication date (`since`) and product category
  (`categories`, case-insensitive).
- Deduplicates alerts by `caseNumber` + `reference` within the run, and across
  runs per Apify user: the Actor remembers every alert it delivered to your
  account (for the same `categories` filter) in a named key-value store and
  never re-delivers or re-charges it.
- Validates every item against the published output schema before saving it.
- Uses only the public XML API: no browser, no login, no CAPTCHA and no proxy.
  Requests are spaced at least 2 seconds apart and send an honest User-Agent.

**Legal and data reuse.** The XML distribution used here is published on
data.europa.eu as part of the dataset
[Safety Gate (the EU rapid alert system - non-food)](https://data.europa.eu/data/datasets/rapex-rapid-alert-system-non-food)
and is licensed **CC0 1.0 Universal** (public domain dedication,
https://creativecommons.org/publicdomain/zero/1.0/), with access right
`PUBLIC`. The `robots.txt` of `ec.europa.eu` does not disallow
`/safety-gate-alerts/`. Source attribution: European Commission, Safety Gate.

**Privacy.** Alerts describe products, risks, countries and authorities. The
Actor reads no person names and emits no contact fields.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `weeksBack` | integer 1-52 | `4` | Number of weekly reports to download, newest first. |
| `since` | string `YYYY-MM-DD` | none | Skip reports published before this date. |
| `categories` | string\[] | `[]` | Case-insensitive product category filter. |
| `maxResults` | integer 1-5000 | `1000` | Maximum alerts saved to the dataset. |

Example:

```json
{
  "weeksBack": 1,
  "categories": ["Jewellery"],
  "maxResults": 50
}
```

### Example output

```json
{
  "caseNumber": "SR/02869/26",
  "reference": "https://ec.europa.eu/safety-gate-alerts/screen/webReport/alertDetail/10097467",
  "category": "Jewellery",
  "product": "Necklace",
  "name": "Squid game necklace",
  "brand": null,
  "type_numberOfModel": "RM-JL-6641",
  "barcode": null,
  "batchNumber": null,
  "riskType": "Chemical",
  "danger": "The product has an excessive concentration of cadmium (measured value: 6.4% by weight). Cadmium is harmful to human health because it accumulates in the body, can damage the kidneys and bones and it may cause cancer. The product does not comply with the REACH Regulation.",
  "measures": "Type of economic operator taking notified measure(s): DistributorCategory of measure(s): Withdrawal of the product from the marketDate of entry into force: 14/11/2025",
  "description": "Necklace with a cross-shaped pendant featuring a hidden compartment.",
  "notifyingCountry": "Sweden",
  "countryOfOrigin": "Unknown",
  "type": "Consumer",
  "level": "Serious risk",
  "onlineTrader": "Other(Fyndiq.se) / ",
  "urlrecall": null,
  "companyRecallCode": null,
  "productionDates": null,
  "pictures": [
    "https://ec.europa.eu/safety-gate-alerts/public/api/notification/image/11238213",
    "https://ec.europa.eu/safety-gate-alerts/public/api/notification/image/11238214"
  ],
  "report": {
    "reference": "Report-2026-41",
    "publicationDate": "2026-10-16",
    "week": 41,
    "year": 2026
  },
  "source_url": "https://ec.europa.eu/safety-gate-alerts/api/download/weeklyReport/detail/xml/10000327?language=en",
  "url": "https://ec.europa.eu/safety-gate-alerts/screen/webReport/alertDetail/10097467",
  "title": "SR/02869/26 \u00b7 Jewellery \u00b7 Squid game necklace",
  "scrapedAt": "2026-10-20T16:05:00.000Z"
}
```

Fields the source publishes as `xsi:nil` are returned as `null`; values are
never invented.

### Pricing

This Actor uses Apify pay-per-event pricing:

- `apify-actor-start`: **0.00005 USD** per run, the Apify-recommended default
  (includes the first 5 seconds of compute).
- `apify-default-dataset-item`: **3.00 USD per 1,000 alerts** (0.003 USD per
  alert), charged only for new, validated alerts saved to the dataset. Alerts
  already delivered to your Apify account are skipped before they reach the
  dataset, so they are never charged. Duplicated or filtered alerts, empty
  results, retries and errors are not charged.

**Cost per 1,000 alerts (measured locally, no Apify credit spent).** On
2026-10-20 a local run with `{"weeksBack":1,"maxResults":50}` used 2 HTTP
requests, downloaded **602,567 bytes (0.60 MB)** and finished in **3.30 s** at
256 MB, emitting 50 alerts with 0 schema rejections. One weekly report holds
about 90 alerts, so 1,000 alerts need 12 reports plus the list:

| Measurement | Value |
|---|---|
| HTTP requests for 1,000 alerts | 13 (1 list + 12 reports) |
| Bytes downloaded for 1,000 alerts | ~2.9 MB (measured report sizes) |
| Wall time for 1,000 alerts at 256 MB | ~25 s (2 s request spacing) |
| Compute cost (0.25 GB x 25 s x 0.20 USD/GB-hour) | ~0.00035 USD |
| Data transfer (0.0029 GB x 0.20 USD/GB) | ~0.00058 USD |
| **Measured platform cost per 1,000 alerts** | **~0.001 USD (< 0.01 USD)** |

Rates: https://apify.com/pricing (compute 0.20 USD per GB-hour, external data
transfer 0.20 USD/GB). The 3.00 USD per 1,000 price leaves a wide margin over
the measured cost and sits inside the direct-competitor band of 0.001-0.012 USD
per alert observed in the Apify Store on 2026-10-19.

### FAQ

**Does it need an API key or login?**
No. The European Commission XML API is public and keyless.

**How fresh is the data?**
Safety Gate publishes a new weekly report every Friday. With `weeksBack: 1` you
get the latest report; increase it to include more history on your first run.
Later runs only add alerts you have not received before.

**How are duplicates handled?**
Within a run, alerts are deduplicated by `caseNumber` + `reference`: the same
alert appearing in two reports is emitted and charged once. Across runs, the
Actor keeps a per-user memory in a named key-value store
(`eu-safety-gate-monitor-state`, one key per Apify user) of the alerts it
actually pushed, for the same `categories` filter. A repeat run with the same
input delivers 0 alerts and is not charged per alert - only the fixed run-start
event applies. A new alert published after your last run is delivered exactly
once. There is no backfill switch: no mode re-delivers alerts you already
received, so every charged alert is new for your account.

**Are personal data included?**
No. The Actor reads product, risk, country and authority fields only.

**Can I filter by category?**
Yes. `categories` is a case-insensitive exact match on the alert category, for
example `["Jewellery", "Toys"]`.

**Why fewer alerts than expected?**
`maxResults` caps emitted alerts, and `categories`/`since` filter the window.
Alerts you already received in an earlier run are skipped: the run log reports
them as `alreadyDelivered`. Check the run log for `reportsFetched`,
`totalNotifications`, `pushed` and `skipped`.

### Maintenance

Maintenance status: **tested daily**. Steadfetch runs the schema and a live
minimum run as part of its daily QA. The Actor validates every item against the
published schema on every run; a schema violation fails the run instead of
saving partial data. Source and license notes are reviewed when the upstream
distribution changes.

# Actor input Schema

## `weeksBack` (type: `integer`):

Number of weekly reports to download from the official list, newest first. Each report covers one week and usually contains around 90 alerts.

## `since` (type: `string`):

Optional earliest report publication date (YYYY-MM-DD, inclusive). Reports published before this date are not downloaded.

## `categories` (type: `array`):

Optional case-insensitive category filter, for example "Jewellery" or "Toys". Empty means every category.

## `maxResults` (type: `integer`):

Maximum number of alerts to save to the dataset. Duplicates and filtered alerts do not count.

## Actor input object example

```json
{
  "weeksBack": 2,
  "since": "2026-10-01",
  "categories": [
    "Jewellery"
  ],
  "maxResults": 10
}
```

# Actor output Schema

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

Dataset items validated against the item schema in dataset_schema.json (fields).

# 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 = {
    "weeksBack": 2,
    "categories": [
        "Toys"
    ],
    "maxResults": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadfetch/eu-safety-gate-monitor").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 = {
    "weeksBack": 2,
    "categories": ["Toys"],
    "maxResults": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("steadfetch/eu-safety-gate-monitor").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 '{
  "weeksBack": 2,
  "categories": [
    "Toys"
  ],
  "maxResults": 10
}' |
apify call steadfetch/eu-safety-gate-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadfetch/eu-safety-gate-monitor"
        }
    }
}
```

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/q8P9lPg9Itb0jiZgD/builds/mBfwAl7eZ0TexsQxk/openapi.json
