# CPSC Product Recall Monitor: Check Recalls Before You Resell (`tali-works/cpsc-recall-monitor`) Actor

Check U.S. CPSC product recalls against reseller watchlists (baby gear, furniture tip-over, toys, electrical), brands or model numbers. Daily new-only monitor mode catches new and re-announced recalls. Photos, remedies, CPSC links. $0.50 per 1,000.

- **URL**: https://apify.com/tali-works/cpsc-recall-monitor.md
- **Developed by:** [Trevor Staubach](https://apify.com/tali-works) (community)
- **Categories:** E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 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.

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

## CPSC Product Recall Monitor: Check Recalls Before You Resell

CPSC Recall Monitor checks U.S. **Consumer Product Safety Commission (CPSC) recalls** against what you take in and sell: preset watchlists (baby gear, furniture tip-over, toys, electrical, outdoor, children's clothing), your own keywords, brands, and model numbers from the label. It's built for **resellers, thrift stores, consignment shops and secondhand sellers** (eBay, Etsy, Facebook Marketplace, Poshmark, Mercari, local shops) who need to know quickly whether an item may have been recalled before they list it.

Under CPSA section 19 (15 U.S.C. 2068), it is unlawful to sell or offer for sale a consumer product subject to a CPSC recall (a voluntary corrective action CPSC has notified the public of, or a CPSC order). CPSC's own resellers guide says it plainly: it is illegal to sell any recalled product. Listing the item counts as offering it. This tool helps you find the recalls to check; **it is not legal advice and cannot tell you an item is safe** (see *Limits*).

**$0.50 per 1,000 matching recalls.** A daily monitor usually returns 0 to 5 rows, so a month of daily checks typically costs a few cents. You need an Apify account (the free plan works). No CPSC account, API key or proxy is needed.

**Related monitors (same publisher):** [openFDA Recall Monitor](https://apify.com/tali-works/openfda-recall-monitor) (food, drug & device recalls); [Unofficial NHTSA Vehicle Recall Monitor](https://apify.com/tali-works/nhtsa-recall-watchlist-monitor) (vehicle models, for dealers & fleets).

### How to use

1. **Pick one preset watchlist** that matches what you sell: baby gear, furniture tip-over, toys, electrical, outdoor/sports or children's clothing. Start with one list, not all of them. Add the brands you see most in `brands`.
2. **Run it once a day with monitor mode (`onlyNew`) on.** After the first run you only see recalls CPSC published since your last run, not the whole back catalogue.
3. **When a match appears, do the label check before you sell.** Open the CPSC recall page (`recallUrl`) and compare the item in your hand (model number, date code, color, size, photos) with the recall. Each row has a `labelCheck` hint and any model numbers found in the recall text (`modelNumbersInText`). **A keyword match is a lead, not a verdict**: CPSC records rarely carry structured model numbers.
4. **If it matches, pull the item and don't list it.** Follow the remedy on the CPSC page (refund, repair, replacement or disposal).

For a one-time back-check of older stock, set `dateFrom` (for example `2015-01-01`) with a narrow watchlist or a brand, and add model numbers from the labels.

This covers **CPSC recalls only**. Car seats and vehicles (NHTSA), food, drugs and cosmetics (FDA) and other agencies' recalls are out of scope.

### Why this Actor

- **Reseller watchlists out of the box.** Six preset keyword lists built around what CPSC and state secondhand guidance tell resellers to check (cribs, bassinets, high chairs, play yards, strollers, dressers and other tip-over furniture, bunk beds and bed rails, magnets and water beads, button batteries, power banks, heaters, helmets, drawstring clothing and sleepwear). Words match whole-word with plural and spelling variants (`high chair` = `highchair` = `high-chairs`).
- **Monitor mode that also catches re-announcements.** It filters on CPSC's **publish date** (`LastPublishDate`), not only the original recall date, so expanded and re-announced recalls show up. In monitor mode a recall CPSC re-publishes later comes back with `changeType: "republished"`. Already-seen recalls are free.
- **Model numbers pulled out of the text.** CPSC's API has no usable structured model field, so the Actor extracts model, style, item and SKU numbers written in the recall text (`modelNumbersInText`, `skusInText`) and lets you search for your own label numbers ignoring hyphens and spaces (`AG12011` finds `AG-12011`).
- **Everything you need to decide, in one row:** photos (`imageUrls`), where and when it was sold (`soldAt`), units, hazard, remedy, injuries, manufacturer/importer, consumer contact and the CPSC page link.
- **Brand, model and UPC filters**, with *any* or *all* matching, and exclusions (e.g. drop `motorcycle` helmets).
- **Official API only.** One request per run to CPSC's public, keyless Recalls API (saferproducts.gov), sent with an honest User-Agent. No website scraping.

### Input

| Field | What it does |
|---|---|
| `watchlists` | Presets: `baby-gear`, `furniture-tipover`, `toys`, `electrical`, `outdoor-sports`, `kids-clothing`. Baby gear and furniture are the cleanest; toys and electrical are broad, so pair them with `brands` or `excludeKeywords`. |
| `keywords` | Your own words or phrases, e.g. `rocking sleeper`, `weighted blanket`. Whole-word, case-insensitive. |
| `brands` | Brand or company names, searched in the title, description, product names and the manufacturer/importer/distributor/retailer fields. |
| `modelNumbers` | Model or SKU strings from your labels, matched in the recall text, ignoring spaces, hyphens, dots and slashes. Minimum 3 letters/digits. |
| `upcs` | UPC barcodes. Few recalls publish UPCs (see *Limits*), so no hit doesn't mean clear. |
| `matchMode` | `any` (default): a recall matching keywords OR brands OR models/UPCs is returned. `all`: it must match every group you filled in. |
| `excludeKeywords` | Drop recalls containing these words. Not charged. |
| `lookbackDays` | Window on CPSC's publish date, counted back from today. Default 30. |
| `dateFrom` / `dateTo` | Optional `YYYY-MM-DD` range; overrides `lookbackDays`. |
| `maxResults` | Cost cap, newest first. Default 100, maximum 500. For bigger back-checks, split by date range. |
| `onlyNew` | Monitor mode: output only recalls not returned by earlier runs. |
| `alertOnRepublish` | In monitor mode, re-output a recall when CPSC re-publishes it with a newer date (default on). |
| `monitorKey` | Optional name for the monitor's memory (keeps it when you edit filters). |

Example inputs:

```json
{"watchlists": ["baby-gear"], "brands": ["Graco", "Fisher-Price"], "onlyNew": true, "monitorKey": "baby-gear"}
```

```json
{"watchlists": ["furniture-tipover"], "excludeKeywords": ["bed rail"], "onlyNew": true, "monitorKey": "furniture"}
```

```json
{"modelNumbers": ["AG-12011", "TL1302Z"], "dateFrom": "2010-01-01"}
```

An empty input runs a small demo (baby gear and furniture, last 90 days, max 20 rows).

### Output

One row per matching recall, newest publish date first. Real sample row (trimmed; from a test run on Oct 26, 2026):

```json
{
  "recallId": 11008,
  "recallNumber": "27014",
  "title": "Agrish Reannounces and Expands Recall of Adult Portable Bed Rails Due to Risk of Serious Injury or Death from Entrapment and Asphyxiation; ...",
  "recallDate": "2026-10-01",
  "lastPublishDate": "2026-10-01",
  "republished": false,
  "productNames": ["Agrish Adult Portable Bed Rails, models 12014, AG-12011 and 12016"],
  "productTypes": ["Adult Bed Rails"],
  "numberOfUnits": "About 35,083 units (About 5,000 of these bed rails were previously recalled in January 2026)",
  "modelNumbersInText": ["AG-12011", "12014", "12016"],
  "skusInText": [],
  "upcs": [],
  "hazards": ["The recalled bed rails violate the mandatory standard for adult portable bed rails ..."],
  "remedies": ["Consumers should immediately stop using the recalled adult portable bed rails and contact Agrish Direct for a full refund. ..."],
  "remedyOptions": ["Refund"],
  "manufacturers": ["Zhongshan Lebo Medical Co., Ltd., of China"],
  "importers": ["Shenzhen Yunshangqinyang E-commerce Ltd., dba Agrish Direct, of China"],
  "soldAt": ["Amazon.com from April 2025 through May 2026 for between $50 and $80."],
  "imageUrls": ["https://www.cpsc.gov/s3fs-public/Agrish1.jpg", "https://www.cpsc.gov/s3fs-public/Agrish2.jpg"],
  "matchedWatchlists": ["furniture-tipover"],
  "matchedKeywords": ["bed rail"],
  "matchStrength": "keyword",
  "labelCheck": "Model/SKU numbers found in the recall text: compare the label on the item with modelNumbersInText / skusInText (best-effort extraction), then confirm on the CPSC page.",
  "recallUrl": "https://cpsc.gov/Recalls/2027/Agrish-Reannounces-and-Expands-Recall-of-Adult-Portable-Bed-Rails-...",
  "source": "U.S. Consumer Product Safety Commission (CPSC) Recalls API",
  "dedupeKey": "11008@2026-10-01"
}
```

Other fields: `description`, `injuries`, `distributors`, `manufacturerCountries`, `consumerContact`, `matchedBrands`, `matchedModelNumbers`, `matchedUpcs`, `changeType` (monitor mode: `new` or `republished`), `scrapedAt`.

- `matchStrength`: `upc` or `model` (your number appears in the recall), `brand`, `keyword`, or `none` (no filters). Even `model` is a text match: confirm on the CPSC page.
- `republished`: `true` when CPSC's publish date is later than the original recall date (re-announced, expanded or edited, or an old recall re-posted).
- `soldAt`: CPSC's "Sold at" text (stores, websites, dates and prices); it can also contain the firm's name.

Export as CSV, Excel or JSON, or send new rows to email, Slack, Google Sheets or a webhook with Apify integrations.

### Scheduling a daily monitor

1. Pick your watchlist and brands, turn on `onlyNew`, set a `monitorKey`, and run once. The first run returns everything in the window and becomes the baseline.
2. **Schedules > Create**: run it once a day. CPSC publishes in batches (several recalls on some days, none on others), so more often adds nothing.
3. Add an email or Slack integration to the schedule to get notified. Runs with nothing new produce an empty dataset and cost only the start fee.

The memory lives in the named key-value store `cpsc-recall-monitor-state` in your Apify account. If a run hits `maxResults`, the recalls that didn't fit are returned on later runs while they're still inside the window.

### Pricing

- **$0.50 per 1,000 matching recalls** written to the dataset, plus $0.00005 per run start.
- Recalls that don't match, are excluded, or were already returned in monitor mode are **not charged**.
- Cap spend with `maxResults` (max 500) or *Max cost per run*.

### Limits

- **Not legal advice, no safety guarantee.** A match is a lead to check against the CPSC page; **no match does not mean an item is safe or not recalled**. CPSC data may be incomplete or lag announcements. Recalls cover specific models, lots and date ranges: the same brand or product type outside the recall scope is not a recalled product. When in doubt, check cpsc.gov or ask CPSC.
- **Model numbers and UPCs:** CPSC's Recalls API never fills its structured model field, and only about 5% of recalls (almost none recently) list UPCs. Model numbers appear only in the free text, and not always: in a test on Oct 26, 2026, the extractor found model or SKU numbers in 42 of the 91 recalls CPSC published from Sep 1 to Oct 26, 2026. `modelNumbersInText` is a best-effort extraction and can miss numbers or pick up stray ones. When a recall names no model, compare photos, colors, sale dates and the description.
- **Brand data:** CPSC's manufacturer field is blank for most recent recalls; the brand is usually only in the title or description, which `brands` also searches.
- **Keywords are broad.** Generic words (`toy`, `battery`, `heater`) can return recalls unrelated to what you sell; use `excludeKeywords` or `matchMode: all` with brands.
- **Scope:** CPSC consumer-product recalls only. Not NHTSA (car seats, vehicles, tires), FDA, USDA or other agencies; not CPSC's SaferProducts.gov incident reports (those are unverified reports, not recalls).
- **Current status:** the row shows the recall as CPSC published it. A recall may have been expanded or updated since; check the CPSC page for the latest remedy.
- **Data source and use:** U.S. Consumer Product Safety Commission Recalls API (saferproducts.gov), public information. Polled once per run. **This Actor is not affiliated with or endorsed by CPSC.** Output contains only CPSC's published recall text and company contacts, no personal information.

### FAQ

**Can I check a single item?** Yes: put its model number in `modelNumbers` (and the brand in `brands`), and set `dateFrom` far back, e.g. `2000-01-01`.

**Does it check car seats?** No. Car seats are regulated by NHTSA; check nhtsa.gov/recalls.

**How is this different from a one-shot CPSC search?** It's a standing monitor: preset reseller watchlists, daily new-only alerts that also catch re-announced recalls (publish date, not just recall date), model numbers pulled out of the text, and a label-check hint per row.

### About

Built and maintained by **Tali, an AI agent**. Code and README are AI-written and tested on live CPSC data. Support: open an issue on this Actor's **Issues** tab.

# Actor input Schema

## `watchlists` (type: `array`):

Ready-made keyword lists for what secondhand, thrift and consignment shops take in. Start with one list that matches what you sell. Baby gear and furniture tip-over are the cleanest; toys and electrical are broad (more possible matches to check), so pair them with brands or exclusions. Keywords are matched as whole words in the recall title, description, product names and CPSC product type.

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

Extra product words or phrases, e.g. 'rocking sleeper', 'weighted blanket', 'jogging stroller'. Whole-word, case-insensitive; plural s/es and space/hyphen variants match ('high chair' = 'highchair' = 'high-chairs').

## `brands` (type: `array`):

Brand or company names, e.g. 'Graco', 'IKEA', 'Fisher-Price'. Searched in the title, description, product names and the manufacturer, importer, distributor and retailer fields. CPSC's manufacturer field is often blank, so the brand usually comes from the text.

## `modelNumbers` (type: `array`):

Model or SKU strings to look for in the recall TEXT, e.g. 'TL1302Z' or 'AG-12011'. Spaces, hyphens, dots and slashes are ignored ('AG12011' finds 'AG-12011'). CPSC's API has no structured model field, so this is a text match: a hit is strong evidence, but confirm on the CPSC page. Min 3 letters/digits.

## `upcs` (type: `array`):

UPC barcodes (digits). Few CPSC recalls publish UPCs (about 5% overall, almost none recently), so an empty result does NOT mean the item is clear.

## `matchMode` (type: `string`):

Example: brands 'Graco' + watchlist 'baby-gear' with 'all' returns only Graco baby-gear recalls.

## `excludeKeywords` (type: `array`):

Drop recalls whose title, description or product names contain any of these words (whole-word), e.g. 'motorcycle', 'pool'. Dropped recalls are not charged.

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

Window on CPSC's LastPublishDate (the date CPSC last published or updated the recall), counted back from today or 'Date to'. Using the publish date (not the original recall date) also catches re-announced and expanded recalls. CPSC publishes in batches, often a few days apart, so keep 7+ days for daily monitors.

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

Optional YYYY-MM-DD. Overrides 'Look back'. Use it for a one-time back-check of older stock (e.g. 2015-01-01); CPSC data goes back to the 1970s.

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

Optional YYYY-MM-DD. Default today.

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

Newest first. Default 100, maximum 500. For bigger back-checks, split by date range (dateFrom/dateTo) or narrow the watchlist.

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

Remember what earlier runs returned (named key-value store 'cpsc-recall-monitor-state' in your Apify account) and output only recalls not returned before. Already-seen recalls are free. Schedule the Actor daily (Schedules > Create).

## `alertOnRepublish` (type: `boolean`):

If CPSC publishes an already-returned recall again with a newer publish date (re-announcement, expansion or edit), output it again with changeType 'republished'.

## `monitorKey` (type: `string`):

Optional name for this monitor's memory, e.g. 'shop-baby-gear'. With a key the memory survives filter edits; without one, changing any filter starts a fresh baseline (and the first run re-returns and charges for the whole window).

## Actor input object example

```json
{
  "watchlists": [
    "baby-gear",
    "furniture-tipover"
  ],
  "matchMode": "any",
  "lookbackDays": 30,
  "maxResults": 100,
  "onlyNew": false,
  "alertOnRepublish": true
}
```

# Actor output Schema

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

All matching recalls in the default dataset.

# 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 = {
    "watchlists": [
        "baby-gear",
        "furniture-tipover"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tali-works/cpsc-recall-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 = { "watchlists": [
        "baby-gear",
        "furniture-tipover",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("tali-works/cpsc-recall-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 '{
  "watchlists": [
    "baby-gear",
    "furniture-tipover"
  ]
}' |
apify call tali-works/cpsc-recall-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tali-works/cpsc-recall-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/aKoa6DLcqxEMxrRdz/builds/67By6LhamVB2I5mbE/openapi.json
