Product & Vehicle Recalls API — CPSC, NHTSA, FDA, USDA avatar

Product & Vehicle Recalls API — CPSC, NHTSA, FDA, USDA

Pricing

from $0.42 / 1,000 recall or rating records

Go to Apify Store
Product & Vehicle Recalls API — CPSC, NHTSA, FDA, USDA

Product & Vehicle Recalls API — CPSC, NHTSA, FDA, USDA

Every US recall a federal agency publishes, in one schema: consumer products (CPSC), vehicles (NHTSA), drugs, devices and food (FDA), and meat, poultry and egg (USDA FSIS) — plus a VIN decoder that joins each VIN to its model's recalls, complaints and NCAP crash-test ratings. Keyless .gov sources.

Pricing

from $0.42 / 1,000 recall or rating records

Rating

0.0

(0)

Developer

Insight Solutions

Insight Solutions

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Every recall a US federal agency publishes, in one schema: consumer products from the Consumer Product Safety Commission, vehicles from the National Highway Traffic Safety Administration, drugs, devices and food from the Food and Drug Administration, and meat, poultry and egg products from USDA's Food Safety and Inspection Service. Plus NHTSA owner complaints, NCAP crash-test ratings, and the free vPIC VIN decoder — with each VIN joined to its model's recalls.

Read straight from the agencies' own APIs. No aggregator sits in the middle, no API key is required, and no browser is involved.

The one thing to know up front. Recalls, complaints and safety ratings are matched by model year, make and model — not by VIN range. NHTSA publishes no public VIN-range endpoint, so a recall covering part of a production run appears against every VIN of that model. Every vehicle row says so, and so does every summary row. Treat a match as "this recall may apply to this car", and check the campaign against the manufacturer before acting on it.

At a glance

Input — this is the Store prefill; paste it and run:

{ "sources": ["cpsc", "fda"], "keywords": ["battery"], "vehicles": ["2020 Honda Civic"], "includeRatings": true, "maxRecords": 10 }

Output — one row per record (recall, owner complaint, crash-test rating or decoded VIN), all in the same columns; the fields you will use most are rowType, agency, title, date, recallingFirm, hazard and sourceUrl (full list under Output reference). Anything that could not be fetched comes back as a free diagnostic row (ok: false, errorType, error) instead of a charge.

Price — $0.70 per 1,000 recalls and crash-test ratings on the FREE tier (+ $0.001 per run), $0.15 per 1,000 owner complaints, $0.50 per 1,000 VINs decoded; diagnostic rows, summary rows, filtered-out records and undecodable VINs are all free. Pay-per-event, no API key, no browser, limited permissions — works over the Apify MCP server (mcp.apify.com) and with agentic (x402) payments.

From codeclient.actor("insight.solutions/product-recalls-api").call(run_input={…}) with apify-client, or POST https://api.apify.com/v2/acts/insight.solutions~product-recalls-api/run-sync-get-dataset-items.


What you get

One row per record. Same columns whoever published it:

{
"rowType": "recall",
"agency": "CPSC",
"source": "cpsc",
"sourceDataset": "cpsc/recall",
"recordId": "cpsc:10967",
"recallNumber": "26761",
"title": "Cade California Electronic Recalls Finger Light Toys Due to Risk of Serious Injury or Death from Battery Ingestion; Violate Mandatory Standard for Toys",
"date": "2026-09-10",
"recallingFirm": "California Cade Electronic, LLC, of Hacienda Heights, California",
"productNames": ["Cade California Electronic Projecting Finger Light Toys"],
"productType": "Lights & Accessories",
"unitsText": "About 179,739",
"units": 179739,
"hazard": "The recalled finger lights violate the mandatory safety standard for toys because the toys contain button cell batteries that can be easily accessed by children…",
"remedyOptions": ["Refund"],
"soldAt": "Amazon.com from March 2015 through July 2026 for between $5 and $16.",
"injuriesText": "None reported.",
"manufacturerCountries": ["China"],
"images": [{ "url": "https://www.cpsc.gov/s3fs-public/cade-1_0.jpg", "caption": "Recalled LED Projecting Finger Lights" }],
"proxyPath": "direct",
"sourceUrl": "https://www.cpsc.gov/Recalls/2026/Cade-California-Electronic-Recalls-Finger-Light-Toys"
}

…and the same row for a vehicle recall, with the fields only NHTSA has:

