US-FDA-monitor avatar

US-FDA-monitor

Pricing

$4.00 / 1,000 result items

Go to Apify Store
US-FDA-monitor

US-FDA-monitor

Query and monitor official U.S. FDA enforcement recalls for drugs, medical devices, and food with normalized, traceable Dataset results.

Pricing

$4.00 / 1,000 result items

Rating

0.0

(0)

Developer

hugo liu

hugo liu

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

US FDA Recall Monitor

Query and monitor official U.S. Food and Drug Administration (FDA) enforcement records for drugs, medical devices, and food. Get normalized, traceable rows from the public openFDA API without writing pagination, filtering, or change-detection code.

Use it for compliance checks, product-safety research, pharmacovigilance workflows, regulatory dashboards, and scheduled recall feeds. Each row keeps the source identity, recall details, official API URL, change metadata, and a stable idempotency key.

Before you run

  • For a one-off API call, use lookup or export. monitor is stateful and returns only new or changed rows after its snapshot has been established.
  • Actor usage costs $0.004 per result, equivalent to $4 per 1,000 results, under Pay Per Event pricing. Runs with zero results have no result-item usage charge. See the Pricing tab for the current terms.
  • Data is returned from openFDA at fetch time. This Actor does not provide a real-time freshness guarantee or an SLA for upstream publication delays.
  • Start with one product type and a small maxResults; maxResults: 0 can traverse a large result set and is not an unlimited historical archive.

What this Actor does

  • Queries the official openFDA drug/enforcement, device/enforcement, and food/enforcement datasets.
  • Filters by product type, recall number, recalling firm, FDA classification, status, state, keyword, and inclusive report-date windows.
  • Normalizes FDA dates such as YYYYMMDD to YYYY-MM-DD and flattens selected brand and generic name arrays.
  • Runs as a one-off current lookup, a bounded export, or an incremental monitor.
  • Writes structured records to the run's Apify Dataset, with JSON, CSV, and Excel download views generated from that same Dataset.
  • Keeps monitor fingerprints in a named Apify Key-Value Store and emits ADDED or UPDATED records for a stable query scope.

Why teams use it

This is a source-first FDA data feed: clean enough for automation, explicit enough for audit trails, and small enough to start with a single bounded query. It uses the government's machine-readable endpoint rather than fragile browser automation, while leaving the original FDA values available for downstream review.

Typical use cases include:

  • Monitoring Class I, Class II, or Class III enforcement activity.
  • Checking a product category or recalling firm over a defined date window.
  • Building a research or compliance dataset for a BI tool or data warehouse.
  • Scheduling a recurring monitor that emits only newly seen or changed rows.

Data source and scope

Product typeOfficial endpointData returned
drugapi.fda.gov/drug/enforcement.jsonDrug enforcement and recall records
deviceapi.fda.gov/device/enforcement.jsonMedical-device enforcement and recall records
foodapi.fda.gov/food/enforcement.jsonFood enforcement and recall records

The Actor reads public openFDA enforcement data. An upstream openFDA API key is optional and can be supplied for higher limits; it is not included in Dataset output. The Actor does not query adverse-event, labeling, approval, or 510(k) datasets, and it does not independently validate clinical, legal, or product-safety claims.

The source is current at fetch time, but it is not a complete historical archive owned by this Actor. Use an explicit reportedSince/reportedUntil window for a reproducible historical export and retain the resulting Dataset in your own workflow when long-term archival is required.

Request and resource notes

  • Selected product-type endpoints are queried sequentially. A multi-type query can therefore make several paginated upstream request series.
  • maxResults limits normalized records considered before the monitor diff is applied. In monitor mode, the number of emitted events can be lower or zero.
  • maxResults: 0 removes the Actor-side result cap but still respects the per-endpoint pagination ceiling; it does not fetch an unlimited archive.
  • apiKey changes the openFDA upstream limit only. It is not an alternative to the Apify API token used to start a run or read a private Dataset.

Run modes

