FDA Drug Recalls
Drug recalls and related enforcement reports from the FDA.
fda_drug_recalls — the dataset name to pass to the Obscura API.
What one row means
One drug recall event as compiled into a single week's FDA Enforcement Report and mirrored by the keyless openFDA `drug/enforcement` endpoint — the firm's recall action against one lot/product line, tagged with FDA's severity classification (Class I/II/III) and current disposition (Ongoing/Completed/Terminated).
One row per recall_number.
Point-in-time availability
Every Obscura dataset carries available_date: the calendar day the publisher made the row
available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the
same thing on every dataset in the catalog.
For fda_drug_recalls: published: available_date = openFDA's report_date, the date FDA published this recall in its weekly Enforcement Report (the day the row became publicly known).
Refresh cadence
Obscura refreshes fda_drug_recalls daily — the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.
Schema — 21 columns
The full public column list for fda_drug_recalls, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/fda_drug_recalls.
| Column | Type | Description |
|---|---|---|
| recall_number | text · not null | FDA's own recall identifier, e.g. 'D-0643-2026' (D=Drug enforcement record, sequence-YEAR). Primary key, not auto-increment; the collector upserts on this column via OnConflict::column(RecallNumber). Sourced from openFDA `results[].recall_number`. |
| available_date | date | openFDA's `report_date` (parsed from %Y%m%d) — the date FDA published this recall in its weekly Enforcement Report, i.e. the day the row became publicly known. Also the field the collector sorts/paginates and windows on (`sort=report_date:desc`, cutoff = today - lookback_days). Confirmed-correct public-availability date; NOT the firm's recall_initiation_date, which precedes it and is currently uncaptured. |
| recalling_firm | text | Name of the company that initiated/is responsible for the recall (openFDA `recalling_firm`), e.g. 'CareFusion 213, LLC'. Freeform manufacturer/distributor name; can be mapped to a parent-company ticker downstream via a name crosswalk, but is not itself a resolved identifier. |
| classification | text | FDA's severity tier for the recall (openFDA `classification`): 'Class I' (reasonable probability of serious harm/death), 'Class II' (temporary/reversible harm), or 'Class III' (unlikely to cause harm, e.g. labeling defects). Can be reclassified after initial filing; the collector's OnConflict update_columns refreshes this on re-sync. |
| status | text | Current lifecycle state of the recall action (openFDA `status`): 'Ongoing', 'Completed', or 'Terminated'. Mutable over the life of a recall_number and refreshed on upsert (listed in the OnConflict update_columns set). |
| voluntary_mandated | text | Whether the recall was firm-initiated or FDA-ordered (openFDA `voluntary_mandated`), e.g. 'Voluntary: Firm initiated'. Nearly all drug recalls are voluntary since FDA mandatory-recall authority for drugs is narrow (mainly compounded/biologics contexts). |
| reason_for_recall | text | Free-text explanation of why the product was recalled (openFDA `reason_for_recall`), e.g. 'Lack of assurance of sterility: Unsterilized ChloraPrep & PurPrep Applicators...'. The primary human-readable safety-signal payload; no fixed vocabulary/enum. |
| product_description | text | Free-text description of the recalled product(s) (openFDA `product_description`), typically embedding brand name, strength/formulation, NDC codes, catalog numbers, pack sizes, and manufacturing-site details, e.g. 'BD ChloraPrep Hi-Lite Orange... NDC 54365-400-35...'. Not structured/parsed into discrete NDC/catalog fields. |
| event_id | text | FDA enforcement-report event id (openFDA `event_id`), e.g. '99217'. Groups the many `recall_number` rows that belong to one recall action; a grouping identifier not reconstructable from the kept columns. |
| recall_initiation_date | date | Firm's actual recall action date (openFDA `recall_initiation_date`, parsed from %Y%m%d), which PRECEDES `report_date`. This is the true event date but NOT the public-availability date — kept as its own natural date to avoid a look-ahead against `available_date`. |
| center_classification_date | date | Date FDA's center assigned the Class I/II/III severity (openFDA `center_classification_date`, parsed from %Y%m%d); a distinct natural date between initiation and report. |
| product_quantity | text | Magnitude of product recalled (openFDA `product_quantity`), e.g. '1,800 units' / '4284 vials'. Free-text recall-size / exposure signal not present in the other columns. |
| code_info | text | Recalled lot numbers and expiration dates (openFDA `code_info`), e.g. 'Lot: 3362296, expires 12/31/2026, ...'. Identifies exactly which lots are affected; only partly echoed inside `product_description`. |
| distribution_pattern | text | Geographic/market scope of distribution (openFDA `distribution_pattern`), e.g. 'Distributed Nationwide in the USA'; a coarse exposure-breadth signal. |
| city | text | Recalling firm's city (openFDA `city`), e.g. 'El Paso'. Firm HQ / plant location; useful for supply-chain / origin analysis. |
| state | text | Recalling firm's state/province (openFDA `state`), e.g. 'TX'. Firm HQ / plant location. |
| country | text | Recalling firm's country (openFDA `country`), e.g. 'United States' / 'India'. Firm HQ / plant location. |
| postal_code | text | Recalling firm's postal/ZIP code (openFDA `postal_code`), e.g. '79912-8000'. Firm HQ / plant location. |
| address_1 | text | Recalling firm's street address line 1 (openFDA `address_1`), e.g. '1550 Northwestern Dr'. Firm HQ / plant location. |
| address_2 | text | Recalling firm's street address line 2 (openFDA `address_2`); suite/unit continuation of `address_1`. |
| initial_firm_notification | text | How the firm first notified customers of the recall (openFDA `initial_firm_notification`), e.g. 'Letter' / 'Press Release' / 'E-Mail'; a small categorical dimension. |
Access fda_drug_recalls
Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.
import obscura
client = obscura.Client("obs_live_…")
df = client.query(
dataset="fda_drug_recalls",
start="2024-01-01",
)
Create a free account Browse all 95 datasets
Frequently asked questions
What is in the fda_drug_recalls dataset?
Drug recalls and related enforcement reports from the FDA. One drug recall event as compiled into a single week's FDA Enforcement Report and mirrored by the keyless openFDA `drug/enforcement` endpoint — the firm's recall action against one lot/product line, tagged with FDA's severity classification (Class I/II/III) and current disposition (Ongoing/Completed/Terminated).
How do I avoid look-ahead bias with fda_drug_recalls?
Filter on fda_drug_recalls.available_date, the day the publisher made the row public. For this dataset that date is derived as follows — published: available_date = openFDA's report_date, the date FDA published this recall in its weekly Enforcement Report (the day the row became publicly known). A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.
In what formats can I get fda_drug_recalls?
As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="fda_drug_recalls". The column schema is public at https://api.obscura.trade/v1/catalog/fda_drug_recalls.
How often is fda_drug_recalls updated?
Obscura refreshes fda_drug_recalls on a daily schedule — that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.