{
"rowType": "recall",
"agency": "NHTSA",
"recordId": "nhtsa:21V215000|HONDA|CIVIC|2020",
"campaignNumber": "21V215000",
"date": "2021-03-25",
"vehicleKey": "2020|HONDA|CIVIC",
"vehicleMake": "HONDA",
"vehicleModel": "CIVIC",
"vehicleModelYear": "2020",
"manufacturer": "Honda (American Honda Motor Co.)",
"component": "FUEL SYSTEM, GASOLINE:DELIVERY:FUEL PUMP",
"summary": "Honda (American Honda Motor Co.) is recalling certain 2019-2020 Acura MDX… The low-pressure fuel pump inside the fuel tank may fail.",
"consequence": "Fuel pump failure can cause an engine stall while driving, increasing the risk of a crash.",
"remedy": "Honda will notify owners, and dealers will replace the fuel pump assembly, free of charge.",
"parkIt": false,
"parkOutSide": false,
"overTheAirUpdate": false,
"sourceUrl": "https://www.nhtsa.gov/recalls?nhtsaId=21V215000"
}

…a decoded VIN:

{
"rowType": "vin",
"agency": "NHTSA",
"vin": "1HGCV1F34LA012345",
"vinValid": true,
"vinMake": "HONDA",
"vinModel": "Accord",
"vinModelYear": "2020",
"trim": "Sport",
"bodyClass": "Sedan/Saloon",
"driveType": "4x2",
"displacementL": "1.5",
"engineHP": "192",
"engineModel": "L15BE",
"transmissionStyle": "Continuously Variable Transmission (CVT)",
"plantCity": "MARYSVILLE",
"plantCountry": "UNITED STATES (USA)",
"gvwr": "Class 1C: 4,001 - 5,000 lb (1,814 - 2,268 kg)",
"vinErrorCodes": ["1"],
"vinErrorTexts": ["1 - Check Digit (9th position) does not calculate properly"],
"vehicleKey": "2020|HONDA|ACCORD"
}

…and a crash-test rating:

{
"rowType": "rating",
"agency": "NHTSA",
"vehicleDescription": "2020 Honda CIVIC 2 DR FWD",
"overallRating": "5",
"overallRatingStars": 5,
"overallFrontCrashRating": "4",
"overallSideCrashRating": "5",
"rolloverRating": "5",
"rolloverPossibility": 0.093,
"dynamicTipResult": "No Tip",
"complaintsCount": 224,
"recallsCount": 5,
"media": [{ "kind": "video", "type": "front", "url": "https://static.nhtsa.gov/crashTest/videos/2020/v09808C018.wmv" }]
}

Owner complaints, free per-source and per-vehicle summary rows, and free diagnostic rows for anything that could not be read, all carry the same columns.


Quick start

Search every agency for a product:

{
"keywords": ["lithium battery"],
"sources": ["cpsc", "fda", "fsis"],
"maxRecords": 100
}

Everything wrong with one car:

{
"vehicles": ["2020 Honda Civic"],
"includeComplaints": true,
"includeRatings": true,
"maxComplaintsPerVehicle": 100
}

Decode a list of VINs and see what each one is recalled for:

{
"vins": ["1HGCV1F34LA012345", "WBA3A5C51CF256581"],
"includeRatings": true
}

Watch for new Class I food recalls every morning:

{
"sources": ["fda", "fsis"],
"classifications": ["Class I"],
"incremental": true
}

You do not have to list nhtsa in sources when you set vehicles or vins — it is switched on for you, because vehicle records exist nowhere else.


Input

FieldTypeDefaultWhat it does
sourcesarrayall fourcpsc, nhtsa, fda, fsis
keywordsarrayMatch title, product, description, hazard or reason
manufacturersarrayMatch recalling firm, manufacturer, importer, distributor, retailer, USDA establishment
hazardKeywordsarrayMatch the hazard, consequence or reason
remedyKeywordsarrayMatch the remedy
statesarrayTwo-letter codes, matched on the firm's state and the distribution text
classificationsarrayClass I, Class II, Class III, Public Health Alert
recallIdsarrayCPSC recall IDs, or NHTSA campaign numbers like 21V215000
dateFrom / dateTostringISO dates. Server-side at CPSC and FDA, here for NHTSA and USDA
vehiclesarray"2020 Honda Civic" or {"make","model","year"}
vinsarrayVINs, full or partial (*), 50 per request
vinModelYearstringModel-year hint for a partial VIN
decodeOnlybooleanfalseDecode VINs and stop — no recall lookup
includeRawVinbooleanfalseAttach all 154 vPIC fields as vpicRaw
includeComplaintsbooleanfalseFetch NHTSA owner complaints
maxComplaintsPerVehicleinteger200Cap on complaints per vehicle
includeRatingsbooleanfalseFetch NCAP crash-test ratings
maxRatingVariantsPerVehicleinteger5Cap on rated body styles per vehicle
includeCampaignDetailbooleanfalseFill potentialUnitsAffected (one extra request per campaign)
crashOnly / fireOnlybooleanfalseComplaints NHTSA flagged as a crash or a fire
resolveAmbiguousstringdiagnosticdiagnostic, first or all
cpscSearchFieldsarraytitle, product, descriptionWhich CPSC fields a keyword is searched against
maxCpscRequestsinteger12Request budget for saferproducts.gov
fsisServerSideFilterbooleantrueTry USDA's text filters before the full list
fdaSearchstringRaw openFDA search= expression, ANDed with the rest
openFdaApiKeystringOptional; raises the openFDA page size to 1,000
maxRecordsinteger100Per source. 0 for no cap
maxVehicles / maxVinsinteger25 / 500Input caps
incrementalbooleanfalseReturn only what has changed since the last run
stateStoreNamestringproduct-recalls-api-stateWhere the cursor lives
includeSummarybooleantrueFree summary rows
maxConcurrencyinteger4Sources and vehicles in flight
maxRunSecsinteger240Wall-clock budget
proxyConfigurationobjectApify datacenterSee Proxy below

