openFDA Recall Monitor: Food, Drug & Device Enforcement Reports avatar

openFDA Recall Monitor: Food, Drug & Device Enforcement Reports

Pricing

from $0.50 / 1,000 recalls

Go to Apify Store
openFDA Recall Monitor: Food, Drug & Device Enforcement Reports

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

Trevor Staubach

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

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 category column. 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 sends 20261014), empty strings as null, 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

FieldWhat it does
categoriesfood, drug, device (default: all three). Food includes dietary supplements.
keywordsAny 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.
keywordFieldsWhere to look for keywords: product_description, reason_for_recall (default both), code_info, recalling_firm, distribution_pattern.
firmsRecalling 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.
reasonKeywordsExtra AND filter on the reason, e.g. undeclared or sterility.
classificationsClass I, Class II, Class III, Not Yet Classified (default all).
statusesOngoing, Completed, Terminated (default all). This is the status at publication (see Limits), not the current status.
firmStatesUS state of the recalling firm (code or name).
distributedTo / includeNationwideKeep recalls whose distribution mentions these states; nationwide recalls are kept by default. Best-effort, because FDA writes distribution as free text.
excludeKeywordsDrop rows whose product, reason or firm contains these words (not charged).
lookbackDaysDate window counted back from today (default 30).
dateFrom / dateToOptional fixed window (YYYY-MM-DD). Overrides lookbackDays.
dateFieldDate the window applies to: report_date (default), recall_initiation_date or center_classification_date.
maxItemsCost 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 / monitorKeyMonitor mode and the name of its memory (see Scheduling a monitor for how filter changes and maxItems affect it).
apiKeyOptional 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.

FieldDescription
categoryfood, drug or device
recallNumber / eventIdFDA recall number (e.g. H-0014-2027) and recall event ID. Not-yet-classified drug recalls have N/A.
classification / statusClass 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.
reportDateWeek the recall appeared in FDA's Enforcement Report (YYYY-MM-DD)
recallInitiationDate / centerClassificationDate / terminationDateOther dates, YYYY-MM-DD
recallingFirm, city, state, country, postalCodeThe recalling firm and its address
productDescription / productQuantity / productTypeWhat was recalled and how much
reasonForRecallFDA's reason text
distributionPatternWhere it was distributed (free text)
codeInfo / moreCodeInfoLot numbers, best-by dates, model numbers
voluntaryMandated / initialFirmNotificationHow the recall was started and communicated
brandNames, genericNames, manufacturerNames, productNdc, packageNdc, upcopenFDA's harmonized fields (mostly drugs). openFDA links these by NDC, so they can list more package sizes or labelers than the recall itself.
upcInText / ndcInTextUPC / 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.
matchedKeywordsWhich of your keywords appear in the row
fdaReportUrlFDA enforcement report search for this recall number
dedupeKeycategory: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 / isNewRun 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

  1. Set your filters, turn on Monitor mode (onlyNew), and give it a monitorKey such as supplier-watch.
  2. Run it once. The first run returns everything in the look-back window and saves it as the baseline.
  3. Go to Schedules > Create, pick this Actor and this input, and run it daily or weekly (openFDA updates weekly, so hourly runs add nothing).
  4. 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 lookbackDays at 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.
  5. 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 a monitorKey, 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.
  • maxItems and the baseline. If a run hits maxItems, 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 with maxItems: 0 or 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 distributedTo or excludeKeywords are not charged.
  • Cap spend with maxItems or 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_updated date 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.
  • status is 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 via fdaReportUrl).
  • 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). matchedKeywords shows 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).