# US Product Recall Checker - FDA, NHTSA & CPSC Recalls Lookup (`rolescout/recallscout-us-product-recalls`) Actor

Recall checker and US product recall lookup across FDA (food, drugs, devices), NHTSA (vehicles) and CPSC (consumer products) at once. Active recalls first, severity normalised to one CRITICAL/SERIOUS/MODERATE/LOW scale with the basis stated, plus lot numbers and UPCs. JSON/CSV, pay per query.

- **URL**: https://apify.com/rolescout/recallscout-us-product-recalls.md
- **Developed by:** [Dave Fergins](https://apify.com/rolescout) (community)
- **Categories:** E-commerce, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$30.00 / 1,000 query answereds

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

US product recall lookup as plain JSON or CSV rows: is this product or vehicle under an ACTIVE recall, and how urgent? One lookup searches the FDA (food, drugs, medical devices), NHTSA (vehicle safety campaigns) and CPSC (consumer products) at once, normalises their three different severity schemes onto one CRITICAL / SERIOUS / MODERATE / LOW scale with the basis for each rating stated, and returns the firm, hazard, remedy, lot numbers and UPCs. Active recalls lead; terminated ones are history and off by default. The data is republished from US federal open data and may lag the agencies' own publications; it is factual public-safety information, not legal, medical or compliance advice.

The Actor is a thin client: it sends each lookup you give it to the recall service, charges one event per lookup the service answers, and writes the answer to the dataset as one summary row plus one row per recall, worst first. A run takes seconds and uses 256 MB. You need no API key or account with any agency; the Actor carries its own credential.

### Product recalls across FDA and CPSC: brands, ingredients, consumer goods

A `product` lookup is a product, brand or ingredient matched as a phrase across FDA enforcement reports (food, drugs, devices) and CPSC consumer product recalls. The summary row answers the headline: `recalled` (whether anything ACTIVE matched), `worst_severity` (the worst active rating, NONE when nothing active matched), `action` in plain language, `active_count` (before `limit` trims the list), `complete` (false when an agency could not be reached, which is never an all-clear), `sources_queried`, `sources_failed` when any did, and `lookup`, the query as matched.

Each recall row carries `agency` (FDA, NHTSA or CPSC), the regulator's own `id`, `title`, `product`, `firm`, `reason`, `hazard`, `remedy`, `severity`, `severity_basis` (which regulator signal produced the rating, for example FDA Class I), `action`, `active`, `status` in the regulator's words, `date`, `url` of the recall notice, `codes` (lot numbers, UPCs and date codes: how to tell whether a unit is affected) and `distribution`. `list` is active or ended, `rank` the position worst-first.

### Vehicle recalls from NHTSA: make, model and year

A vehicle lookup is `make`, `model` and `year` together, with no `product`; it searches NHTSA's safety recall campaigns for that model year. NHTSA grades nothing itself but flags "do not drive" and "park outside" campaigns, and those flags set the severity. Set `include_ended` to true to add terminated recalls as history, tagged `list` = ended, with `ended_count` on the summary row. `limit` caps each list (default 10); the counts always report the full totals, and `truncated` is set when a list was cut.

### Several products or vehicles in one run

The top-level fields are the first lookup and the defaults (`include_ended`, `limit`) for every other. Add `products` as a list of products, brands or ingredients for more product lookups with the same settings, or `queries` as a list of objects using the same field names to mix product and vehicle lookups; a `queries` object that names a product or a vehicle does not inherit the top-level one. A run may hold at most 25 lookups, and each lookup the service answers is one billable event.

### Example input

```json
{
    "product": "infant formula",
    "include_ended": false,
    "limit": 10,
    "products": ["peanut butter", "space heater"],
    "queries": [{ "make": "Honda", "model": "Accord", "year": 2020 }]
}
```

That run is four lookups: infant formula, peanut butter and space heaters across FDA and CPSC, and the 2020 Honda Accord in NHTSA's campaigns. Field names are the service's own, so a `queries` object is exactly the lookup it sends. Leave `make`, `model` and `year` empty when you look up a product; a vehicle lookup in `queries` needs all three and no `product`.

### Output: example rows, CSV views and the OUTPUT record

Every row starts with the same eight columns: `scout`, `row_type` (summary or recall), `query_index` (1-based position in the run), `query` (the normalised lookup as sent), `as_of`, `receipt`, `source` (the attribution) and `disclaimer`. Then the row's own fields. A recall row looks like this:

```json
{
    "scout": "recalls",
    "row_type": "recall",
    "query_index": 1,
    "query": { "limit": 10, "product": "infant formula" },
    "as_of": "2026-10-08T18:00:00Z",
    "receipt": "",
    "source": "US FDA (openFDA enforcement), US NHTSA (vehicle safety recalls), US CPSC (saferproducts.gov). Public domain / US Government works.",
    "disclaimer": "Recall data is republished from US federal open data (FDA openFDA, NHTSA, CPSC) ...",
    "list": "active",
    "rank": 1,
    "agency": "FDA",
    "id": "F-0123-2026",
    "title": "Example Infant Formula recall",
    "product": "Example Infant Formula, 12.4 oz",
    "firm": "Example Nutrition Co.",
    "reason": "Potential Cronobacter contamination",
    "hazard": "Serious infection in infants",
    "remedy": "Return for a full refund",
    "severity": "CRITICAL",
    "severity_basis": "FDA Class I: reasonable probability that use will cause serious adverse health consequences or death.",
    "action": "Stop using and act now - the regulator judged this capable of causing serious injury or death.",
    "active": true,
    "status": "Ongoing",
    "date": "2026-07-14",
    "url": "(the recall notice on the regulator's site)",
    "codes": "UPC 0 00000 00000 0; Lot ABC123",
    "distribution": "Nationwide"
}
```

The dataset has two table views: `summary` (one line per lookup) and `recalls` (one line per recall). Filter on `row_type` when you export both as one CSV. The run's `OUTPUT` key-value record holds the service's response for every lookup verbatim, keyed q1, q2, ..., each with the lookup it answered, plus an `errors` map for any lookup that failed.

### Pricing: pay per query answered

One `query-answered` event per lookup the service answered, whatever the number of recalls: one product is one event, ten products is ten events. Rows are never billed individually, so `limit` and `include_ended` change the size of the dataset, not the price. A lookup the service refuses (a product with a vehicle, a vehicle missing its year, the service warming up) is not charged, and the run still succeeds with the lookups that worked; only a run where every lookup failed ends as failed. A lookup that finds no active recall is answered, charged once and writes its summary row with `recalled` false. Price: $0.03 per lookup answered, on every Apify plan. Example: checking three products daily is about 90 lookups a month, $2.70. A daily schedule of ten products is about 300 lookups a month, $9.00.

### Use cases: retail safety checks, supply chain and insurance

- Retail and marketplace safety checks: run your catalogue's product names on a schedule and alert on any summary row where `recalled` turns true or `worst_severity` is CRITICAL.
- Supply chain and procurement: ingredients and components checked across FDA and CPSC in one pass, with lot numbers and UPCs to match against stock.
- Fleet and dealer compliance: every vehicle in the fleet by make, model and year, with NHTSA's do-not-drive and park-outside flags surfaced as severity.
- Insurance and claims: the regulator's own recall number, date, status and notice URL on every row, for the file.
- Spreadsheets and dashboards: export the `recalls` view as CSV or attach Apify's Google Sheets integration so every scheduled run appends its rows.
- AI agents and automations: like any public Actor it can be called through the Apify API, a webhook or Apify's MCP server, with the same input and the same dataset.

### Data sources and attribution

The data is republished from US federal open data: the US FDA (openFDA enforcement reports), the US NHTSA (vehicle safety recalls) and the US CPSC (saferproducts.gov), all public domain / US Government works. Every summary row carries that attribution in `source` and the service's disclaimer verbatim:

> Recall data is republished from US federal open data (FDA openFDA, NHTSA, CPSC) and may lag the agencies' own publications. Severity is normalised across three regulators that grade differently — the basis for each rating is stated so it can be checked. Matching is by product text, so a product may be affected without matching the search terms, and a match does not prove the specific unit in hand is affected: always confirm against the lot numbers, UPCs and date codes in the recall notice. This is factual public-safety information, not legal, medical or compliance advice.

### FAQ

**Which agencies are searched?** The FDA for food, drug and medical device recalls, NHTSA for vehicle safety campaigns and the CPSC for consumer products, in one lookup. `sources_queried` lists the ones consulted for each answer.

**What if an agency is down?** The answer says so: `complete` is false and `sources_failed` names the agency, and `worst_severity` is UNKNOWN rather than NONE when nothing active was found. A lookup that could not consult all three is never reported as an all-clear.

**How is severity normalised?** FDA Class I, II and III, NHTSA's do-not-drive and park-outside flags and the CPSC's prose are mapped onto CRITICAL, SERIOUS, MODERATE and LOW, and every row states the `severity_basis` so the mapping can be checked.

**Does a match mean my unit is affected?** No. Matching is by product text, so a product may be affected without matching your words, and a match does not prove the unit in hand is affected. Confirm against the lot numbers, UPCs and date codes in `codes` and the recall notice.

**Can I get recalls that have ended?** Yes: set `include_ended` to true and terminated recalls are added as history, tagged `list` = ended, with `ended_count` on the summary row.

**Can I check several products or vehicles in one run?** Yes: `products` for more product lookups with the same settings, or `queries` for a list of full lookup objects, mixing products and vehicles. At most 25 lookups per run, one event each.

**Do I need an API key?** No. The Actor carries its own credential for the recall service; you only give it the lookups.

**Why did one lookup fail while the others worked?** The service answers each lookup on its own; one it cannot answer (a product together with a vehicle, a vehicle missing its year, the service warming up) is recorded in the status message and the `OUTPUT` record's `errors` map, skipped without charge, and the rest continue. A lookup the service never answers (unreachable, or a gateway error) is retried once; after two such lookups in a row the remaining ones are skipped rather than waited for.

**What happens with an empty input?** The run succeeds with one unbilled `status` row (`status: needs_input`) that names the missing fields, gives a hint and repeats the example input. Nothing is sent to the service and nothing is charged. Any field that is present must still be valid.

# Actor input Schema

## `product` (type: `string`):

Matched as a phrase across FDA (food, drugs, devices) and CPSC (consumer products) recalls. Required unless make, model and year are given.

## `make` (type: `string`):

For an NHTSA vehicle lookup, e.g. Honda. Needs model and year too, and no product: leave all three empty for a product lookup.

## `model` (type: `string`):

e.g. Accord. Needs make and year too, and no product.

## `year` (type: `integer`):

e.g. 2020. Needs make and model too, and no product.

## `include_ended` (type: `boolean`):

Also return terminated recalls, as history, tagged list = ended. Off by default: only recalls the regulator still considers open are returned.

## `limit` (type: `integer`):

Recalls returned per list (active, and ended when included), worst first. The counts always report the full totals. It changes the dataset size, not the price.

## `products` (type: `array`):

Extra products, brands or ingredients, one lookup each, with include_ended and limit as set above. Each is one billable event; at most 25 queries per run.

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

A list of query objects using the same field names as above, each merged over the top-level fields: mix product and vehicle lookups in one run. At most 25 queries per run in total.

## Actor input object example

```json
{
  "product": "infant formula",
  "include_ended": false,
  "limit": 10,
  "products": [
    "peanut butter",
    "space heater"
  ],
  "queries": [
    {
      "make": "Honda",
      "model": "Accord",
      "year": 2020
    },
    {
      "product": "eye drops",
      "include_ended": true
    }
  ]
}
```

# Actor output Schema

## `rows` (type: `string`):

Summary and recall rows for every lookup, with the query object on each.

## `summary` (type: `string`):

One line per lookup: the headline. Filter on row_type = summary.

## `recalls` (type: `string`):

One line per recall, worst first per lookup. Filter on row_type = recall.

## `answers` (type: `string`):

The service's response for each lookup verbatim, keyed q1, q2, ..., plus an errors map for any lookup that failed.

# 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 = {
    "product": "infant formula",
    "limit": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("rolescout/recallscout-us-product-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 = {
    "product": "infant formula",
    "limit": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("rolescout/recallscout-us-product-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 '{
  "product": "infant formula",
  "limit": 10
}' |
apify call rolescout/recallscout-us-product-recalls --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rolescout/recallscout-us-product-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/GDsgjRXcCJjdo4aGZ/builds/v8R4AnobSu9htW8So/openapi.json