Output reference

rowType is one of recall, complaint, rating, vin, summary or diagnostic. Every row carries every column; the ones that do not apply are null, so the dataset exports as one rectangular table however the run was configured.

Every row: ok, rowType, input, error, errorType, scrapedAt, source, sourceUrl, plus agency, sourceDataset, recordId, apiUrl, proxyPath and fetchedVia.

Recall core: recallNumber, campaignNumber, eventId, title, summary, description, reason, date, dateRaw, lastPublishDate, reportDate, initiationDate, classificationDate, terminationDate, closedDate, classification, riskLevel, recallType, status, voluntaryMandated, initialFirmNotification, isArchived, relatedToOutbreak.

Product: productType, categoryId, productNames, productDescription, productModels, productQuantity, unitsText, units, upcs, codeInfo, brands, genericNames, substanceNames, productNdcs, applicationNumbers, images, relatedUrls.

Firm and distribution: manufacturer, manufacturers, recallingFirm, importers, distributors, retailers, soldAt, establishment, manufacturerCountries, firmCity, firmState, firmCountry, postalCode, distributionPattern, states, consumerContact, mediaContact, companyMediaContact, qtyRecovered.

Hazard and remedy: hazard, hazards, hazardType, consequence, remedy, remedyOptions, component, componentRaw, components, injuriesText, injuryCount, deathCount, crash, fire.

Vehicle: vehicleKey, vehicleMake, vehicleModel, vehicleModelYear, vehicleDescription, parkIt, parkOutSide, overTheAirUpdate, potentialUnitsAffected, odiNumber, maskedVin, incidentDate, complaintFiledDate.

Rating: vehicleId, overallRating, overallRatingStars, the front, side, pole and rollover ratings, rolloverPossibility, dynamicTipResult, electronicStabilityControl, forwardCollisionWarning, laneDepartureWarning, complaintsCount, recallsCount, investigationCount, media.

VIN: vin, vinValid, vinErrorCodes, vinErrorTexts, suggestedVin, vinMake, vinModel, vinModelYear, vinManufacturer, and the decoded specification — body, trim, engine, transmission, plant, restraints and driver assistance — plus vpicRaw when you ask for it.

Six dataset views are built in: Recalls, Vehicle recalls, Owner complaints, Crash-test ratings, Decoded VINs and Problems.

Dates

Every date column is ISO YYYY-MM-DD, and dateRaw keeps whatever the agency printed. That matters more here than usual: NHTSA prints recall dates as DD/MM/YYYY and complaint dates as MM/DD/YYYY — the same API, two conventions. This Actor has two separate parsers and never lets one read the other's field.

Free summary rows

  • summaryType: "source" — what each agency returned, how many requests it took, which date window was asked for, and for USDA whether the text filter or the full list was used.
  • summaryType: "vehicle" — the resolved make, model and year, NHTSA's own recall and complaint totals for cross-checking, and the VIN-range limitation.
  • summaryType: "vin-batch" — one row per vehicleKey that your VINs decoded to, carrying how many recalls, complaints and ratings that model produced and how many duplicate lookups the dedupe saved. Join it to the vin rows on vehicleKey. The counts live here rather than on the vin rows themselves because a paid VIN row is written the moment it decodes — it is never held back waiting on a recall lookup that a deadline or a budget might cut short.
  • summaryType: "run" — totals for the whole run, including how many records were skipped as already seen and how many were deduplicated.

