# Food, Drug & Device Recalls Monitor (from openFDA data) (`br_data_hub/fda-recalls-monitor`) Actor

Food, drug and medical device recalls from the official openFDA enforcement API in one uniform format. Filter by company, product words, class I/II/III, state, country and dates, and get only new recalls since the last run.

- **URL**: https://apify.com/br_data_hub/fda-recalls-monitor.md
- **Developed by:** [br_data_hub](https://apify.com/br_data_hub) (community)
- **Categories:** Automation, AI, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 recalls

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

## Food, Drug & Device Recalls Monitor (from openFDA data)

Get **U.S. recalls of food, drugs and medical devices** from public **openFDA** enforcement data, all three in **one uniform format**, and turn them into **scheduled alerts** that return **only recalls you have not seen yet**.

Built for compliance, quality, supply-chain and retail teams who need to know when a supplier, a brand or a product type is recalled, and for AI agents that need clean recall data.

### Why this Actor

- **Three categories, one schema.** Food, drug and device enforcement records come out with the same fields (`recallNumber`, `recallingFirm`, `productDescription`, `reasonForRecall`, `classification`, `status`, `distributionPattern`, dates, `productQuantity`...). No need to merge three APIs yourself.
- **"Only new since last run" mode.** The Actor remembers which recalls it already returned (in a named key-value store, one memory per filter combination). Schedule it daily or weekly and get just the new ones, ready for an email, Slack or webhook integration.
- **Handles openFDA paging limits.** openFDA cannot page past 26,000 results (`skip` max 25,000). The Actor splits the date range automatically, so long histories still come out complete.
- **Optional free API key.** Without a key openFDA allows 1,000 requests per day per IP address; add your key for 120,000 per day.

### Input

| Field | Description |
|---|---|
| `categories` | `food`, `drug`, `device` (all by default). |
| `companies` | Recalling firm names, e.g. `["Abbott", "Tyson Foods"]` (phrase search, any matches). |
| `productKeywords` | Words in the product description, e.g. `["peanut", "insulin pump"]`. |
| `classifications` | `I`, `II`, `III` (FDA hazard class). |
| `states` | U.S. state of the recalling firm, e.g. `["CA", "NY"]`. |
| `countries` | Country of the recalling firm, e.g. `["United States", "India"]`. |
| `statuses` | `Ongoing`, `Completed`, `Terminated`, `Pending`. |
| `dateFrom`, `dateTo` | Date range (YYYY-MM-DD). Empty = last `lookbackDays` (30) until today. |
| `dateField` | Which date the range applies to: `report_date` (default, weekly FDA Enforcement Report), `recall_initiation_date`, `center_classification_date`, `termination_date`. |
| `onlyNew` | Return only recalls not returned before for the same filters. |
| `skipExistingOnFirstRun` | With `onlyNew`, the first run just memorizes current recalls (returns and charges nothing). |
| `stateStoreName` | Named key-value store for the memory (default `fda-recalls-monitor-state`). |
| `maxItems` | Maximum recalls per run, newest first (default 100). |
| `apiKey` | Optional openFDA API key (stored as a secret). |

Example: Class I food and drug recalls mentioning peanut or milk, alerts only for new ones:

```json
{
  "categories": ["food", "drug"],
  "productKeywords": ["peanut", "milk"],
  "classifications": ["I"],
  "onlyNew": true,
  "lookbackDays": 14
}
```

### Output

One item per recall (product), same fields for every category:

```json
{
  "category": "food",
  "recallNumber": "F-2058-2012",
  "eventId": "62644",
  "recallingFirm": "Cass Clay Creamery AMPI Fargo Division",
  "productDescription": "Cass-Clay, Swiss Chip, 3 Gallon(11.34 L).",
  "productType": "Food",
  "reasonForRecall": "Cass-Clay Creamery is voluntarily recalling a number of ice cream products because they may contain undeclared soy (lecithin).",
  "classification": "Class II",
  "classLevel": "II",
  "status": "Ongoing",
  "voluntaryMandated": "Voluntary: Firm Initiated",
  "initialFirmNotification": "Two or more of the following: Email, Fax, Letter, Press Release, Telephone, Visit",
  "distributionPattern": "ND, AZ, MN, SD, KS",
  "productQuantity": "81 containers",
  "codeInfo": "all products that has a plant code of \"38-25\".",
  "city": "Fargo",
  "state": "ND",
  "country": "United States",
  "recallInitiationDate": "2012-07-20",
  "centerClassificationDate": "2012-08-31",
  "reportDate": "2012-09-05",
  "terminationDate": null,
  "brandNames": [],
  "genericNames": [],
  "productCode": null,
  "sourceUrl": "https://api.fda.gov/food/enforcement.json?search=recall_number%3A%22F-2058-2012%22"
}
```

`brandNames` and `genericNames` come from openFDA's harmonized fields when available (mostly drugs). Street addresses of firms are not included.

### How much does it cost?

Pay per event, no platform usage fees:

| Event | When | Price |
|---|---|---|
| `apify-actor-start` | Once per run (charged by Apify) | US$ 0.00005 |
| `recall` | Once per recall returned | US$ 0.002 (US$ 2 per 1,000) |

Runs that find nothing, failed runs and the first "memorize only" run pay only the start event. A daily alert that finds 5 new recalls costs about US$ 0.01 per day.

**$0.001 per recall** (`recall` event, pay per event). Charged once per recall returned. Errors, empty runs and memorize-only runs are free.

- `apify-actor-start`: $0.00005 (Charged once when a run starts (Apify synthetic event).)

| You get | Free tier | Bronze tier (10% off) | Gold tier (30% off) |
|---|---|---|---|
| 100 recalls | $0.10 | $0.09 | $0.07 |
| 1,000 recalls | $1.00 | $0.90 | $0.70 |
| 10,000 recalls | $10.00 | $9.00 | $7.00 |

Discounts follow your Apify subscription tier: Bronze 10%, Silver 20%, Gold and above 30%. No subscription to this Actor and no charge for platform usage: you pay only for results.
The Apify Free plan includes $5 of monthly credit, enough for about **5,000 recalls** at the list price.
You can cap the cost of any run with **Maximum cost per run**; the Actor stops when it is reached.

### Data source

[openFDA](https://open.fda.gov) enforcement endpoints of the U.S. Food and Drug Administration: `/food/enforcement`, `/drug/enforcement` and `/device/enforcement` (`api.fda.gov`). These are the recalls published in FDA's weekly Enforcement Report. Data is public domain (CC0 1.0) per the [openFDA terms](https://open.fda.gov/terms/). Data provided by the U.S. Food and Drug Administration (https://open.fda.gov). **This Actor is an independent tool. It is not affiliated with, endorsed by or sponsored by the U.S. Food and Drug Administration (FDA) or openFDA.** openFDA notes that results are unvalidated and must not be used for medical decisions.

Limits: openFDA is updated weekly; without an API key, Apify servers share the 1,000 requests per day per IP limit with other users, so add your free key for heavy or frequent use.

### More questions

#### How fresh is the data?

As fresh as openFDA. FDA publishes recalls in its weekly Enforcement Report and openFDA updates about once a week, so a recall announced by a company today can take a week or more to appear here. Each run asks openFDA live; nothing is cached by the Actor.

#### What do Class I, II and III mean?

They are FDA's hazard classes. Class I is the most serious: a reasonable probability that the product causes serious health problems or death. Class II covers temporary or reversible problems, and Class III products are unlikely to cause harm. Filter with `classifications` (`I`, `II`, `III`; `1`, `2`, `3` or `Class I` also work). `classLevel` holds just the Roman numeral.

#### Why do I get several rows for what looks like one recall?

openFDA lists each recalled product separately, with its own `recallNumber`. Products recalled together share the same `eventId`, so group by `eventId` to see one row per recall event.

#### How does "only new since last run" work?

With `onlyNew`, the Actor keeps the recall numbers it already returned in a named key-value store (`stateStoreName`), one memory per combination of filters, and returns only the ones not seen before. Each run looks back `lookbackDays` before the previous run, because FDA sometimes publishes reports late. Turn on `skipExistingOnFirstRun` if the first run should only memorize what exists today, without returning or charging anything.

#### How do company and product filters match?

Each company name and each product keyword is searched as a phrase in `recalling_firm` or `product_description`. Several values are combined with OR inside a field, and different fields with AND. A short phrase such as `peanut` catches more than `peanut butter cups`. The country filter accepts `US`, `USA` or `United States`.

#### Do I need an openFDA API key?

No, but it helps for frequent runs. Without a key openFDA allows 1,000 requests per day per IP address, and Apify IP addresses are shared with other users. A free key raises that to 120,000 per day. Add it in `apiKey`, a secret input field.

#### Can I get more than 26,000 recalls?

Yes. openFDA stops paging after 26,000 results, so the Actor splits the date range in halves until each part fits, newest part first. Set `maxItems` to the number you want.

#### Can it tell me if a product I have at home is safe?

No. The Actor only relays FDA enforcement records, which openFDA says are not validated and must not be used for medical decisions. It gives no medical advice. Read the official FDA or company recall notice, and ask a pharmacist or doctor about any health concern.

### Use it via API

Run it from any language and get the results as JSON. Replace `<YOUR_API_TOKEN>` with your [Apify API token](https://console.apify.com/settings/integrations).

```bash
curl -X POST "https://api.apify.com/v2/acts/br_data_hub~fda-recalls-monitor/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"categories": ["food", "drug", "device"], "dateField": "report_date", "lookbackDays": 30, "onlyNew": false, "skipExistingOnFirstRun": false, "stateStoreName": "fda-recalls-monitor-state", "maxItems": 100}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("br_data_hub/fda-recalls-monitor").call(run_input={'categories': ['food', 'drug', 'device'],
                                      'dateField': 'report_date',
                                      'lookbackDays': 30,
                                      'onlyNew': False,
                                      'skipExistingOnFirstRun': False,
                                      'stateStoreName': 'fda-recalls-monitor-state',
                                      'maxItems': 100})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

You can also schedule runs, send results to webhooks, or connect the Actor to Make, Zapier, n8n, Google Sheets and other [integrations](https://docs.apify.com/platform/integrations).

### Use it with AI agents (MCP)

This Actor is ready for AI agents: typed input and output schemas, pay-per-event pricing, limited permissions and short runs.

- **Apify MCP server:** add `https://mcp.apify.com/?tools=br_data_hub/fda-recalls-monitor` to Claude, ChatGPT, Cursor, VS Code or any MCP client, and the agent can call this Actor as a tool.
- **Agent frameworks:** call it from LangChain, LlamaIndex, CrewAI or the OpenAI Agents SDK through the Apify integrations, or with the API call above.
- Results come as structured JSON with stable field names, documented in the **Output** tab.

### FAQ

#### Where does the data come from?

[openFDA](https://open.fda.gov) enforcement endpoints of the U.S. Food and Drug Administration: `/food/enforcement`, `/drug/enforcement` and `/device/enforcement` (`api.fda.gov`). These are the recalls published in FDA's weekly Enforcement Report. Data is public domain (CC0 1.0) per the [openFDA terms](https://open.fda.gov/terms/). Data provided by the U.S. Food and Drug Administration (https://open.fda.gov). **This Actor is an independent tool. It is not affiliated with, endorsed by or sponsored by the U.S. Food and Drug Administration (FDA) or openFDA.** openFDA notes that results are unvalidated and must not be used for medical decisions.

#### How much does it cost?

$0.001 per recall. Discounts follow your Apify subscription tier: Bronze 10%, Silver 20%, Gold and above 30%. See **How much does it cost?** above for examples.

#### Do I pay for errors or empty results?

No. Charged once per recall returned. Errors, empty runs and memorize-only runs are free.

#### Can I run it on a schedule or connect it to other tools?

Yes. Use Apify schedules to run it daily or weekly, webhooks to get notified, and integrations such as Make, Zapier, n8n and Google Sheets. Everything also works through the API.

#### Can AI agents use it?

Yes. It works as a tool in the Apify MCP server and in agent frameworks, and AI agents can pay per event. See **Use it with AI agents (MCP)**.

#### Is it legal to use this data?

The Actor reads only public sources. You are responsible for how you use the data and for complying with the source's terms and with privacy laws such as GDPR.

#### I found a bug or need a feature. What should I do?

Open an issue in the **Issues** tab. We answer within 14 days, usually much sooner.

### More Actors from BR Data Hub

| Actor | What it does |
|---|---|
| [Domain RDAP Lookup: modern WHOIS for any TLD](https://apify.com/br_data_hub/domain-rdap-lookup) | Bulk RDAP lookup on each TLD's official registry server (IANA bootstrap): registrar, creation, update and expi |
| [Email Domain Auth Checker: SPF, DKIM, DMARC, BIMI, MTA-STS](https://apify.com/br_data_hub/email-domain-auth-checker) | Bulk check SPF (real recursive lookup count vs |
| [CVE Risk Prioritizer, from NVD, CISA KEV and EPSS data](https://apify.com/br_data_hub/cve-risk-prioritizer) | One row per CVE built from public NVD (CVSS, CWE, affected products), CISA KEV (exploited, due date, ransomwar |
| [Clinical Trials Tracker, from ClinicalTrials.gov data](https://apify.com/br_data_hub/clinical-trials-tracker) | Search public ClinicalTrials.gov data by condition, drug, sponsor, phase, status and country, and track what c |

See all our Actors at [apify.com/br_data_hub](https://apify.com/br_data_hub).

### Usar em português

Recalls (recolhimentos) da FDA dos EUA para alimentos, medicamentos e dispositivos médicos, pela API oficial openFDA, num formato único para as três categorias. Filtre por empresa, palavras do produto, classe (I, II, III), estado, país, status e datas. O modo "só novos desde a última execução" guarda o que já foi devolvido num key-value store nomeado, para alertas agendados de compliance, cadeia de suprimentos e varejo. Chave da API opcional (sem ela, 1.000 requisições por dia por IP). Cobrança só por recall devolvido; execuções sem resultado ou com erro não são cobradas.

**Quanto custa:** $0.001 por resultado (`recall`); 1.000 resultados saem por $1.00. Desconto pelo nível da assinatura Apify: Bronze 10%, Silver 20%, Gold ou acima 30%. Erros e consultas sem resultado não são cobrados. Use também pela API ou por agentes de IA no servidor MCP da Apify (`https://mcp.apify.com/?tools=br_data_hub/fda-recalls-monitor`).

# Actor input Schema

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

Pick the openFDA enforcement endpoints to search: food, drugs and medical devices. Leave all three for every recall.

## `companies` (type: `array`):

Enter recalling firm names, one per line, e.g. Abbott or Tyson Foods. Any name matches (phrase search, case ignored). Leave empty for all companies.

## `productKeywords` (type: `array`):

Enter words or phrases from the product description, one per line, e.g. peanut, insulin pump or ibuprofen. Any of them matches. Leave empty for all products.

## `classifications` (type: `array`):

Pick FDA hazard classes: I (serious health risk or death), II (temporary or reversible health problems), III (unlikely to cause harm). Leave empty for all.

## `states` (type: `array`):

Enter two-letter US state codes where the recalling firm is located, one per line, e.g. CA or NY. Leave empty for all.

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

Enter the recalling firm's country, one per line, e.g. United States, Canada or India (US and USA also work). Leave empty for all.

## `statuses` (type: `array`):

Pick the statuses to keep, e.g. Ongoing. Leave empty for all.

## `dateFrom` (type: `string`):

Type the first date as YYYY-MM-DD for the date field below. Leave empty to use the last 'Lookback days'.

## `dateTo` (type: `string`):

Type the last date as YYYY-MM-DD. Leave empty for today.

## `dateField` (type: `string`):

Pick which date the range applies to. Keep report_date (when FDA published the recall in its weekly Enforcement Report) for monitoring.

## `lookbackDays` (type: `integer`):

Set how many days back to search when no From date is given, e.g. 30. With 'Only new' the window starts this many days before the previous run, to catch late FDA updates.

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

Turn on for scheduled alerts: only recalls not returned by a previous run with the same filters are returned. The memory is kept in a named key-value store.

## `skipExistingOnFirstRun` (type: `boolean`):

Turn on so the first 'Only new' run saves the recalls already in the window as seen and returns nothing (no charge); alerts start from the next run.

## `stateStoreName` (type: `string`):

Type the key-value store that keeps the 'Only new' memory. Each filter combination gets its own key; change the name to keep separate alert lists.

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

Set the maximum number of recalls to return, newest first, e.g. 100. You pay only for recalls returned.

## `apiKey` (type: `string`):

Paste a free key from open.fda.gov/apis/authentication to raise the limit from 1,000 requests per day per IP (shared on Apify servers) to 120,000. Optional.

## Actor input object example

```json
{
  "categories": [
    "food",
    "drug",
    "device"
  ],
  "companies": [],
  "productKeywords": [],
  "classifications": [],
  "states": [],
  "countries": [],
  "statuses": [],
  "dateFrom": "",
  "dateTo": "",
  "dateField": "report_date",
  "lookbackDays": 30,
  "onlyNew": false,
  "skipExistingOnFirstRun": false,
  "stateStoreName": "fda-recalls-monitor-state",
  "maxItems": 100
}
```

# Actor output Schema

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

Dataset with all results

## `files` (type: `string`):

Key-value store with the files and the OUTPUT summary of the run

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("br_data_hub/fda-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("br_data_hub/fda-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 '{}' |
apify call br_data_hub/fda-recalls-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,br_data_hub/fda-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/KmuCqmj6QiemQ0AjP/builds/0RANXbb7jiZDg6Zqb/openapi.json
