# FDA Recalls: food, drug and device recalls by search term (`steadydata/fda-recalls`) Actor

US product recalls from openFDA by search term, category, class, state and date: product, reason, firm, classification, status, quantity, distribution, lot codes and dates, from the FDA's official enforcement reports. Up to 50 searches a run. Pay per recall.

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

## Pricing

from $0.65 / 1,000 recall listeds

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

## FDA Recalls: food, drug and device recalls by search term

US product recalls from openFDA by search term, category, class, state and date: product, reason, firm, classification, status, quantity, distribution, lot codes and dates, from the FDA's official enforcement reports. Up to 50 searches a run. Pay per recall.

### Why this scraper

- **Only delivered results are charged.** Inputs that fail come back as clear error
  records at no cost.
- Straight from openFDA, the FDA's own API over its weekly enforcement reports, the source every recall tracker copies from. Measured on the platform: 300 food recalls for two search terms in 10 seconds for a quarter of a cent.
- One search covers the product description, the reason and the firm name at once, over food, drugs and devices, so "listeria", "insulin pump" or a company name each work without knowing which field the FDA put it in.
- Every row is complete: recall number, class (I, II, III), status, product, reason, recalling firm with city, state and country, quantity, distribution pattern, lot codes and best-by dates, how the firm notified customers, the initiation, classification, report and termination dates, the event id that groups products of one recall, and a link to the FDA record.
- Filters on class, US state and report date; newest first with a per-search ceiling, so a daily run returns only what is new.

### Who this is for

Put search terms in `queries` (up to 50 per run; `*` lists everything that matches the other filters), choose `categories` (food, drug, device; default all), optionally `classifications`, `states`, `sinceDate` (YYYY-MM-DD) and `maxRecallsPerQuery` (default 100). Built for food safety and quality teams, pharma and medical device compliance, retailers and distributors that check what they stock, insurers, and journalists covering recalls.

### Who this is not for

This is the FDA's enforcement report: US recalls only, and a recall appears here when the FDA classifies it, which can be days to weeks after the firm's own announcement; for same-day press releases use the FDA newsroom. USDA-regulated meat and poultry recalls are not in openFDA. The recalling firm's street address is not copied (city, state and country are). Without your own key the FDA allows 1,000 requests a day per IP address; a run of 50 searches over three categories uses at most 150 plus paging, and `apiKey` lifts the limit for heavy use.

### Input fields

| Field | Type | Required or default | What it does |
|---|---|---|---|
| `queries` | list of text | required | One search per row, up to 50: words in the product description, the reason or the firm name, for example listeria or insulin pump. An asterisk lists everything that matches the other filters. |
| `categories` | list of text |  | food, drug or device. Empty means all three. |
| `classifications` | list of text |  | Class I (serious), Class II or Class III. Empty means every class. |
| `states` | list of text |  | Two-letter codes of the recalling firm's state, for example CA, TX. Empty means every state and country. |
| `sinceDate` | text |  | Only recalls with a report date on or after this date (YYYY-MM-DD). Empty means no date limit. |
| `maxRecallsPerQuery` | number | 100 | Cost ceiling per search and category, newest first. |
| `apiKey` | text | your own key | Your own free key from open.fda.gov raises the FDA's limit from 1,000 to 120,000 requests a day. Leave empty for small runs. |

### Input example

```json
{
    "queries": [
        "listeria",
        "undeclared peanut"
    ],
    "categories": [
        "food"
    ],
    "maxRecallsPerQuery": 100
}
```

### Output example

