# FDA Recalls Scraper (Food, Drug, Device) (`hamsmoothie/fda-recalls`) Actor

Latest FDA recall and enforcement reports from openFDA: product, reason, classification, firm, state, distribution and dates. Filter by product type, status, state and keyword.

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

## Pricing

$5.00 / 1,000 result rows

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

## FDA Recalls Search: Food, Drug and Device Recall Data (openFDA)

**FDA Recalls Search** pulls FDA recall and enforcement reports straight from the official openFDA enforcement API and returns one clean row per recall: product description, reason for recall, classification (Class I, II or III), recalling firm, city and state, distribution pattern, quantity, code info, status and the initiation, report and classification dates. Filter by product type (food, drug, device), status, keyword, the recalling firm's state, and how recent the recall is. It needs no API key and uses only public FDA data.

### Input

Every field is optional. This example finds ongoing food and drug recalls from the last 120 days that mention "undeclared milk":

```json
{
  "productTypes": ["food", "drug"],
  "status": "Ongoing",
  "keyword": "undeclared milk",
  "states": ["CA", "TX"],
  "sinceDays": 120,
  "maxResults": 250
}
```

- `productTypes`: any mix of `food`, `drug`, `device` (default `["food"]`).
- `status`: `Ongoing`, `Completed`, `Terminated`, or empty for all (default `Ongoing`).
- `keyword`: matched against the product description and the reason for recall (for example `listeria`, `undeclared peanut`, `sterility`).
- `states`: two-letter codes of the recalling firm's state. Empty means all states.
- `sinceDays`: only recalls initiated in the last N days; `0` means any time (default 90).
- `maxResults`: stop after this many rows (default 500, maximum 20000).

### Output

One row per recall, newest first. Example row:

```json
{
  "productType": "food",
  "recallNumber": "H-1395-2026",
  "eventId": "99874",
  "status": "Ongoing",
  "classification": "Class I",
  "product": "Fromagerie Coop de Mean Cabricharme and Belgium Cabricharme ... Whole Foods Market scale label PLUs: 54670, 57953",
  "reason": "Undeclared Egg Allergen",
  "recallingFirm": "WFM Purchasing, LP",
  "city": "Austin",
  "state": "TX",
  "country": "United States",
  "distribution": "CA, AZ, NJ, MA, RI, CT, NY",
  "quantity": "21 Wheels",
  "codeInfo": "Shelf life: 30 days, all dates through and including 10/7/2026",
  "voluntaryOrMandated": "Voluntary: Firm initiated",
  "initiatedOn": "2026-09-08",
  "reportedOn": "2026-09-30",
  "classifiedOn": "2026-09-22"
}
```

Download the dataset as JSON, CSV, Excel or XML, or call it from the Apify API.

### Use cases

Search phrases this actor is built for:

- **"FDA recalls by keyword"**: set `keyword` to `listeria`, `undeclared peanut` or `sterility` and get every matching recall.
- **"Look up an FDA food recall by product name"**: put the product or brand in `keyword` with `productTypes: ["food"]`.
- **"FDA drug and device recall enforcement reports"**: set `productTypes` to `["drug", "device"]` and filter by status.

Typical users are food distributors, pharmacies, retailers, QA and compliance teams, lawyers and journalists. Schedule a daily run with `sinceDays: 7` to send new recalls to Slack, email or a spreadsheet.

### Pricing

Pay per result: each recall row returned is one billable result, listed at $0.005 per row ($5 per 1,000). Set a maximum charge on the run for a hard ceiling.

### Limits

- Data comes from the openFDA enforcement endpoints. The FDA posts weekly enforcement reports, usually on Wednesdays, so very new recalls can lag.
- openFDA caps paging at 26,000 records per query; use filters or `sinceDays` for bigger pulls.
- `maxResults` is capped at 20,000 per run. `productTypes` accepts only food, drug and device.
- This is a data feed, not medical, legal or safety advice. Check the FDA site for official notices.

### FAQ

**Does it need an API key?** No. It reads the public openFDA API.

**Which recalls does it cover?** FDA enforcement report recalls for food, drugs and medical devices, including Class I, II and III classifications.

**Can I get only new recalls every day?** Schedule the actor daily with a small `sinceDays` value and compare on `recallNumber`.

# Actor input Schema

## `productTypes` (type: `array`):

food, drug, device (any combination).

## `status` (type: `string`):

Ongoing, Completed, Terminated, or empty for all.

## `keyword` (type: `string`):

Matches product description and reason for recall, e.g. listeria, undeclared peanut, sterility.

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

Two-letter codes of the recalling firm's state, e.g. CA, TX. Empty = all.

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

Only recalls initiated in the last N days. 0 = any time.

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

Stop after this many recalls.

## Actor input object example

```json
{
  "productTypes": [
    "food"
  ],
  "status": "Ongoing",
  "states": [],
  "sinceDays": 90,
  "maxResults": 500
}
```

# Actor output Schema

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

All recalls found, one row each; download as JSON, CSV or Excel.

# 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("hamsmoothie/fda-recalls").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("hamsmoothie/fda-recalls").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 hamsmoothie/fda-recalls --silent --output-dataset

```

## MCP server setup

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

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/k6skF1RrhsDskzC71/builds/otZHFL5cXXs4TCwyr/openapi.json