ModeWhat it returnsState behavior
lookupMatching current source records as CURRENTDoes not read or change monitor state
exportA bounded current-source result set as CURRENTDoes not read or change monitor state
monitorNew and changed records as ADDED or UPDATEDReads and updates the named Key-Value Store

lookup is useful for a focused check, export for a defined report-date window, and monitor for a recurring workflow. The default mode is monitor; when it has no explicit reportedSince, the Actor uses lookbackDays before today as the fetch window.

Quick start

Apify Console

  1. Open the Actor and select Input.
  2. Choose lookup, export, or monitor.
  3. Select one or more productTypes and add a precise filter.
  4. Keep maxResults small for the first run, then click Start.
  5. Open the run's Dataset or use the JSON, CSV, and Excel links in the Output tab.

Apify CLI

After installing and authenticating the Apify CLI, run a bounded lookup:

apify call <ACTOR_ID> \
--input '{"mode":"lookup","productTypes":["drug"],"classification":"Class I","maxResults":10}' \
--output-dataset

<ACTOR_ID> can be the Actor ID or an authorized Actor name. A valid query with no matches completes successfully with zero Dataset items.

REST API

Start a run with a JSON body:

curl -X POST \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"mode": "lookup",
"productTypes": ["food"],
"keyword": "allergen",
"reportedSince": "2025-01-01",
"reportedUntil": "2025-12-31",
"maxResults": 100
}' \
"https://api.apify.com/v2/acts/<ACTOR_ID>/runs?waitForFinish=60"

The response includes the run status and defaultDatasetId. Read the same Dataset through the Apify API:

GET https://api.apify.com/v2/datasets/<DATASET_ID>/items?format=json&clean=true
GET https://api.apify.com/v2/datasets/<DATASET_ID>/items?format=csv&clean=true&attachment=true
GET https://api.apify.com/v2/datasets/<DATASET_ID>/items?format=xlsx&clean=true&attachment=true

Use limit and offset for pagination. Keep $APIFY_TOKEN in an environment variable; never put it in Actor input, source code, logs, or Dataset records.

API run lifecycle

The POST request starts an Apify run; it does not return Dataset rows directly. If waitForFinish=60 returns a non-terminal status such as RUNNING, keep the returned runId and poll GET /v2/actor-runs/<RUN_ID> or use a Webhook. Read defaultDatasetId after the run reaches SUCCEEDED. A successful empty Dataset is valid; in monitor mode it can mean that no record changed, not that the source had no matching records.

Input API reference

The input is a JSON object. The ./.actor/input_schema.json is the machine-readable contract used by the Console and API.

FieldType / defaultDescription
modeenum, "monitor"monitor, lookup, or export.
productTypesarray; default drug, device, foodFDA enforcement datasets to query. Allowed values are drug, device, and food; the array must not be empty.
keywordstringPartial terms matched locally across product description, recall reason, recalling firm, code information, and more-code information. All normalized terms must be present.
recallNumberstringExact recall number match after case and punctuation normalization.
recallingFirmstringCase-insensitive partial recalling-firm match.
classificationenumClass I, Class II, or Class III.
statusenumOngoing, Completed, or Terminated.
statestringFirm state value, normally a two-letter U.S. state code such as NJ.
reportedSinceYYYY-MM-DDInclusive lower bound for report_date.
reportedUntilYYYY-MM-DDInclusive upper bound for report_date.
lookbackDaysinteger, 14Monitor-only lookback when reportedSince is omitted. Range: 03650.
maxResultsinteger, 500Maximum normalized records considered/emitted. Range: 025000; in monitor the final event count can be lower. 0 removes the Actor-side cap within the per-endpoint pagination ceiling.
emitInitialSnapshotboolean, trueIn monitor, emit first-seen records as ADDED; set false to seed state without emitting the initial snapshot.
monitorIdstringOptional stable namespace for separate monitors sharing one state store.
stateStoreNamestring, "us-fda-monitor-state"Named Apify Key-Value Store used for monitor fingerprints.
apiKeysecret stringOptional openFDA API key for higher upstream limits. It is not written to output.

