FDA Recalls Scraper - Food, Drug & Device Recalls API, openFDA avatar

FDA Recalls Scraper - Food, Drug & Device Recalls API, openFDA

Pricing

$8.00 / 1,000 recall records

Go to Apify Store
FDA Recalls Scraper - Food, Drug & Device Recalls API, openFDA

FDA Recalls Scraper - Food, Drug & Device Recalls API, openFDA

Every FDA enforcement report (recall) for food, drugs and medical devices from the official openFDA API. Dates parsed to ISO, the recall class explained in one line, and the free-text distribution turned into a list of US states. No API key. Ongoing and terminated recalls.

Pricing

$8.00 / 1,000 recall records

Rating

0.0

(0)

Developer

NeverEmpty

NeverEmpty

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 hours ago

Last modified

Share

Every FDA recall (enforcement report) for food, drugs and medical devices, from the official openFDA API, in one schema you can put straight into a monitor, a spreadsheet or a compliance review.

  • No API key, no scraping, no proxy. US government data, public domain.
  • All three FDA lists in one run, with the same column names for each.
  • Filter where it costs nothing: by recall class, by keyword (product, reason or firm), by date window. The filter is applied by FDA, so you are not billed for rows you did not ask for.

What this returns that the raw openFDA JSON does not

ColumnWhy it matters
reportDate, recallInitiationDate, centerClassificationDate, terminationDateThe raw API returns "20260508". These are real ISO dates you can sort and compare. Unreadable values stay null — never guessed.
classificationMeaningClass I on its own means nothing to most readers. This is FDA's definition from 21 CFR 7.3, shortened to one line: for Class I, a reasonable probability that use of, or exposure to, the product will cause serious adverse health consequences or death.
distributionStates, isNationwide, isInternationalThe raw field is free text: "WI", "FL and TX.", "Nationwide.", "The recalled product was distributed to the following states: MD, VA". This turns it into a sorted list of state codes and two flags. The raw text is always kept in distributionPattern.
brandNames, genericNames, manufacturerNames, productNdc, substanceNamesPulled out of the openfda block. Food and device records never carry it, and only some drug records do (about 18% of drug recalls, measured over 17,899 records), so these stay null instead of becoming empty lists.
dataLastUpdatedThe date FDA itself last refreshed the data, on every row, so you can tell "no recalls" from "not published yet".

On the state list: it is only filled in when the text is actually written as a list of states. Prose such as "Distributed IN bulk OR by mail" contains two valid state codes as English words, so it is left null instead of claiming Indiana and Oregon. Measured over 1,200 real records: no record was given a state it did not have, and about 1% of records that do list states are left null because the list is broken up by something else (a foreign territory, a spelled-out state). The raw text is always in distributionPattern.

Input

FieldTypeDefaultMeaning
productsarray["food","drug","device"]Which FDA lists to read.
sinceDaysinteger30How far back on the FDA report date. Ignored when a start and end date are set.
beginDate / endDatestring""A fixed window, "2026-08-01" to "2026-08-31". Past years work.
classificationsarray[] (all)"Class I", "Class II", "Class III".
keywordstring""Only recalls whose product description, reason, or firm contain this phrase.
maxRecordsPerProductinteger1000Upper bound per list, so a wide window cannot run up a bill.
maxRetriesinteger4Retries when openFDA does not answer or rate-limits.

Output

One row per recall:

{
"rowType": "recall",
"product": "food",
"recallNumber": "H-1180-2026",
"classification": "Class I",
"classificationMeaning": "Reasonable probability that use of, or exposure to, the product will cause serious adverse health consequences or death.",
"status": "Ongoing",
"recallingFirm": "Green Jeeva LLC",
"productDescription": "Moringa Powder",
"reasonForRecall": "Moringa Powder ingredient positive for salmonella",
"distributionPattern": "Nationwide.",
"distributionStates": null,
"isNationwide": true,
"isInternational": false,
"reportDate": "2026-07-29",
"recallInitiationDate": "2026-06-30",
"terminationDate": null,
"dataLastUpdated": "2026-08-19"
}

What it does when something is wrong

A recall feed that quietly answers "nothing was recalled" is the worst possible failure, so this Actor never does that.

  • No matching recall → one row saying so, with the window and the FDA update date. Not charged, and the run does not fail: an empty week is a real answer.
  • openFDA rejecting the request (a malformed window, an unusable keyword) → an error row with the reason, and the run fails if nothing at all could be read. It is never reported as "no recalls".
  • A keyword openFDA would silently ignore — punctuation only, or non-ASCII, which it answers with the whole window or an error — stops the run before anything is billed, instead of returning everything you did not ask for.
  • One list failing while the others work → the working rows are delivered, the failure is reported as its own row and in RUN_ISSUES.
  • More matches than your cap → the log and RUN_TRUNCATED say how many of how many were returned.
  • Rate limiting (HTTP 429) is retried with a pause; rejections are not retried.

Timing you should know about

FDA publishes enforcement reports weekly, and the data lags. On 2026-08-31 the newest data in all three lists was stamped 2026-08-19. Every row carries dataLastUpdated so a monitor can tell the difference between "nothing happened" and "FDA has not published yet". A daily schedule is still useful — it just means new rows appear in weekly batches.

Measured

Run on 2026-08-31, 45-day window, Class I only: 92 recalls in 1.8 seconds (food 51, drug 6, device 35). States were parsed for 58 of them, 32 were nationwide, 18 reached outside the US, and every date came back as a valid ISO date.

The build is covered by 55 automated checks, and 54 deliberate defects were injected one at a time to confirm those checks actually catch them.

Billing

Pay per event: one charge per recall row delivered. The default sinceDays of 30 covers a rolling month, so a daily schedule bills that whole month every day (about 240 rows a day at the time of writing). For daily monitoring set sinceDays to 7 or less, or use a date window — FDA publishes weekly, so nothing is missed.

The "no recalls" row and rows that report a problem are not charged. Setting a maximum total charge on the run stops delivery rather than handing rows over unpaid, and the run says so instead of reporting "no recalls".

Support

Questions and bug reports: use the Issues tab on this Actor. Include the input you ran and the run id.

Data source: openFDA enforcement reports — official US Food and Drug Administration data, public domain. This Actor is not affiliated with the FDA. Recall data is not medical or legal advice; for action on a specific recall, check the FDA's own listing for that recall number.