# EU Safety Gate Scraper (`crawlerbros/eu-safety-gate-scraper`) Actor

Scrape the European Commission's Safety Gate (RAPEX) database of dangerous product alerts. Search by keyword or alert number, filter by product category, risk type, notifying country and country of origin, or fetch a full alert report by ID.

- **URL**: https://apify.com/crawlerbros/eu-safety-gate-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, Developer tools, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## EU Safety Gate Scraper

Scrape the European Commission's **Safety Gate** (formerly RAPEX) database — the EU's rapid alert system for dangerous non-food products. Search or browse thousands of official product safety alerts covering toys, electronics, cosmetics, childcare articles, chemicals and more, with risk descriptions, measures taken, and country of origin/notification. No login, no API key, no cookies required.

### What this actor does

- **Two modes:** `search` (keyword + filters, paginated) and `byAlertId` (fetch one or more specific alerts by ID)
- **Filters:** product category (34 official categories), risk type (22 official risk types), notifying country (31 EU/EEA/UK members), country of origin (any of 251 ISO countries), alert type (serious risk / other risk level / other alert type), product user (professional / consumer), publication year range, exact publication date range, sort field (publication date or alert number) with ascending/descending order
- **Free-text search** across product name, brand, and alert reference number (e.g. `SR/02077/26`)
- **Optional full detail fetch** — risk description, legal provision, measures taken (recall, ban, withdrawal, etc.), traceability (country of origin, online sale status), and reacting countries
- **28 output languages** — get the product name, description, risk description and legal provision in any of the official Safety Gate languages (all EU/EEA languages plus Norwegian, Icelandic, Ukrainian, Arabic and Irish), not just English
- **Product images** — direct, hotlink-free URLs to official alert photos
- **Empty fields are omitted** — every record only contains data that was actually available for that alert

### Output per alert

**Search mode (default, light record):**

- `alertId`, `reference`, `publicationDate`, `modificationDate`
- `productName`, `productNameSpecific`, `brand`, `brands[]`
- `riskTypes[]`
- `images[]`, `mainImage`
- `webReportCode`, `correctionNote` — official corrigendum text, when the alert was later corrected
- `alertUrl` (official Safety Gate search page carrying this alert's reference number — the site doesn't auto-run searches from a URL, so paste the reference into the on-page search box; use `alertApiUrl` for immediately-usable JSON), `alertApiUrl`

**With `fetchFullDetail: true` or `byAlertId` mode, additionally:**

- `notificationType`, `notificationTypeCode`, `creationDate`, `isImmediateNotification` — `true` for an immediate/rapid Article 12 alert, `false` for a regular weekly-report notification
- `notifyingCountry`, `notifyingCountryCode`
- `productCategory`, `productCategoryOther` — free-text specific category, present only when `productCategory` is "Other"
- `productDescription`, `packageDescription`
- `barcodes[]`, `batchNumbers[]`, `modelNumbers[]` — product identifiers, when disclosed
- `riskDescription`, `legalProvision`, `riskTypeOther` — free-text specific risk, present only when `riskTypes` includes "Other"
- `measures[]` — `{ category, categoryOther, type, entryIntoForceDate, responsibleParty }` — `categoryOther` is the free-text specific measure, present only when `category` is "Other"
- `hasPublishedRecallOnline`, `companyRecallLinks[]` — link(s) to the manufacturer/retailer's own recall notice, when published
- `countryOfOrigin`, `countryOfOriginCode`, `isSoldOnline`
- `onlineMarketplaces[]` — `{ trader, productIdentifier }`, the online marketplace(s) (e.g. Amazon, AliExpress, Temu) the product was reportedly sold on, when disclosed
- `reactingCountries[]`
- `professionalProduct`, `isCounterfeit` (only present when `true`)

