# US CPSC Consumer Product Recall & Supply Chain Monitor (`afkdigital/us-cpsc-consumer-product-recall-supply-chain-monitor`) Actor

Official CPSC recall notices with manufacturer, importer, distributor and retailer roles. Date, country and company filters. JSON/CSV for Clay and n8n.

- **URL**: https://apify.com/afkdigital/us-cpsc-consumer-product-recall-supply-chain-monitor.md
- **Developed by:** [AFK Digital](https://apify.com/afkdigital) (community)
- **Categories:** Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.50 / 1,000 unique 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.

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 CPSC Consumer Product Recall & Supply Chain Monitor

Turn official US Consumer Product Safety Commission recall notices into structured supplier-monitoring data. Filter by recall date, country of manufacture, source-listed companies and retailers. Export JSON or CSV for Clay, n8n, compliance research, supplier review and recall dashboards.

### What you receive

One dataset row per unique CPSC RecallID. Products and companies never create additional rows or charges.

- recall_id, recall_number, recall_date (YYYY-MM-DD)
- product_name (array), products (complete source product entries)
- hazard_description (array), remedies (array), remedy_options
- manufacturer_names, importer_names, distributor_names, retailer_names (separate arrays)
- distributor_retailer_names (array with explicit role, name, source_entry)
- manufactured_in_country (array), recall_url, fetched_at (UTC)
- source_record (complete CPSC JSON entry, including all source arrays and unmodified date)
  Missing or empty source fields become null in normalized outputs; source_record preserves original empties. Null elements in arrays preserve missing source names. Retailers.Name is often a sales-channel/date/price narrative: it is retained verbatim, not parsed into invented company entities. No attribution is inferred from the recall title.

### Inputs and filter scope

All active filters combine with AND; string matching is literal case-insensitive substring, not regex or a taxonomy classifier.
| Input | Application |
| --- | --- |
| recallDateFrom / recallDateTo | Inclusive YYYY-MM-DD via RecallDateStart / RecallDateEnd and local validation |
| productCategory | Local Products.Type or Products.CategoryID only. Fields are often blank; blank records do not match. Never falls back to product names. |
| manufacturedInCountry | Local ManufacturerCountries.Country, using source wording (e.g. China) |
| companyName | Local OR across Manufacturers, Importers, Distributors, Retailers; roles stay separate |
| retailerName | Local Retailers.Name only |
| maxResults | 1–10000 unique recalls; default 20 |
| maxCostUsd | Extra event budget, default $1.10, maximum $55 |

Omitted dates use the last 30 days through UTC today. The fixed January 2025 example provides reproducible recall data. Maximum span 3660 days; split larger history into separate runs. Different runs may return and charge the same recall again; deduplication is per run, including restart/resurrection.

### Example input

```json
{"recallDateFrom":"2025-01-01","recallDateTo":"2025-01-31","manufacturedInCountry":"China","companyName":"AliExpress","maxResults":20,"maxCostUsd":0.11}
```

### API behavior and completeness

Source: https://www.saferproducts.gov/RestWebServices/Recall?format=json
Official guide: https://www.cpsc.gov/s3fs-public/RecallRetrievalWebServicesProgrammersGuide20180917.pdf
The legacy service returns a JSON array without a documented total-count or pagination contract. We request date windows of at most 31 days, newest windows first; dense responses (500 or more) are recursively split. A dense single day fails explicitly. Source order within each window is retained; this is not a guaranteed global date sort.
Dates are validated locally so an ignored source date filter fails visibly. Invalid/unknown inputs are rejected, not silently ignored. Non-date filters are always applied locally. In live verification ManufacturerCountry=China returned no rows despite China being present; therefore it is not used for remote filtering.
No numeric official rate limit was found in the linked guide. Our conservative policy is sequential requests, at most 1 per second, 3 attempts per request, Retry-After support for 429/transient server responses, up to 35s timeout per attempt, 20MiB response cap, 400 HTTP attempts and a 210s fetch deadline. Narrow the date range if a cap is reached. Errors fail the run; any already saved rows remain visible and billable. SUMMARY reports source URLs, attempts, saved count, time, error status, and whether a result/budget cap stopped scanning. Reaching maxResults/budget is an intentional limited scan, not a complete archive export. The undocumented source backend may have limits we cannot prove; no exhaustive archive guarantee is made.

### Price

Pay per event: **$0.0055 per successfully returned unique recall**, or **$5.50 per 1000**.
Only recall-returned is billed; no start fee and no per-product, per-country or per-company charges. Standard-run compute is included. Empty successful runs have zero recall events. maxResults, maxCostUsd and the Apify platform spending limit all apply. Dataset access/storage after the run follows Apify standard rules.
The SDK writes/charges one recall at a time. Existing dataset IDs are loaded on restart to avoid re-emission. A source failure after some results does not erase those delivered results.

### Clay / n8n

Call the Actor with JSON input, wait for completion, then read the default Dataset JSON or CSV link in Output. JSON retains nested arrays and source entries most faithfully. CSV is one row per recall, with nested values represented by the platform export; use JSON or parse nested cells when importing into tabular tools. Use recall_id as your downstream upsert key. No webhook or third-party service credentials required.

### Interpretation and use

A recall is a historical safety notice, not evidence of current sales, a live inventory listing, or a legal liability decision. A source-listed company is not automatically the manufacturer, an affected supplier in your own chain, or a commercial prospect. Check the original notice, model/date details and remedies before acting.
The public CPSC recall data is described as publicly available by CPSC and the data.gov catalog lists a public-domain license: https://catalog.data.gov/dataset/recalls-api . This Actor charges for structured retrieval and filtering, not exclusive ownership of government data. No CPSC endorsement. Third-party images/marks are not republished as marketing assets. No warranty of source completeness or uptime.

### Development

Python 3.13, Apify SDK 4.2.0, standard-library HTTP/JSON only. Version 1.0.0. No browser, Playwright, proxies or paid upstream API.

# Actor input Schema

## `recallDateFrom` (type: `string`):

Inclusive YYYY-MM-DD. Omit for UTC today minus 30 days.

## `recallDateTo` (type: `string`):

Inclusive YYYY-MM-DD. Omit for UTC today. Maximum range 3660 days.

## `productCategory` (type: `string`):

Local literal substring on Products.Type and CategoryID only. Frequently empty in source: such records will not match. No inferred categories.

## `manufacturedInCountry` (type: `string`):

Local case-insensitive literal substring on ManufacturerCountries.Country. Use source wording, e.g. China; no ISO conversion.

## `companyName` (type: `string`):

Local case-insensitive literal substring across source Manufacturers, Importers, Distributors, Retailers. Roles remain separate.

## `retailerName` (type: `string`):

Local case-insensitive literal substring in Retailers.Name only. These may contain sales narratives, retained verbatim.

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

One row and one event per recall_id, irrespective of product/company array lengths.

## `maxCostUsd` (type: `number`):

Additional result budget at $0.0055 each; platform maximum total charge also applies.

## Actor input object example

```json
{
  "maxResults": 20,
  "maxCostUsd": 1.1
}
```

# Actor output Schema

## `recallsJson` (type: `string`):

No description

## `recallsCsv` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("afkdigital/us-cpsc-consumer-product-recall-supply-chain-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("afkdigital/us-cpsc-consumer-product-recall-supply-chain-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 '{}' |
apify call afkdigital/us-cpsc-consumer-product-recall-supply-chain-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,afkdigital/us-cpsc-consumer-product-recall-supply-chain-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/RH2hqkMUhZr1RM01S/builds/rCZMIYdG6vewhYmUd/openapi.json
