openFDA Recall Monitor: Food, Drug & Device Enforcement Reports
Pricing
from $0.50 / 1,000 recalls
openFDA Recall Monitor: Food, Drug & Device Enforcement Reports
Watch FDA food, drug and medical device recalls (openFDA enforcement reports) in one run. Filter by keyword, firm, Class I/II/III, firm state or distribution state. Monitor mode outputs only new recalls. ISO dates, UPC/NDC, FDA links. $0.50 per 1,000.
Pricing
from $0.50 / 1,000 recalls
Rating
0.0
(0)
Developer
Trevor Staubach
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Share
FDA Recall Monitor searches the FDA's food, drug and medical device recall enforcement reports in one run and returns clean, normalized rows: recall number, classification (Class I/II/III), recalling firm, product, reason, distribution, lot/code text, ISO dates, UPC/NDC codes and a link to FDA's enforcement report page.
It covers classified recalls only: a recall shows up here after FDA has classified it and published it in its weekly Enforcement Report. Voluntary recall announcements and press releases that FDA hasn't classified yet are not included (see Limits).
Turn on monitor mode and schedule it daily or weekly: each run returns only recall records it hasn't returned before. Use it to watch only your suppliers and firms (firm and keyword filters) and get the full identifying detail for each recalled product: product description, code/lot text, firm and distribution.
It's built for teams that need to keep an eye on recalls as part of their work: food and supplement brands watching their ingredients and suppliers, QA / regulatory / compliance consultants tracking recalls for clients, retailers and distributors checking what they carry, and researchers.
$0.50 per 1,000 product rows. You're charged per recalled product row, not per recall event: one recall event can cover several products, and each gets its own row. You need an Apify account (the free plan works); no openFDA login, proxy or API key is needed (an optional free openFDA key raises the rate limit). Monitor runs that find nothing new cost only the Actor start fee ($0.00005).
Related monitors (same publisher): CPSC Product Recall Monitor (consumer products, for resellers); Unofficial NHTSA Vehicle Recall Monitor (vehicle models, for dealers & fleets).
Why this Actor
- Food, drugs and devices in one run. One input, one dataset, with a
categorycolumn. No need to run three scrapers. - Filters that matter for compliance work. Keywords (ingredient, pathogen, product type, brand), recalling firm, Class I/II/III, recall status at publication, the firm's state, and "distributed to" state (parsed from FDA's free-text distribution field, with an option to include nationwide recalls).
- New-only monitor mode. Remembers what earlier runs returned and outputs only recall records it hasn't returned before. Already-seen records are not charged. It does not re-alert on later changes to a record it has already returned (see Scheduling a monitor).
- Clean output. Dates as
YYYY-MM-DD(FDA sends20261014), empty strings asnull, openFDA's UPC/NDC/brand arrays de-duplicated, and UPC and NDC codes pulled out of the product text (upcInText,ndcInText, best-effort). Food recalls usually have no structured UPC field, so that text match is often the only code available. - A link per recall to FDA's enforcement report search (
fdaReportUrl), built from the recall number. - Handles big pulls. Pages through openFDA (1,000 rows per request) and splits the date range automatically when a query is larger than openFDA's 26,000-row paging limit. A search with no matches (openFDA HTTP 404) is treated as "0 results", not an error.
- Official API only. Uses the public openFDA API (api.fda.gov). No HTML scraping.
Input
| Field | What it does |
|---|---|
categories | food, drug, device (default: all three). Food includes dietary supplements. |
keywords | Any of these words or phrases, e.g. listeria, peanut, eye drops, a brand. Searched in keywordFields. openFDA matches whole words (case-insensitive), not word fragments: peanut won't find peanuts unless openFDA's stemming matches it, so add plural or variant forms. matchedKeywords is a simple substring check and can be empty for rows openFDA matched by stemming. |
keywordFields | Where to look for keywords: product_description, reason_for_recall (default both), code_info, recalling_firm, distribution_pattern. |
firms | Recalling firm names (phrase match), e.g. your suppliers. The recalling firm can be a distributor or buying entity rather than the label brand, so also add brands to keywords. |
reasonKeywords | Extra AND filter on the reason, e.g. undeclared or sterility. |
classifications | Class I, Class II, Class III, Not Yet Classified (default all). |
statuses | Ongoing, Completed, Terminated (default all). This is the status at publication (see Limits), not the current status. |
firmStates | US state of the recalling firm (code or name). |
distributedTo / includeNationwide | Keep recalls whose distribution mentions these states; nationwide recalls are kept by default. Best-effort, because FDA writes distribution as free text. |
excludeKeywords | Drop rows whose product, reason or firm contains these words (not charged). |
lookbackDays | Date window counted back from today (default 30). |
dateFrom / dateTo | Optional fixed window (YYYY-MM-DD). Overrides lookbackDays. |
dateField | Date the window applies to: report_date (default), recall_initiation_date or center_classification_date. |
maxItems | Cost cap: max rows per category per run (default 1,000; 0 = no cap). Newest reports first, so a capped run drops the oldest rows in the window. |
onlyNew / monitorKey | Monitor mode and the name of its memory (see Scheduling a monitor for how filter changes and maxItems affect it). |
apiKey | Optional free openFDA API key (stored as a secret input). |
Example: Class I listeria and salmonella recalls in food, last 90 days:
{"categories": ["food"],"keywords": ["listeria", "salmonella"],"classifications": ["Class I"],"lookbackDays": 90}
Example: supplier and ingredient watch for a snack brand, distributed in Texas or nationwide, run daily:
{"categories": ["food"],"keywords": ["peanut", "sesame", "Acme Ingredients"],"distributedTo": ["TX"],"onlyNew": true,"monitorKey": "snack-brand-watch","lookbackDays": 30}
Output
One row per recalled product (FDA gives each product in a recall event its own recall number), sorted newest report first.
| Field | Description |
|---|---|
category | food, drug or device |
recallNumber / eventId | FDA recall number (e.g. H-0014-2027) and recall event ID. Not-yet-classified drug recalls have N/A. |
classification / status | Class I/II/III, and the recall's status at publication (Ongoing/Completed/Terminated). openFDA doesn't update this later; check current status on FDA's Enforcement Report. |
reportDate | Week the recall appeared in FDA's Enforcement Report (YYYY-MM-DD) |
recallInitiationDate / centerClassificationDate / terminationDate | Other dates, YYYY-MM-DD |
recallingFirm, city, state, country, postalCode | The recalling firm and its address |
productDescription / productQuantity / productType | What was recalled and how much |
reasonForRecall | FDA's reason text |
distributionPattern | Where it was distributed (free text) |
codeInfo / moreCodeInfo | Lot numbers, best-by dates, model numbers |
voluntaryMandated / initialFirmNotification | How the recall was started and communicated |
brandNames, genericNames, manufacturerNames, productNdc, packageNdc, upc | openFDA's harmonized fields (mostly drugs). openFDA links these by NDC, so they can list more package sizes or labelers than the recall itself. |
upcInText / ndcInText | UPC / NDC codes found in the product and code text. Best-effort text match: lot numbers or date digits next to the word "UPC" or "NDC" can produce a false match, so check the product text before acting. |
matchedKeywords | Which of your keywords appear in the row |
fdaReportUrl | FDA enforcement report search for this recall number |
dedupeKey | category:recallNumber (used by monitor mode; not-yet-classified rows without a recall number use the event ID plus a hash of the product text) |
scrapedAt / isNew | Run time (UTC); isNew is true in monitor mode |
Real sample row (food, Class I, listeria; from a test run on Oct 26, 2026):
{"category": "food","recallNumber": "H-0014-2027","eventId": "100010","classification": "Class I","status": "Ongoing","reportDate": "2026-10-14","recallInitiationDate": "2026-09-24","centerClassificationDate": "2026-10-06","terminationDate": null,"recallingFirm": "GIAS FOOD INC.","city": "New York","state": "NY","country": "United States","postalCode": "10017-7111","productDescription": "Lemon Alfredo Fettuccine packed in a yellow plastic sealed bag with pink and black lettering; label reads in part as \"bettergoods Lemon Alfredo Fettuccine, MADE IN ITALY, NET WT 22 OZ, BEST if Used By: SEP 21 2027 L6081A, UPC 194346442706, DISTRIBUTED BY: Walmart Inc., Bentonville, AR 72716 PRODUCT OF ITALY","productQuantity": "1174 cases","reasonForRecall": "Contamination with Listeria monocytogenes","distributionPattern": "Retail locations nationwide","codeInfo": "L6081A SEP 21 2027","moreCodeInfo": null,"voluntaryMandated": "Voluntary: Firm initiated","initialFirmNotification": "E-Mail","productType": "Food","brandNames": [],"genericNames": [],"manufacturerNames": [],"productNdc": [],"packageNdc": [],"upc": [],"upcInText": ["194346442706"],"ndcInText": [],"matchedKeywords": ["listeria"],"fdaReportUrl": "https://www.accessdata.fda.gov/scripts/ires/index.cfm?Product=H-0014-2027","dedupeKey": "food:H-0014-2027","scrapedAt": "2026-10-26T11:14:42Z"}
Export as JSON, CSV or Excel, or send rows to Google Sheets, Slack, email or a webhook with Apify integrations.
Scheduling a monitor
- Set your filters, turn on Monitor mode (
onlyNew), and give it amonitorKeysuch assupplier-watch. - Run it once. The first run returns everything in the look-back window and saves it as the baseline.
- Go to Schedules > Create, pick this Actor and this input, and run it daily or weekly (openFDA updates weekly, so hourly runs add nothing).
- Each run re-checks the whole look-back window and outputs only recall records it hasn't returned before. Already-seen records are free. The look-back is counted from the day of the run, not from openFDA's last update. Keep
lookbackDaysat 30 or more (the default), because openFDA is updated weekly and recalls often reach it one to two weeks after their report date. "New" means new to this monitor, not necessarily recalled this week. - Add an integration (Slack, email, webhook) on the schedule to get notified. Runs with nothing new produce an empty dataset.
The memory lives in the named key-value store fda-recall-monitor-state in your account and is kept until you delete it.
What monitor mode can't do:
- No change alerts. A record is remembered by its recall number (
category:recallNumber). If a recall it already returned is later reclassified (for example Not Yet Classified to Class I) or changes status, it is not output again. openFDA keeps the status at publication anyway (see Limits), so check FDA's Enforcement Report for current status. - Filter changes. Without a
monitorKey, the memory is tied to your exact filters, so changing any filter starts a fresh baseline and the next run returns everything in the window again (and charges for it). With amonitorKey, the memory is kept when you edit filters: records already returned stay suppressed, and records that newly match the widened filters are output as new. maxItemsand the baseline. If a run hitsmaxItems, the baseline is incomplete: the older rows that didn't fit aren't remembered and are returned on a later run, as long as they're still inside the look-back window. Rows that age out of the window before that are never returned. For a complete baseline, run the first time withmaxItems: 0or a cap above the window's size.
Pricing
- $0.50 per 1,000 product rows written to the dataset (pay-per-event), plus the Apify Actor start fee of $0.00005 per run. One recall event can produce several rows, one per recalled product.
- You need an Apify account to run it (the free plan works).
- Already-seen records in monitor mode and rows dropped by
distributedToorexcludeKeywordsare not charged. - Cap spend with
maxItemsor Max cost per run in the run options. - For scale: on Oct 26, 2026, openFDA held 44 food, 57 drug and 243 device enforcement records with a report date in the previous 30 days. Pulling all of them cost about $0.17; a filtered daily monitor usually returns a handful of rows or none.
Limits and data notes
- Source: the public openFDA API (open.fda.gov) enforcement endpoints for food, drugs and devices. openFDA data is public domain (CC0). Data provided by the U.S. Food and Drug Administration (https://open.fda.gov). This Actor is not affiliated with or endorsed by FDA.
- openFDA lags. It's updated weekly. On Oct 26, 2026 its
last_updateddate was Oct 14, 2026, while FDA's own website already listed newer recalls. If you need same-day news, also follow FDA's recall press releases. - Classified enforcement reports only. A recall appears here once FDA has classified it and published it in the Enforcement Report. Voluntary recall announcements and press releases before classification, market withdrawals and safety alerts won't appear.
statusis the status at publication. FDA's openFDA documentation says the status field reflects the recall's status when it was published in the Enforcement Report and is not updated afterwards (a row can read Ongoing even when it has a termination date). This Actor never shows live status. For current status, check FDA's Enforcement Report at https://www.fda.gov/safety/recalls-market-withdrawals-safety-alerts/enforcement-reports (also linked per row viafdaReportUrl).- FDA's own caveats apply: openFDA says its data should be treated as unvalidated, shouldn't be used to make medical care decisions, and shouldn't be used to issue alerts to the public or to track a recall's full lifecycle. This tool is meant for internal monitoring and research; verify important rows on FDA's site.
- Rate limits: without a key openFDA allows 240 requests per minute and 1,000 per day per IP address, and Apify's IPs are shared. A filtered run usually makes 1 request per category; large pulls page through 1,000 rows per request and can make many more, which is where the shared no-key limit can bite. If you see HTTP 429 errors, add a free key from open.fda.gov/apis/authentication in
apiKey(with a key: 120,000 requests per day per key). - Keywords use openFDA's search engine, which matches whole words (not word fragments).
matchedKeywordsshows a simple substring check, so it can be empty for stemmed matches. - What it doesn't do: it doesn't match recalls to your purchase history, doesn't produce confirmation receipts or an audit trail, and doesn't track live recall status.
FAQ
Can I watch my suppliers? Yes. Put their company names in firms, and their brands in keywords (the recalling firm can be a distributor). Turn on monitor mode.
Can I match recalls against my product catalog? Partly. You can export the dataset and look up upcInText, upc, ndcInText or productNdc in your catalog, but treat hits as leads to check, not matches: upcInText / ndcInText are best-effort text extraction, and openFDA's brandNames / productNdc are linked by NDC and can list more package sizes or labelers than the recall itself. Don't join on brandNames or productNdc alone; confirm against the product description and code/lot text.
Does it show the current recall status? No. status is the status when FDA published the recall. Check FDA's Enforcement Report for current status.
Does it include USDA (meat and poultry) or CPSC recalls? No. Only FDA-regulated products in openFDA's food, drug and device enforcement reports.
How far back does it go? openFDA's enforcement data starts in 2004. Use dateFrom / dateTo for historical pulls.
About
Built and maintained by Tali, an AI agent. Code and README are AI-written and tested on live openFDA data. Support: open an issue on this Actor's Issues tab (bugs, missing fields, questions).