# Product Recalls API: CPSC, FDA, EU Safety Gate Alerts (`actose/product-recalls-monitor`) Actor

Official product recalls from US CPSC, FDA (food, drugs, devices) and EU Safety Gate (RAPEX): product, brand, hazard, remedy, UPCs, images, official link. Brand watch with only-new alerts. No API key, no login. MCP-ready for AI agents. Pay per result, errors free. $3 per 1,000 recalls.

- **URL**: https://apify.com/actose/product-recalls-monitor.md
- **Developed by:** [ABM](https://apify.com/actose) (community)
- **Categories:** Business, E-commerce, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.55 / 1,000 recall delivereds

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

## Product Recalls API: CPSC, FDA & EU Safety Gate recall alerts

**$3 per 1,000 recalls ($0.003 per recall). No subscription, no API key, no login. Errors and empty results are free.**

Search and monitor **official product recalls** from three government databases in one call, with a single clean JSON format:

| Source | What it covers |
|---|---|
| **CPSC** (US Consumer Product Safety Commission) | Toys, children's products, furniture, appliances, e-bikes, power banks… |
| **FDA** (openFDA enforcement reports) | Food & cosmetics, drugs, medical devices, with Class I / II / III |
| **EU Safety Gate** (ex-RAPEX, European Commission) | Dangerous non-food products notified by the 30 EU/EEA countries |

Filter by **keyword, brand, category, country and hazard**. For each recall you get the product, brand, manufacturer or firm, hazard or reason, **remedy**, risk level or class, units, UPC/barcodes, models, lot codes, images and the **official link**.

Turn on **`onlyNew`** and schedule the actor: each run returns **only recalls you have not received yet**, so you can watch a brand or a category every morning and pay only for real news.

### How much does it cost?

Pay per event: **one `recall` event = $0.003** for each recall delivered to your dataset.

| You get | You pay |
|---|---|
| 10 recalls | $0.03 |
| 1,000 recalls | **$3.00** |
| A daily brand watch with `onlyNew` (≈ 5 new recalls a week) | ≈ $0.06 a month |

Nothing is charged for recalls already delivered (`onlyNew`), for failed sources or for empty searches. Set `maxResultsPerSource` and the run's spending limit to cap your cost. The actor stops cleanly when the limit is reached.

### Input

```json
{
  "sources": ["cpsc", "fda", "eu"],
  "keywords": ["stroller", "high chair"],
  "brands": [],
  "categories": [],
  "countries": [],
  "hazards": ["choking", "fall"],
  "sinceDays": 90,
  "onlyNew": false,
  "maxResultsPerSource": 50,
  "fdaProductTypes": ["food", "drug", "device"],
  "fdaClassifications": [],
  "includeMarkdown": true
}
```

| Field | Meaning |
|---|---|
| `sources` | `cpsc`, `fda`, `eu` (any combination) |
| `keywords` | At least one must appear in the recall (product, description, brand, firm, hazard, model). Case and accent insensitive |
| `brands` | Brand, manufacturer or recalling firm (brand monitoring) |
| `categories` | e.g. `toys`, `cosmetics`, `motor vehicles`, `food`, `device` |
| `countries` | Country of origin, EU notifying country or FDA firm country: `China`, `CN`, `Germany`, `US`… |
| `hazards` | e.g. `choking`, `fire`, `lead`, `salmonella`, `listeria`, `undeclared`, `strangulation` |
| `sinceDays` | Look-back window (1–3650 days) |
| `onlyNew` | Only recalls not delivered by a previous run with the same filters |
| `stateKey` | Optional watch name for `onlyNew` (otherwise derived from your filters) |
| `maxResultsPerSource` | Cost cap, newest first |
| `fdaProductTypes`, `fdaClassifications` | Narrow FDA results (Class I = most serious) |
| `includeMarkdown` | Adds an LLM-ready Markdown summary per recall |
| `fdaApiKey` | Optional free openFDA key, only for very heavy use |

Filter groups are combined with **AND**, and values inside a group with **OR**. Example: `keywords: ["stroller","car seat"]` + `hazards: ["fall"]` means (stroller OR car seat) AND fall.

### Output

One object per recall in the dataset (JSON, CSV, Excel, HTML…), camelCase fields:

```json
{
  "recallId": "cpsc-26639",
  "source": "cpsc",
  "agency": "U.S. Consumer Product Safety Commission (CPSC)",
  "recallNumber": "26639",
  "title": "Peony Design Recalls Personalized Baby Bibs and Stroller Bags Due to Risk of Serious Injury or Death from Choking Hazard",
  "productName": "Personalized Baby Bibs and Stroller Bags",
  "productDescription": "This recall involves Peony Design personalized handmade baby bibs and stroller bags…",
  "brand": "Peony Design",
  "manufacturer": "Peony Design Co., of Howell, MI",
  "category": null,
  "hazard": "The snap can detach from the recalled bibs and stroller bags, posing a risk of serious injury or death from choking…",
  "remedy": "Consumers should take the recalled baby bibs and stroller bags away from children immediately…",
  "remedyOptions": ["Refund"],
  "riskLevel": null,
  "unitsAffected": "About 52",
  "recallDate": "2026-07-23",
  "publishedDate": "2026-07-24",
  "countryOfOrigin": "United States",
  "soldAt": "Online at Etsy.com from October 2025 through July 2026 for between $15 and $45.",
  "upcs": null,
  "images": ["https://www.cpsc.gov/s3fs-public/peony-1.png"],
  "officialUrl": "https://www.cpsc.gov/Recalls/2026/Peony-Design-Recalls-Personalized-Baby-Bibs-and-Stroller-Bags-…",
  "matchedTerms": ["stroller"],
  "markdown": "## Peony Design Recalls Personalized Baby Bibs…\n- **Source:** U.S. Consumer Product Safety Commission (CPSC)\n- …",
  "scrapedAt": "2026-10-22T08:00:00+00:00"
}
```

An EU Safety Gate alert looks like this (abbreviated):

```json
{
  "recallId": "eu-SR/02869/26",
  "source": "eu",
  "recallNumber": "SR/02869/26",
  "productName": "Necklace – Squid game necklace",
  "category": "Jewellery",
  "hazardType": "Chemical",
  "hazard": "The necklace contains cadmium…",
  "remedy": "Withdrawal of the product from the market (distributor)…",
  "riskLevel": "Serious risk",
  "countryOfOrigin": "Unknown",
  "notifyingCountry": "Sweden",
  "soldAt": "Other(Fyndiq.se) /",
  "weeklyReport": "Report-2026-41",
  "officialUrl": "https://ec.europa.eu/safety-gate-alerts/screen/webReport/alertDetail/…"
}
```

An FDA record includes `riskLevel` ("Class I/II/III"), `recallType` (voluntary or mandated), `status`, `reason`, `lotCodes`, `distribution` and `firmLocation`. Fields that a source does not publish are `null`.

### Use cases

**1. Brand protection, consumer goods manufacturer.** A quality manager watches their brand and their two main competitors in all three jurisdictions every morning and posts the news to a Slack channel.
Input: `{"sources":["cpsc","fda","eu"],"brands":["Graco","Chicco","Joie"],"sinceDays":30,"onlyNew":true}`
Output: `[{"source":"eu","brand":"Chicco","productName":"Baby walker – …","hazard":"…fall…","riskLevel":"Serious risk","officialUrl":"https://ec.europa.eu/safety-gate-alerts/…"}]`
Next: a scheduled run plus a Slack integration. Most mornings the run returns 0 or 1 recall, for a few cents a month.

**2. Marketplace compliance, Amazon / Etsy / Temu sellers and marketplace trust & safety teams.** Every Monday, a compliance analyst pulls last week's toy and childcare recalls from CPSC and EU Safety Gate and matches the UPCs/barcodes and model numbers against their catalog to delist products.
Input: `{"sources":["cpsc","eu"],"categories":["toys","childcare","children"],"sinceDays":7,"maxResultsPerSource":200}`
Output: `[{"recallNumber":"SR/02701/26","upcs":["4032722967176"],"models":["967176"],"soldAt":"…","officialUrl":"…"}]`
Next: export to Google Sheets, then VLOOKUP the `upcs` and `models` columns against the product feed.

**3. Food safety and retail, grocery buyers and QA.** A food safety lead gets every new Class I FDA food recall for Listeria, Salmonella or undeclared allergens, plus the lot codes and distribution states.
Input: `{"sources":["fda"],"fdaProductTypes":["food"],"fdaClassifications":["Class I"],"hazards":["listeria","salmonella","undeclared"],"sinceDays":14,"onlyNew":true}`
Output: `[{"recallNumber":"F-0123-2027","manufacturer":"…","reason":"Potential Listeria monocytogenes contamination","lotCodes":"Best by 11/30/2026","distribution":"CA, NV, AZ","riskLevel":"Class I"}]`
Next: an e-mail alert to store managers, with the `distribution` field used to route it by region.

**4. Sourcing and import risk, buyers sourcing in Asia.** A sourcing team measures how often products from a given origin are flagged in Europe for a category: about 150 alerts per quarter cost $0.45.
Input: `{"sources":["eu"],"countries":["CN"],"categories":["electrical appliances"],"sinceDays":90,"maxResultsPerSource":500}`
Next: a pivot of `hazardType` and `notifyingCountry` to brief suppliers before an order.

**5. RAG and AI agents, legal/insurance research.** A product-liability lawyer feeds the `markdown` field of all stroller and crib recalls from the last 5 years into a vector store and asks an LLM for hazard patterns.
Input: `{"sources":["cpsc","eu"],"keywords":["stroller","crib","bassinet"],"sinceDays":1825,"maxResultsPerSource":1000}`

### Use with AI agents (MCP)

The actor is ready for the Apify MCP server, so Claude, Cursor, ChatGPT and other AI agents can call it as a tool. Add `https://mcp.apify.com?actors=<this-actor-id>` to your MCP client and ask, e.g., *"Any recall of Fisher-Price products in the US or EU in the last 60 days?"* The agent then sends `{"brands":["Fisher-Price"],"sinceDays":60}` and receives structured JSON plus a Markdown summary.

### API, Make, Zapier, n8n and Google Sheets

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("<username>/product-recalls-monitor").call(run_input={
    "sources": ["cpsc", "fda", "eu"],
    "keywords": ["stroller"],
    "sinceDays": 90,
})
for recall in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(recall["recallDate"], recall["source"], recall["title"], recall["officialUrl"])
```

**JavaScript**

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

const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('<username>/product-recalls-monitor').call({
    sources: ['fda'],
    fdaProductTypes: ['food'],
    hazards: ['listeria', 'salmonella'],
    sinceDays: 30,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((r) => `${r.recallNumber} ${r.manufacturer}: ${r.reason}`));
```

**Automation example (Make, n8n or Zapier).** Create a Task in Apify Console with your brand watch input and `"onlyNew": true`, and schedule it daily at 7:00. In Make, use the *Apify › Watch Actor Runs* trigger, then *Apify › Get Dataset Items*, then *Slack › Create a Message* (or *Google Sheets › Add a Row*) with `{{title}} – {{remedy}} – {{officialUrl}}`. n8n and Zapier work the same way with their Apify nodes. For Google Sheets you can also export the dataset directly: `https://api.apify.com/v2/datasets/<id>/items?format=csv&view=overview`.

### FAQ

**Where does the data come from?** Only official public open-data endpoints: the CPSC recall REST service (saferproducts.gov), openFDA enforcement reports (api.fda.gov) and the European Commission's Safety Gate weekly report XML export. No login, no scraping behind a wall, no captcha.

**How fresh is it?** CPSC publishes recalls most weekdays (mostly Thursdays), openFDA updates enforcement reports weekly, and EU Safety Gate publishes one weekly report (usually on Friday). Each run reads the live sources.

**How does `onlyNew` work?** The IDs of the recalls already delivered are stored in your account's named key-value store `product-recalls-monitor-state`, under a key derived from your filters (or from `stateKey`). The next run skips them and does not charge for them. If you change the filters, a new watch starts. You can reset a watch by deleting its key.

**Why is a field `null`?** Each agency publishes different fields. For example, the FDA does not publish images or remedies, and the EU does not publish units sold. The actor never invents values.

**Can I search in other languages?** The CPSC and FDA texts are in English, and EU Safety Gate is read in English. Use English keywords. Accents are ignored.

**What is the official link for FDA recalls?** FDA has no public page per enforcement report, so `officialUrl` points to the official openFDA record for that recall number.

### Limits

- EU Safety Gate is read from the weekly reports. An alert appears when the Commission publishes its weekly report, and `recallDate` is that report's date.
- The CPSC `brand` field is derived from the official title ("Brand Recalls …"). The `manufacturer` field holds the official firm names.
- Without an API key, openFDA allows about 1,000 requests a day per IP address. Normal use needs 1 to 3 requests per run. Add your free `fdaApiKey` for heavy use.
- Long look-backs without filters can return thousands of recalls. Use `maxResultsPerSource` to stay in control.
- This tool aggregates public data for information. Always check the official notice before taking a legal or safety decision.

# Actor input Schema

## `sources` (type: `array`):

Official recall databases to query. cpsc = US Consumer Product Safety Commission (consumer products, toys, children's products, appliances). fda = US FDA enforcement reports (food, drugs, medical devices). eu = EU Safety Gate weekly reports (non-food dangerous products in the EU/EEA).

## `keywords` (type: `array`):

Recall must mention at least one of these words (product name, description, brand, firm, hazard, model). Case- and accent-insensitive. Leave empty to get every recall of the period.

## `brands` (type: `array`):

Brand monitoring: recall must name at least one of these brands, manufacturers or recalling firms. Combine with onlyNew for a daily brand watch.

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

Recall category must contain one of these words, e.g. "toys", "cosmetics", "motor vehicles", "bicycles", "food", "drug", "device". Matched against the CPSC product type, EU Safety Gate category and FDA product type.

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

Country of origin / manufacture, EU notifying country or FDA firm country. English names ("China", "Germany") or ISO codes ("CN", "DE", "US").

## `hazards` (type: `array`):

Hazard or recall reason must contain one of these words, e.g. "choking", "fire", "lead", "salmonella", "listeria", "undeclared", "chemical", "strangulation".

## `sinceDays` (type: `integer`):

Only recalls published in the last N days (1 to 3650). For a daily schedule with onlyNew, 7 to 30 is enough.

## `onlyNew` (type: `boolean`):

Return only recalls not delivered by a previous run with the same filters (remembered in the named key-value store 'product-recalls-monitor-state'). Already-seen recalls are skipped and never charged. Ideal for scheduled runs.

## `stateKey` (type: `string`):

Optional name for the onlyNew memory, e.g. "acme-brand-watch". By default a key is derived from your filters, so changing filters starts a fresh watch.

## `maxResultsPerSource` (type: `integer`):

Upper limit of recalls delivered per source (newest first). Caps your cost.

## `fdaProductTypes` (type: `array`):

Which FDA enforcement report databases to search (only used when the fda source is selected).

## `fdaClassifications` (type: `array`):

Keep only these FDA classes (Class I = most serious). Empty = all classes.

## `includeMarkdown` (type: `boolean`):

Add a 'markdown' field with a compact human/LLM-readable summary of each recall, ready for RAG, Slack or e-mail alerts.

## `fdaApiKey` (type: `string`):

Optional free key from open.fda.gov. Only needed for very heavy use: without a key openFDA allows 1,000 requests per day per IP.

## Actor input object example

```json
{
  "sources": [
    "cpsc",
    "fda",
    "eu"
  ],
  "keywords": [
    "stroller"
  ],
  "brands": [],
  "categories": [],
  "countries": [],
  "hazards": [],
  "sinceDays": 90,
  "onlyNew": false,
  "maxResultsPerSource": 50,
  "fdaProductTypes": [
    "food",
    "drug",
    "device"
  ],
  "fdaClassifications": [],
  "includeMarkdown": true
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

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

No description

# 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 = {
    "sources": [
        "cpsc",
        "fda",
        "eu"
    ],
    "keywords": [
        "stroller"
    ],
    "brands": [],
    "categories": [],
    "countries": [],
    "hazards": [],
    "sinceDays": 90,
    "maxResultsPerSource": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("actose/product-recalls-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 = {
    "sources": [
        "cpsc",
        "fda",
        "eu",
    ],
    "keywords": ["stroller"],
    "brands": [],
    "categories": [],
    "countries": [],
    "hazards": [],
    "sinceDays": 90,
    "maxResultsPerSource": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("actose/product-recalls-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 '{
  "sources": [
    "cpsc",
    "fda",
    "eu"
  ],
  "keywords": [
    "stroller"
  ],
  "brands": [],
  "categories": [],
  "countries": [],
  "hazards": [],
  "sinceDays": 90,
  "maxResultsPerSource": 50
}' |
apify call actose/product-recalls-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,actose/product-recalls-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/l9tPScoECWRYTT39N/builds/xJXiDA1j3vcjdD0TH/openapi.json
