FDA Recalls Scraper - Food, Drug & Device Recalls API, openFDA
Pricing
$8.00 / 1,000 recall records
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 hours ago
Last modified
Categories
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
| Column | Why it matters |
|---|---|
reportDate, recallInitiationDate, centerClassificationDate, terminationDate | The raw API returns "20260508". These are real ISO dates you can sort and compare. Unreadable values stay null — never guessed. |
classificationMeaning | Class 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, isInternational | The 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, substanceNames | Pulled 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. |
dataLastUpdated | The 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
| Field | Type | Default | Meaning |
|---|---|---|---|
products | array | ["food","drug","device"] | Which FDA lists to read. |
sinceDays | integer | 30 | How far back on the FDA report date. Ignored when a start and end date are set. |
beginDate / endDate | string | "" | A fixed window, "2026-08-01" to "2026-08-31". Past years work. |
classifications | array | [] (all) | "Class I", "Class II", "Class III". |
keyword | string | "" | Only recalls whose product description, reason, or firm contain this phrase. |
maxRecordsPerProduct | integer | 1000 | Upper bound per list, so a wide window cannot run up a bill. |
maxRetries | integer | 4 | Retries 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_TRUNCATEDsay 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.