What you are never charged for

  • Diagnostic rows of every type: not-found, no-results, ambiguous, invalid-input, blocked, timeout, unavailable.
  • Every summary row.
  • Records your filters excluded — the filters run before the charge.
  • Records already returned by an earlier incremental run.
  • Records deduplicated across sources, or across several VINs of the same model.
  • A VIN we cannot decode. You get a free row saying why, with vPIC's own error codes and its suggested correction.
  • A vehicle description that matches more than one model. You get the list of candidates, free, instead of a guess.
  • CPSC's placeholder record, in every form it takes.
  • A run that returns nothing at all. It finishes FAILED, says why, and bills nothing — start fee included.

Pricing

EventFREEBRONZESILVERGOLD
Run started$0.001$0.001$0.001$0.001
Recall or rating returned$0.0007$0.0007$0.00056$0.00042
Owner complaint returned$0.00015$0.00015$0.00015$0.00015
VIN decoded$0.0005$0.0005$0.0004$0.0003

That is $0.70 per 1,000 recalls and crash-test ratings, $0.15 per 1,000 owner complaints, and $0.50 per 1,000 VINs decoded. Prices shown are what a new account pays on the FREE tier, not a best-case GOLD number.

Complaints are priced separately for a reason, and you should know it before you switch them on. NHTSA returns every complaint against a vehicle in a single response, and popular models have a lot of them: one 2021 Tesla Model 3 comes back with 660. That is why includeComplaints defaults to false and maxComplaintsPerVehicle defaults to 200 — 200 complaints is $0.03, and the uncapped 660 would be $0.099.

The run honours ACTOR_MAX_TOTAL_CHARGE_USD: when the budget runs out it stops fetching rather than handing over rows it cannot bill for, and says so in the run status.


Proxy

The default is Apify's datacenter proxy, and it is enough for NHTSA, vPIC, openFDA and USDA — USDA's firewall actually prefers it to an unproxied client.

CPSC is the exception, and it is handled for you. In our measurements saferproducts.gov answered every datacenter request with a placeholder record instead of recalls — six queries, six identical placeholders, 15 to 29 seconds each — while the same query from an unproxied address returned real recalls in 180 milliseconds. So CPSC requests go out direct first, retry twice with backoff, and fall back to your proxy only if all three fail. Every CPSC row carries proxyPath and fetchedVia so you can see which leg answered.