| Field | Type | What it holds | Example |
|---|---|---|---|
| `recallNumber` | text | The FDA's number of the recall, for example H-1271-2026; H is food, D drugs, Z devices. | `H-1150-2026` |
| `category` | text | food, drug or device, the openFDA endpoint the recall came from. | `food` |
| `classification` | text | Class I is a reasonable probability of serious harm, Class II temporary or reversible harm, Class III unlikely harm. | `Class I` |
| `recallStatus` | text | Ongoing, Completed or Terminated as the FDA marks the recall. | `Terminated` |
| `productDescription` | text | The product as the firm describes it, often with sizes and package codes. | `High Valley Orchard Chocolate Covered Raisins, net wt. 15...` |
| `reasonForRecall` | text | Why the product was recalled, in the firm's or the FDA's words. | `Undeclared Peanut. High Valley Orchard Chocolate Covered...` |
| `recallingFirm` | text | The company that recalls. | `Lehi Valley Trading Company, Inc` |
| `city` | text | The city of the recalling firm as the FDA records it. | `Mesa` |
| `state` | text | The firm's US state as a two-letter code; empty for foreign firms. | `AZ` |
| `country` | text | The country of the recalling firm; foreign firms recall in the US too. | `United States` |
| `productQuantity` | text | How much product is affected, as the firm reports it (cases, units, bags). | `624 plastic 15oz tubs: 585 lbs total` |
| `distributionPattern` | text | Where the product went, in the firm's words: states, nationwide, countries. | `Nationwide, Arizona, Nevada, New Mexico, Texas` |
| `codeInfo` | text | Lot numbers, best-by dates and UDIs that identify the affected units. | `Lot # 0160933 Best by date of Jan 23, 2027` |
| `voluntaryMandated` | text | Whether the firm recalled on its own initiative or the FDA mandated it. | `Voluntary: Firm initiated` |
| `initialFirmNotification` | text | How the firm first told its customers: letter, e-mail, press release, phone. | `E-Mail` |
| `recallInitiationDate` | text | When the firm started the recall. | `2026-06-24` |
| `centerClassificationDate` | text | When the FDA assigned the class; empty until it does. | `2026-07-07` |
| `reportDate` | text | When the recall appeared in the FDA's weekly enforcement report; the rows are sorted on this. | `2026-07-15` |
| `terminationDate` | text | When the FDA closed the recall; only on terminated recalls. | `2026-09-04` |
| `eventId` | text | The FDA event number shared by all products in the same recall event. | `99324` |
| `brandNames` | list | Brand names from the FDA's product database, mostly for drugs and devices; empty when the FDA has no match. |  |
| `url` | text | The recall on the FDA's enforcement report site. | `https://www.accessdata.fda.gov/scripts/ires/index.cfm?Pro...` |
| `query` | text | The search term this row was found with. | `undeclared peanut` |

Error codes: `INVALID_QUERY`, `NO_RESULTS`, `BLOCKED`.

One delivered row looks like this:

```json
{
  "recallNumber": "H-1271-2026",
  "category": "food",
  "classification": "Class II",
  "recallStatus": "Ongoing",
  "productDescription": "Marketside Tomato Bisque Soup Kit, Tomato Bisque with Cheese Croutons & White Cheddar Cheese, Ready to Heat, Net Wt. 14 OZ (397g), with UPC 1 94346474004. Must Keep Refrigerated.",
  "reasonForRecall": "Product had a presumptive positive test result for Listeria monocytogenes",
  "recallingFirm": "CUISINE, KETTLE",
  "city": "Savage",
  "state": "MD",
  "country": "United States",
  "productQuantity": "540 cases",
  "distributionPattern": "The recalled product was distributed to the following States: IL, NV, NM, CA, OK, TX, PA, OH, NC, NY, GA, and AR.",
  "codeInfo": "Best By/ Use By: 8/22/2026",
  "voluntaryMandated": "Voluntary: Firm initiated",
  "initialFirmNotification": "E-Mail",
  "recallInitiationDate": "2026-08-11",
  "centerClassificationDate": "2026-08-26",
  "reportDate": "2026-09-02",
  "terminationDate": null,
  "eventId": "99690",
  "brandNames": [],
  "url": "https://www.accessdata.fda.gov/scripts/ires/index.cfm?Product=H-1271-2026",
  "query": "listeria",
  "status": "ok"
}
```