Every record also includes `recordType: "safetyGateAlert"` and `scrapedAt`.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` or `byAlertId` |
| `searchQuery` | string | `toy` | Free-text query (mode=search) |
| `alertIds` | array | – | Numeric alert IDs (mode=byAlertId) |
| `productCategories` | array (enum) | – | Filter by one or more product categories |
| `riskTypes` | array (enum) | – | Filter by one or more risk types |
| `notifyingCountries` | array (enum) | – | Filter by notifying EU/EEA/UK country |
| `countriesOfOrigin` | array (enum) | – | Filter by country of manufacture |
| `yearFrom` | int | `2017` | Earliest case/reference-number year (the `YY` in `A12/02131/23`) — NOT the calendar year of `publicationDate`; see FAQ below |
| `yearTo` | int | `2026` | Latest case/reference-number year — NOT the calendar year of `publicationDate`; see FAQ below |
| `publishedSince` | date | – | Earliest exact publication date (`YYYY-MM-DD`) — finer-grained than `yearFrom`, can be combined with it or used alone |
| `publishedUntil` | date | – | Latest exact publication date (`YYYY-MM-DD`) — finer-grained than `yearTo`, can be combined with it or used alone |
| `alertType` | string | – | `SERIOUS_RISK`, `OTHER_RISK_LEVEL`, or `OTHER_ALERT_TYPE` — filter by alert severity/classification. Leave empty for all |
| `productUser` | string | – | `PROFESSIONAL` or `CONSUMER` — filter by whether the product is intended for professional/business or general consumer use. Leave empty for all |
| `sortField` | string | `PUBLICATION_DATE` | `PUBLICATION_DATE` or `ALERT_NUMBER` — which field to sort by |
| `sortOrder` | string | `DESC` | `DESC` (newest/highest first) or `ASC` (oldest/lowest first), applied to `sortField` |
| `fetchFullDetail` | boolean | `false` | Fetch full detail report for every result (mode=search) |
| `outputLanguage` | string | `en` | Language for product name/description and risk description/legal provision text (28 languages supported) |
| `maxItems` | int | `50` | Hard cap on emitted records (1–1000) |

#### Example: recent toy alerts with full risk detail

```json
{
  "mode": "search",
  "searchQuery": "toy",
  "productCategories": ["TOYS"],
  "yearFrom": 2024,
  "yearTo": 2026,
  "fetchFullDetail": true,
  "maxItems": 100
}
```

#### Example: browse all cosmetics alerts from China, newest first

```json
{
  "mode": "search",
  "productCategories": ["COSMETICS"],
  "countriesOfOrigin": ["CN"],
  "sortOrder": "DESC",
  "maxItems": 200
}
```

#### Example: fetch specific alerts by ID

```json
{
  "mode": "byAlertId",
  "alertIds": ["10099540", "10118542"]
}
```

#### Example: alerts published in a specific week

```json
{
  "mode": "search",
  "publishedSince": "2026-08-01",
  "publishedUntil": "2026-08-07",
  "maxItems": 200
}
```

#### Example: German-language alert reports

```json
{
  "mode": "search",
  "productCategories": ["ELECTRICAL_APPLIANCES"],
  "fetchFullDetail": true,
  "outputLanguage": "de",
  "maxItems": 50
}
```

### FAQs

**Do I need an API key or login?**
No. Safety Gate publishes its alert database publicly with no authentication required.

**Why do some alerts have fewer fields than others?**
Not every alert includes every field (e.g. brand, notifying country, or country of origin may be unknown or undisclosed by the reporting authority). Only fields that Safety Gate actually populated are included in the output — there are no placeholder or "N/A" values.

**What's the difference between `search` and `fetchFullDetail: true`?**
`search` alone returns a lightweight summary card per alert (fast, good for browsing). Setting `fetchFullDetail: true` fetches the full official report for each matching alert, including the risk description, legal basis, and measures taken — slower, but the same data shown on the alert's detail page.

**How current is the data?**
Safety Gate is updated by the European Commission on an ongoing basis (multiple new alerts published daily). This actor always queries the live database.

**Can I search by alert reference number?**
Yes — `searchQuery` also matches reference numbers like `SR/02077/26`.

**Can I filter by an exact date instead of just a year?**
Yes — `publishedSince` and `publishedUntil` accept exact `YYYY-MM-DD` dates and can be used together with (or instead of) `yearFrom`/`yearTo` for day-level precision, e.g. to get only alerts from a specific week.

**Why does `yearFrom`/`yearTo` return alerts published outside that range?**
`yearFrom`/`yearTo` filter by the case/reference-number year (the `YY` in a reference like `A12/02131/23`), not by the calendar year the alert was actually published. Immediate Article 12 notifications are opened under one year's case number but can go through review and only get published 1-2+ years later, so a case from 2023 can have a 2026 `publicationDate`. If you need the actual calendar publication date, use `publishedSince`/`publishedUntil` instead — those filter directly on `publicationDate`.

**Can I get the alert text in a language other than English?**
Yes — set `outputLanguage` to any of the 28 supported language codes (e.g. `de`, `fr`, `es`, `pl`). This translates the product name, description, risk description, and legal provision. Category, risk-type and country labels are always shown in English regardless of this setting, and `searchQuery` matching is unaffected by `outputLanguage`.

**What's the difference between `riskTypes` and `alertType`?**
`riskTypes` filters by the *kind* of hazard (e.g. Choking, Fire, Chemical). `alertType` filters by the alert's *severity/classification* instead — `SERIOUS_RISK` for immediate Article 12 notifications, `OTHER_RISK_LEVEL` for regular weekly-report alerts with a lower risk level, or `OTHER_ALERT_TYPE` for non-risk-based notifications (e.g. a corrective-measure-only alert). The two filters can be combined.

**What does `productUser` filter on?**
It restricts results to products the notifying authority classified as intended for professional/business use (`PROFESSIONAL`) versus general consumer use (`CONSUMER`) — e.g. industrial machinery vs. a household toy. Leave it empty to get both. With `fetchFullDetail: true` or `byAlertId` mode, the corresponding `professionalProduct: true` output field is also included on professional-use alerts.

# Actor input Schema

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

What to fetch.

## `searchQuery` (type: `string`):

Free-text search across product name, brand, and alert reference number (e.g. `toy`, `SR/02077/26`). Leave empty to browse all alerts with the filters below. (mode=search)

## `alertIds` (type: `array`):

Numeric Safety Gate alert IDs to fetch full reports for. (mode=byAlertId)

## `productCategories` (type: `array`):

Restrict results to one or more product categories. (mode=search)

## `riskTypes` (type: `array`):

Restrict results to one or more risk types. (mode=search)

## `notifyingCountries` (type: `array`):

Restrict results to alerts notified by one or more EU/EEA/UK countries. (mode=search)

## `countriesOfOrigin` (type: `array`):

Restrict results to products manufactured in one or more countries. (mode=search)

## `yearFrom` (type: `integer`):

Only include alerts whose case/reference number falls in or after this year (the `YY` in a reference like `A12/02131/23`) — this is the upstream API's own `year` filter. It is NOT the calendar year of `publicationDate`: an immediate Article 12 notification can be opened in one year but only publish 1-2+ years later after review, so this filter can return alerts with a `publicationDate` well outside the chosen range. To filter by the actual calendar publication date instead, use `publishedSince`/`publishedUntil`. (mode=search)

## `yearTo` (type: `integer`):

Only include alerts whose case/reference number falls in or before this year (the `YY` in a reference like `A12/02131/23`) — this is the upstream API's own `year` filter. It is NOT the calendar year of `publicationDate`: an immediate Article 12 notification can be opened in one year but only publish 1-2+ years later after review, so this filter can return alerts with a `publicationDate` well outside the chosen range. To filter by the actual calendar publication date instead, use `publishedSince`/`publishedUntil`. (mode=search)

## `publishedSince` (type: `string`):

Only include alerts published on or after this exact date (YYYY-MM-DD). More precise than `yearFrom`; combine both or use this alone. (mode=search)

## `publishedUntil` (type: `string`):

Only include alerts published on or before this exact date (YYYY-MM-DD). More precise than `yearTo`; combine both or use this alone. (mode=search)

## `alertType` (type: `string`):

Restrict results by alert severity/classification: a serious-risk Article 12 immediate notification, a regular weekly-report alert with another risk level, or a non-risk-based alert type (e.g. a corrective-measure-only notification). Leave empty for all alert types. (mode=search)

## `productUser` (type: `string`):

Restrict results to products intended for professional/business use or general consumer use. Leave empty for all. (mode=search)

## `sortField` (type: `string`):

Which field to sort alerts by. (mode=search)

## `sortOrder` (type: `string`):

Sort direction, applied to the field chosen in `sortField`. (mode=search)

## `fetchFullDetail` (type: `boolean`):

For mode=search, fetch the full detail report (risk description, legal provision, measures taken, traceability) for every matching alert instead of just the summary card. Slower but much richer output.

## `outputLanguage` (type: `string`):

Language for the official product name, description, risk description and legal provision text (Safety Gate publishes each alert in all EU/EEA languages plus Norwegian, Icelandic, Ukrainian, Arabic and Irish). Country/category/risk-type labels are always in English regardless of this setting.

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "toy",
  "alertIds": [],
  "productCategories": [],
  "riskTypes": [],
  "notifyingCountries": [],
  "countriesOfOrigin": [],
  "yearFrom": 2017,
  "yearTo": 2026,
  "alertType": "",
  "productUser": "",
  "sortField": "PUBLICATION_DATE",
  "sortOrder": "DESC",
  "fetchFullDetail": false,
  "outputLanguage": "en",
  "maxItems": 50
}
```