Query behavior and validation

  • Dates must be real calendar dates in YYYY-MM-DD; invalid dates such as 2026-02-30 are rejected.
  • reportedSince cannot be after reportedUntil.
  • Filters are sent to openFDA where supported and then applied again after normalization before maxResults is applied.
  • Product types are queried sequentially. A multi-type query can therefore make one upstream request series per selected product type.
  • The Actor paginates each endpoint in bounded batches and stops at its configured result limit. maxResults: 0 does not mean an unlimited archive; openFDA and the Actor still impose pagination ceilings.
  • A valid query with no matches returns SUCCEEDED with an empty Dataset. Invalid input, malformed upstream JSON, or an unrecoverable upstream error fails the run with an explanatory message.

Example inputs

Current Class I drug recalls

{
"mode": "lookup",
"productTypes": ["drug"],
"classification": "Class I",
"maxResults": 25
}

Historical food enforcement export

{
"mode": "export",
"productTypes": ["food"],
"reportedSince": "2015-01-01",
"reportedUntil": "2015-12-31",
"maxResults": 1000
}

Monitor a topic across all FDA product types

{
"mode": "monitor",
"productTypes": ["drug", "device", "food"],
"keyword": "listeria",
"lookbackDays": 14,
"maxResults": 500,
"monitorId": "listeria-watch"
}

Valid empty result and invalid input

An exact lookup for a number that is not in the selected source is a valid request and returns an empty Dataset:

{
"mode": "lookup",
"productTypes": ["drug"],
"recallNumber": "not-a-real-recall",
"maxResults": 1
}

An input such as {"reportedSince":"2026-02-30"} is rejected before an upstream request because the date is not a real calendar date.

For abnormal upstream behavior, the Actor retries bounded transient failures such as 429, 5xx, network errors, and timeouts. Malformed JSON and other unrecoverable responses fail the run with an explanatory error; they are not silently converted to an empty Dataset.

Output API reference

Each Dataset item is one normalized FDA enforcement record. Missing source values are represented by an empty string, an empty array, or null for date fields, according to the field contract.

Representative lookup output

The following is a trimmed example showing the output shape; the complete row contains every field listed below. Hash values are placeholders for the actual 64-character values generated by the run.

{
"source": "fda",
"sourceRecordId": "drug:D-1234-2026",
"recordType": "recall",
"changeType": "CURRENT",
"changedFields": [],
"productType": "drug",
"recallNumber": "D-1234-2026",
"title": "Example Drug 10mg Tablets",
"productDescription": "Example Drug 10mg Tablets, 100-count bottle",
"recallingFirm": "Example Pharma Inc.",
"classification": "Class I",
"status": "Ongoing",
"reasonForRecall": "Failed dissolution specifications",
"reportDate": "2026-01-15",
"brandNames": ["Example"],
"genericNames": ["Example drug"],
"sourceUrl": "https://api.fda.gov/drug/enforcement.json?search=recall_number:D-1234-2026",
"detectedAt": "2026-09-02T00:00:00.000Z",
"contentHash": "<sha256>",
"idempotencyKey": "<sha256>"
}

For monitor, the same content fields are accompanied by ADDED or UPDATED; changedFields lists normalized fields that changed since the prior snapshot. CURRENT is used by lookup and export.

Identity and monitor metadata

FieldTypeDescription
sourcestringAlways fda.
sourceRecordIdstringStable identity formed from product type and the FDA recall_number or event_id.
recordTypestringAlways recall for this Actor.
changeTypestringADDED, UPDATED, or CURRENT.
changedFieldsstring[]Normalized fields changed since the previous monitor snapshot; empty for ADDED and CURRENT.
detectedAtISO timestampTime this Actor produced the row.
contentHashstringSHA-256 hash of the normalized source snapshot, excluding derived monitor metadata.
idempotencyKeystringStable key for monitor scope, source record, and content version. Use it to deduplicate retries.

FDA record fields