### Related actors from steadydata

- [eu-safety-gate](https://apify.com/steadydata/eu-safety-gate): the EU's product safety alerts, the European counterpart
- [google-news](https://apify.com/steadydata/google-news): press coverage of a recall or a firm
- [sec-edgar-filings](https://apify.com/steadydata/sec-edgar-filings): what a listed firm told investors about it

### Pricing

Pay per event: one `recall-listed` event per delivered result. No charge for inputs
that fail, no separate platform-usage surcharge.

**Free Apify plan:** this actor delivers up to 25 rows per run for accounts on the Apify free
plan, and then stops with a message. That limit is set by us, not by Apify. It exists so the
actor keeps paying for itself for the people who do pay. Any paid Apify plan runs it at full
size, billed per delivered row, with failed rows never charged.

**Reviews:** if this actor saves you time, a short review on this page is the one thing that
helps most. Ratings are what other buyers look at first, and we have no other way to ask.

### FAQ

**Is personal data collected?**
No. Rows carry the recalling company, its city, state and country, and the product; the street address in the FDA record is not copied.

**How do I get only new recalls every week?**
Run with `sinceDate` set to last week's date and `*` as the search term with your categories or classes. Searches with nothing new come back as a free `NO_RESULTS` row.

**What do Class I, II and III mean?**
The FDA's severity: Class I is a reasonable probability of serious harm or death, Class II temporary or medically reversible harm, Class III unlikely to cause harm. Filter on `classifications` to keep only Class I.

**Why does one event have several rows?**
Because the FDA lists one row per product in a recall; a firm that recalls twelve flavours gets twelve rows with the same `eventId`. Group on it to count events instead of products.

**Do I need an API key?**
Not for normal use. The FDA allows 1,000 requests a day per IP without one; a free key from open.fda.gov raises that to 120,000 and is passed through `apiKey` for heavy daily runs.

**What does a run cost when a search finds nothing?**
Nothing. `NO_RESULTS`, `INVALID_QUERY` and `BLOCKED` rows are free; only delivered recalls are charged.

**What happens when the source changes?**
Sources change from time to time; that is the nature of this work. The actor is
monitored daily and fixed fast, and while it is broken you are not charged, because
only delivered results cost anything.

# Changelog

This Actor's version history is a separate document: https://apify.com/steadydata/fda-recalls/changelog.md

# Actor input Schema

## `queries` (type: `array`):

One search per row, up to 50: words in the product description, the reason or the firm name, for example listeria or insulin pump. An asterisk lists everything that matches the other filters.

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

food, drug or device. Empty means all three.

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

Class I (serious), Class II or Class III. Empty means every class.

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

Two-letter codes of the recalling firm's state, for example CA, TX. Empty means every state and country.

## `sinceDate` (type: `string`):

Only recalls with a report date on or after this date (YYYY-MM-DD). Empty means no date limit.

## `maxRecallsPerQuery` (type: `integer`):

Cost ceiling per search and category, newest first.

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

Your own free key from open.fda.gov raises the FDA's limit from 1,000 to 120,000 requests a day. Leave empty for small runs.

## Actor input object example

```json
{
  "queries": [
    "listeria",
    "undeclared peanut"
  ],
  "categories": [
    "food"
  ],
  "maxRecallsPerQuery": 100
}
```

# Actor output Schema

## `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 = {
    "queries": [
        "listeria",
        "undeclared peanut"
    ],
    "categories": [
        "food"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadydata/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 = {
    "queries": [
        "listeria",
        "undeclared peanut",
    ],
    "categories": ["food"],
}

# Run the Actor and wait for it to finish
run = client.actor("steadydata/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 '{
  "queries": [
    "listeria",
    "undeclared peanut"
  ],
  "categories": [
    "food"
  ]
}' |
apify call steadydata/fda-recalls --silent --output-dataset

```

## MCP server setup

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