# Actor output Schema

## `alerts` (type: `string`):

Dataset containing all scraped Safety Gate alerts.

# 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 = {
    "mode": "search",
    "searchQuery": "toy",
    "alertIds": [],
    "productCategories": [],
    "riskTypes": [],
    "notifyingCountries": [],
    "countriesOfOrigin": [],
    "yearFrom": 2017,
    "yearTo": 2026,
    "publishedSince": "",
    "publishedUntil": "",
    "alertType": "",
    "productUser": "",
    "sortField": "PUBLICATION_DATE",
    "sortOrder": "DESC",
    "fetchFullDetail": false,
    "outputLanguage": "en",
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/eu-safety-gate-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 = {
    "mode": "search",
    "searchQuery": "toy",
    "alertIds": [],
    "productCategories": [],
    "riskTypes": [],
    "notifyingCountries": [],
    "countriesOfOrigin": [],
    "yearFrom": 2017,
    "yearTo": 2026,
    "publishedSince": "",
    "publishedUntil": "",
    "alertType": "",
    "productUser": "",
    "sortField": "PUBLICATION_DATE",
    "sortOrder": "DESC",
    "fetchFullDetail": False,
    "outputLanguage": "en",
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/eu-safety-gate-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 '{
  "mode": "search",
  "searchQuery": "toy",
  "alertIds": [],
  "productCategories": [],
  "riskTypes": [],
  "notifyingCountries": [],
  "countriesOfOrigin": [],
  "yearFrom": 2017,
  "yearTo": 2026,
  "publishedSince": "",
  "publishedUntil": "",
  "alertType": "",
  "productUser": "",
  "sortField": "PUBLICATION_DATE",
  "sortOrder": "DESC",
  "fetchFullDetail": false,
  "outputLanguage": "en",
  "maxItems": 50
}' |
apify call crawlerbros/eu-safety-gate-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/eu-safety-gate-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/SzbahgLcHUwiKPS0o/builds/gCb5lu2xGgOpXyniE/openapi.json