FieldTypeDescription
productTypestringdrug, device, or food.
recallNumberstringFDA recall number when supplied.
eventIdstringFDA event identifier when supplied.
titlestringShort title derived from the product description, capped at 240 characters.
productDescriptionstringFDA product description.
recallingFirmstringFirm initiating or named in the recall.
citystringFirm city.
statestringFirm state.
countrystringFirm country.
classificationstringFDA recall classification.
statusstringFDA recall status.
voluntaryMandatedstringFDA voluntary/mandated value.
distributionPatternstringReported distribution pattern.
productQuantitystringReported quantity.
reasonForRecallstringFDA reason for recall.
recallInitiationDatestring or nullNormalized initiation date in YYYY-MM-DD.
centerClassificationDatestring or nullNormalized FDA center classification date.
terminationDatestring or nullNormalized termination date when supplied.
reportDatestring or nullNormalized FDA report_date.
codeInfostringProduct lot, code, or identifying information.
moreCodeInfostringAdditional code information.
brandNamesstring[]Brand names from the source's openfda object when supplied.
genericNamesstring[]Generic names from the source's openfda object when supplied.
sourceUrlstringOfficial openFDA endpoint/query URL used for the record.

The Actor pushes structured rows only. Apify derives these representations from the same Dataset:

  • JSON: .../items?format=json&clean=true
  • CSV: .../items?format=csv&clean=true&attachment=true
  • Excel: .../items?format=xlsx&clean=true&attachment=true

For non-empty runs, this Actor names the current Dataset us-fda-monitor-results-<runId> after all rows are delivered. The Dataset ID does not change, so the Output links remain valid. Empty runs are not renamed into a long-lived named Dataset.

The other Actors in this product family do not automatically rename their Datasets. If you use all three, retain the returned Dataset IDs immediately or copy/name the results according to your account's retention policy.

Monitoring and delivery semantics

In monitor mode:

  1. Records are normalized and deduplicated by sourceRecordId.
  2. The Actor compares the normalized content with the snapshot in stateStoreName.
  3. New records become ADDED; changed records become UPDATED with changedFields.
  4. Dataset delivery completes before the checkpoint is written.

This is safe at-least-once delivery. If Dataset delivery succeeds but the checkpoint write fails, a later run may emit the same event again; downstream consumers should deduplicate with idempotencyKey. Records that disappear from a later rolling source window are not emitted as REMOVED, because absence may reflect pagination or the selected date/filter scope rather than an official withdrawal.

For scheduled monitoring, keep the same monitorId, stateStoreName, and query scope. The rolling date calculated from lookbackDays is not itself used to create a new state namespace every day.

The HTTP layer starts requests serially within one process, waits one second by default between request starts, retries transient network errors, 429, and 5xx responses with bounded exponential backoff and jitter, and honors Retry-After when supplied. These locks and limits are process-local; they do not provide account-wide rate limiting or cross-container exactly-once delivery.

Do not interpret an empty monitor Dataset as a negative safety result. Use lookup or export when the application needs the current matching records on every call.

Reliability and limitations

  • openFDA fields and availability can change. The Actor preserves the source values it maps, but it does not create a complete FDA data warehouse.
  • A broad multi-product or uncapped query can make many upstream requests and consume more runtime and platform resources. Start with one product type, one date window, and a small maxResults.
  • The Actor reports FDA enforcement data; it does not determine whether a product is clinically safe, whether a remedy was completed, or whether a recall applies to a particular person or inventory item.
  • Public data and API availability are subject to FDA/openFDA terms and operational limits. Review the current source guidance before operating at scale.

Local development

Requirements: Node.js 20 or newer.

npm install
npm test
npm run build
apify validate-schema

npm test includes simulated 429/Retry-After, 5xx, timeout, rate-limit, state-order, and delivery-failure cases. FDA currently has no real-source test:real script in this package; use a bounded apify run or API smoke when you need to verify a live current record, historical record, empty result, or source response. Do not use an unbounded export for smoke testing.

Attribution

This Actor consumes public FDA data through openFDA. Preserve sourceUrl, productType, and recallNumber when passing records downstream so users can inspect the authoritative source context.