# Recall Watch: FDA, CPSC & NHTSA (Unofficial) (`saiberops/product-recall-watch`) Actor

New FDA (drug, device, food), CPSC and NHTSA recalls in one clean feed: firm and role, product, UPC/NDC/model, hazard, class, remedy, units. Firm and UPC watchlist, new-since-last-run mode. Unofficial; no API key needed.

- **URL**: https://apify.com/saiberops/product-recall-watch.md
- **Developed by:** [Saiber Operations](https://apify.com/saiberops) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 recall returneds

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 Recall Watch (Unofficial): FDA, CPSC and NHTSA Recalls in One Feed

Know the day a product you make, sell or insure is recalled. This Actor pulls **new recalls from three U.S. agencies** and returns them in **one normalized format**: FDA drug, medical-device and food enforcement reports, CPSC consumer-product recalls, and NHTSA vehicle, equipment, tire and child-seat recalls. Each row names the **firms and their roles** (recalling firm, manufacturer, importer, distributor, retailer), the product, its **UPC, NDC, model or vehicle** identifiers, the hazard or FDA class, units affected, the remedy and a link back to the agency record.

Add your suppliers, brands or catalog codes to the **watchlist** and every matching recall is flagged. Run it on a schedule with **New since last run** and each run returns only recalls you haven't seen.

**Built for:**

- **Retailers and marketplaces:** match recalled UPCs and model numbers against your catalog and pull listings fast.
- **Quality, compliance and supplier-risk teams:** watch your suppliers, contract manufacturers and your own brands across agencies.
- **Product-liability law firms, insurers and claims teams:** a daily list of new recalls with firms, hazards, units and injury counts.
- **Trade press and analysts:** one clean feed instead of three agency formats.
- **AI agents and data teams:** clean JSON, no API key, no login.

### Sample output

```json
{
  "agency": "CPSC",
  "feed": "cpsc",
  "recallId": "27012",
  "title": "Aria Child Recalls Strollers Due to Laceration and Fall Hazards",
  "productCategory": "consumer product",
  "productType": "Strollers",
  "productNames": ["Qbit strollers"],
  "reportDate": "2026-10-16",
  "hazard": "A gap in the stroller's folding side hinge can pinch a child's finger, posing a laceration hazard.",
  "hazardTypes": ["Laceration"],
  "recallingFirm": "Aria Child Inc.",
  "firms": [
    {"name": "Aria Child Inc.", "role": "importer"},
    {"name": "Example Baby Depot Inc.", "role": "retailer"}
  ],
  "manufacturerCountries": ["China"],
  "upcs": ["070847001232", "070847001249"],
  "modelNumbers": ["QB-100, QB-110"],
  "unitsAffected": 29400,
  "remedy": "Consumers should immediately stop using the recalled strollers and contact Aria Child for a free repair kit.",
  "remedyOptions": ["Repair"],
  "incidentCount": 71,
  "injuryCount": 5,
  "sourceUrl": "(link to the recall page on cpsc.gov)",
  "watchlistMatch": true,
  "watchlistMatches": ["firm: Aria Child"],
  "attribution": "Data provided by the U.S. Consumer Product Safety Commission"
}
```

(Illustrative example; field list abbreviated.) FDA rows add the **FDA class** (I, II or III), status, recall start date, lot and code information, distribution and the recalling firm's city, state and ZIP. NHTSA rows list the **vehicles** (make, model, year), model-year range, component, production dates, owner-notification date and the manufacturer's campaign number.

### Inputs

- **What to fetch:** the last N days (default 30), **New since last run** for a schedule, or a fixed date range of up to a year.
- **Agencies and feeds:** FDA drugs, FDA devices, FDA food, CPSC and NHTSA. All are on by default.
- **Firm watchlist:** company names; matching ignores case, punctuation and words like Inc or LLC.
- **UPC, NDC and model watchlist:** UPCs or GTINs (leading zeros and check digit optional), NDCs and model numbers.
- **Only return watchlist matches:** turn the feed into an alert list.
- **FDA classes** and **keywords** to narrow the feed.
- **Max recalls** (default 50). When there are more, each feed gets a fair share.
- **Advanced:** which date the window uses (published, or published or updated), cursor name, records read per feed, and your own openFDA key (optional; not needed).

**Quick start:** keep the defaults and click **Start** to see the last 30 days from all three agencies. For alerts, add your suppliers or catalog codes to the watchlists, choose **New since last run**, and schedule the Actor daily. Results appear in the **Recalls**, **Products, firms and codes**, **Hazards and remedies**, **Vehicles (NHTSA)** and **Watchlist** tabs, newest first. The **Watchlist** tab lists every returned recall with its `watchlistMatch` column (true when the recall matches your watchlist, and `watchlistMatches` says which entry matched); Apify tabs can't hide rows, so sort on that column, or turn on **Only return watchlist matches** to get matches only. Each run also saves a **run summary** with the status of every source.

### Pricing

Pay per event: you pay only for recalls returned.

| Event | Free plan | Bronze | Silver | Gold |
|---|---|---|---|---|
| Recall returned | $0.0036 | $0.003 | $0.0027 | $0.0024 |
| Watchlist match (add-on) | $0.012 | $0.01 | $0.009 | $0.008 |

That's $2.40–$3.60 per 1,000 recalls, plus Apify's standard Actor start fee. The watchlist add-on is charged only for returned recalls that match **your** watchlist; with an empty watchlist it is never charged. Recalls removed by your filters, recalls already returned (in "New since last run"), sources that fail and runs that fail are **not charged**. Set **Max cost per run** to cap spending; the Actor stops cleanly at the cap, and stops before a watchlist match when what is left would not cover both the recall and the add-on.

### Integrations and API

Schedule it in Apify and send new recalls or watchlist matches to Google Sheets, Slack, email, Make, Zapier or n8n through Apify's integrations, or call it from the Apify API. AI agents can use it through Apify's MCP server.

### Limits

- **FDA publishes weekly.** openFDA's enforcement data is updated once a week, so FDA rows arrive in weekly batches and a 1-day window often has no FDA rows. Use 14 days or more.
- **NHTSA file size.** NHTSA recalls come from the agency's daily flat file (about 14 MB, covering reports from 2010 on). Each run downloads it once and keeps only the window; this takes a few seconds. Recalls reported before 2010 are not covered.
- **NHTSA posting lag.** By default an NHTSA recall is dated by its report date (when NHTSA received the manufacturer's report), but it reaches NHTSA's file days or sometimes weeks later. A recall posted late can therefore fall before a short window. For **New since last run**, keep **Days to look back** at 30 or more, or set **Which date the window uses** to **Published or updated in the window**, which dates NHTSA rows by the day they were added to the file.
- **No VIN ranges.** NHTSA's file lists makes, models, model years and production dates, not VIN ranges.
- **CPSC injury details are counts only.** The Actor reads the number of incidents, injuries and deaths from CPSC's text and never returns the narrative. Counts are left empty when the text gives no clear number.
- **UPCs inside FDA text.** FDA rows carry UPCs only when the FDA text or openFDA's drug labeling lists them, and only barcodes with a valid check digit are kept.
- **Shared FDA limit.** Without a key, openFDA allows a limited number of requests per day per network address. The Actor makes one request per FDA feed for a normal run and stops that source cleanly if openFDA says the limit is reached; CPSC and NHTSA rows are still returned.
- A date range covers up to 366 days per run. Each feed reads up to **Max records to read per feed** records in the window.

### FAQ

**Why do FDA recalls show up a week or more after they started?** FDA lists a recall in its weekly enforcement report once it has been classified, which can be weeks after the firm began the recall. The row carries both dates: `reportDate` (published) and `recallDate` (started).

**What does "New since last run" remember?** The recalls it returned under the cursor name, for the length of your look-back window. Use a separate cursor name for each watch you schedule.

**Are phone numbers, emails or people's names included?** The Actor never returns contact blocks (CPSC's consumer contact details, NHTSA's notes), injury narratives or person-name fields. Phone numbers and emails inside other text are replaced with "\[removed]", and in distribution, lot-code and corrective-action text, sentences that point to a contact are dropped. Text that names a person by title (such as "Mr.") or in a court-case caption is blanked. Firm addresses are limited to city, state, ZIP and country. An FDA or CPSC recall whose firm name looks like a private person's name (no business word such as Inc, LLC or Foods) is left out, and other person-like names are removed from the firm list. NHTSA firms are the manufacturers that filed the recall with NHTSA, so they are always kept.

**What do the firm roles mean?** They come from the agency: FDA names the recalling firm (and, for drugs, the labeler); CPSC lists manufacturers, importers, distributors and retailers; NHTSA names the manufacturer that filed the recall.

**How does UPC matching work?** Digits are compared with leading zeros removed, and a code typed without its last (check) digit still matches. A product-level NDC matches its package NDCs.

### Data sources and responsible use

Data comes from three public U.S. government sources: openFDA's drug, device and food enforcement endpoints (CC0); the CPSC Recalls web service on SaferProducts.gov; and NHTSA's recalls flat file. Data provided by the U.S. Food and Drug Administration. Data provided by the U.S. Consumer Product Safety Commission. Data provided by the U.S. National Highway Traffic Safety Administration. The Actor identifies itself with a company name and contact email, paces its requests, retries server errors, and stops using a source for the rest of the run if that source signals throttling or refuses access. Output is limited to business-entity and product facts. This is an **unofficial** tool, **not affiliated with** or endorsed by the FDA, CPSC, NHTSA or any U.S. government agency. Agency data can contain errors and can change after publication; always check the agency's own record before acting on a recall.

### Support

Found a bug or need a field? Open an issue on this Actor's **Issues** tab and we'll respond there.

*Maintained by Saiber Operations LLC.*

# Changelog

This Actor's version history is a separate document: https://apify.com/saiberops/product-recall-watch/changelog.md

# Actor input Schema

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

latest: recalls from the last N days. newSinceLastRun: only recalls your previous runs didn't return (use it on a schedule). dateRange: a fixed start and end date (up to 366 days per run).

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

For 'latest' and 'newSinceLastRun'. Calendar days including today. FDA publishes its enforcement report weekly, so use at least 14 days; 30 is a good default.

## `startDate` (type: `string`):

First date to include, YYYY-MM-DD.

## `endDate` (type: `string`):

Last date to include, YYYY-MM-DD. Defaults to today.

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

FDA drug, device and food enforcement reports, CPSC consumer-product recalls and NHTSA vehicle, equipment, tire and child-seat recalls. All are selected by default.

## `watchFirms` (type: `array`):

Company names to flag: suppliers, brands, your own company or competitors. Matching ignores case, punctuation and words like Inc or LLC, so 'Acme' also matches 'ACME Foods, Inc.'. Checks every firm on the recall (recalling firm, manufacturer, importer, distributor, retailer) and vehicle makes.

## `watchCodes` (type: `array`):

Product codes to flag: UPCs or GTINs (leading zeros and check digit optional), NDCs (product or package level) and model numbers. Paste your catalog's codes to see which recalls touch what you sell.

## `watchlistOnly` (type: `boolean`):

Return only recalls that match your firm or code watchlist. Each match also costs the watchlist add-on (see Pricing).

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

Keep only these FDA recall classes (Class I is the most serious). Leave empty for all. Does not affect CPSC or NHTSA recalls.

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

Keep recalls whose title, product, reason, hazard, component or firm names contain any of these words, for example peanut, lithium, airbag. Leave empty for all.

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

The run stops after this many recalls. When there are more, each agency gets a fair share. Each returned recall is one charged event.

## `dateBasis` (type: `string`):

reportDate: when the recall was published (FDA report date, CPSC recall date, NHTSA report date). lastUpdated: when CPSC last republished it or NHTSA added it to its file, which also catches updated recalls. FDA always uses its report date.

## `cursorName` (type: `string`):

Keeps a separate 'new since last run' position per name, so different scheduled watches (for example one per client) don't share one. Letters, numbers and dashes.

## `maxRecordsPerSource` (type: `integer`):

When filters, the watchlist-only option or 'new since last run' are on, each feed reads up to this many records in the window before filtering.

## `openFdaApiKey` (type: `string`):

Not needed: the Actor works without a key. Add your own free openFDA key only if you run very large or very frequent jobs. It is stored encrypted and sent only to api.fda.gov.

## Actor input object example

```json
{
  "mode": "latest",
  "lookbackDays": 30,
  "sources": [
    "fda-drug",
    "fda-device",
    "fda-food",
    "cpsc",
    "nhtsa"
  ],
  "watchFirms": [],
  "watchCodes": [],
  "watchlistOnly": false,
  "fdaClassifications": [],
  "keywords": [],
  "maxItems": 50,
  "dateBasis": "reportDate",
  "cursorName": "",
  "maxRecordsPerSource": 1000
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "watchFirms": [],
    "watchCodes": [],
    "keywords": [],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("saiberops/product-recall-watch").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 = {
    "watchFirms": [],
    "watchCodes": [],
    "keywords": [],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("saiberops/product-recall-watch").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 '{
  "watchFirms": [],
  "watchCodes": [],
  "keywords": [],
  "maxItems": 50
}' |
apify call saiberops/product-recall-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,saiberops/product-recall-watch"
        }
    }
}
```

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/wgnaudLw7TXfOgjOd/builds/eeuCiNUcseBeYfowt/openapi.json