The run paces itself: 250–600 ms between successive requests to one host, at most two batch requests a second to vPIC, at most 200 requests a run to openFDA (whose keyless quota is 1,000 a day per IP, and a shared exit is everybody's budget), and exactly one fetch of USDA's list per run.


Running it every day

Set incremental: true and schedule it. The Actor keeps each record's id and its revision marker in a named key-value store — CPSC's publish date, FDA's status, USDA's last-modified date, NHTSA's report-received date and star rating. So a recall the agency re-publishes comes back, an FDA recall that moves from Ongoing to Terminated comes back, and an unchanged one does not. On a quiet day the run finishes SUCCEEDED with "Nothing new" in its status and charges nothing — a scheduled monitor should not look broken because no one recalled anything that morning.

The first incremental run returns everything up to your caps and seeds the state. Give two scheduled jobs different stateStoreName values and they will not tread on each other.


Use it from an AI agent, or from code

One JSON object in, one flat array out — the shape agent runtimes want. The Actor runs with limited permissions, uses pay-per-event pricing and never enters Standby, so it works over the Apify MCP server and with x402 agentic payments. The Integrations tab pushes results to Slack, a webhook, Zapier, Make, Google Sheets, Snowflake or BigQuery.

curl -X POST "https://api.apify.com/v2/acts/insight.solutions~product-recalls-api/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"keywords":["lithium battery"],"sources":["cpsc","fda"],"maxRecords":50}'
# pip install apify-client
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("insight.solutions/product-recalls-api").call(run_input={
"vins": ["1HGCV1F34LA012345", "WBA3A5C51CF256581"],
"includeRatings": True,
"includeComplaints": True,
"maxComplaintsPerVehicle": 50,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if not row.get("ok"):
continue
if row["rowType"] == "vin":
print("VIN", row["vin"], row["vinModelYear"], row["vinMake"], row["vinModel"], row["trim"], sep=" | ")
elif row["rowType"] == "recall":
print("RECALL", row["agency"], row["recallNumber"] or row["campaignNumber"],
row["date"], row["title"], row["sourceUrl"], sep=" | ")

Set incremental: true when you want a monitor rather than a backfill: the run returns only records that are new or that the agency has revised.


FAQ

Which agencies, and how far back? NHTSA recalls and owner complaints cover 1949 to the present and are updated daily; NCAP crash-test ratings cover 1990 to the present and are updated annually. CPSC has published more than 8,000 recalls by the agency's own 2018 count, and the newest recall ID we have seen is 10967. openFDA enforcement covers drug, device and food recalls. USDA FSIS covers meat, poultry and egg products.

Why did my VIN come back as a different model than I expected? Because the VIN says so. A VIN's world manufacturer identifier and descriptor section carry the make and model, and vPIC reads them even when the check digit fails. If the decode surprises you, check vinErrorCodes — code 1 is a bad check digit, which usually means a typo in a VIN that still decodes to something.

A recall matched my VIN. Is my car definitely affected? Not definitely. NHTSA publishes no public VIN-range endpoint, so recalls are indexed against the model, not the vehicle. A campaign covering part of a production run comes back for every VIN of that model. Take the campaignNumber to the manufacturer's own VIN lookup to confirm.

Why is a CPSC hazard a whole sentence instead of a code? Because that is what the agency returns. CPSC's API has HazardType and HazardTypeID fields and they are empty on every record we have measured, so hazard is the sentence the agency wrote and hazardType is honestly null. The same goes for injuries: CPSC writes "There have been 10 reported incidents of the hair dryer smoking or catching fire. No injuries reported." — that is injuriesText, and injuryCount stays null rather than being parsed out of prose.

Why are brands and genericNames empty on my food recalls? Because openFDA populates its openfda block on drug enforcement records and leaves it empty on food and device ones. Those three columns are drug-only in practice. We would rather say so than ship columns that are silently always null.

Why does CPSC sometimes return a diagnostic instead of recalls? CPSC's recall service is read directly from saferproducts.gov. When it is temporarily unavailable it answers with a placeholder record rather than an error — a valid HTTP 200 with a fake recall in it. We detect that, retry three times, try the proxy, and if it still fails you get a free diagnostic row with the service's own message. You never get a fake recall.

Why is USDA slower than the others? Because USDA publishes its entire recall list — about 13 MB — in one response and offers no recall-date range filter at all. The run fetches it once and filters locally. When you set keywords it first tries USDA's two documented text parameters and falls back to the full list if they return nothing, because an empty answer from that API is indistinguishable from a parameter it ignored.

Do I need an API key? No. Every source here is a keyless public federal API. openFdaApiKey is optional and only raises openFDA's page size from 100 to 1,000.

Can I use this data? These are public federal records. CPSC, NHTSA, FDA and USDA publish no attribution requirement, rate limit or terms of use for the endpoints used here beyond NHTSA's note that vPIC applies automated traffic control. Check the agency's own page if your use is commercial and high volume.

What happens if a source changes its format? Agency APIs change without notice. When a record cannot be read the run returns a free diagnostic row naming the request rather than a wrong number, and the run only finishes successfully if it returned at least one real record.


Limitations

  • Vehicle records are matched by model, not by VIN range. Said again here because it is the single most important thing about this dataset.
  • NHTSA defect investigations and the ODI-number lookup are not in this version. Both routes we tried answered Missing Authentication Token. investigationCount on a rating row is the only investigation signal shipped.
  • CPSC hazard-type codes and UPCs are not available. The agency returns both empty on every record we have measured. The UPC search parameter is correspondingly near-useless.
  • CPSC has no paging and no limit parameter. The whole result set arrives in one body, so maxRecords is a client-side cut and a request with no filter at all would download all 11,000-odd records. The run will not issue one: with no keyword and no dates it bounds CPSC to the last 90 days.
  • USDA's record shape is read from the agency's documentation. The 13 MB list was too large to capture during development. Every field is read defensively, so an unexpected shape produces null columns rather than a failure.
  • NCAP ratings have no publication date, so a dateFrom/dateTo filter does not apply to them. Neither does it apply to VIN rows.
  • potentialUnitsAffected costs an extra request per campaign, because NHTSA publishes it only on its campaign-number endpoint. It is null unless you set includeCampaignDetail.
  • No severity score of our own. FDA and USDA classes, NHTSA's parkIt and parkOutSide flags and the CPSC hazard sentence are passed through under their own names. We do not rank them against each other.
  • No EU, Canadian or Australian recalls. CPSC sometimes links a Health Canada or Transport Canada notice of the same recall; those links are in relatedUrls.
  • The upstream format may change. See the FAQ.

Our other Actors

Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.

Video, audio & social

News, documents & the web

Business, finance & jobs

Apps & games