openFDA — Drug Labels, Adverse Events, Recalls, Devices
Pricing
from $30.00 / 1,000 search runs
openFDA — Drug Labels, Adverse Events, Recalls, Devices
Query the FDA's own open data: prescribing information from drug labels, adverse event reports from FAERS, drug, food and device recalls, and 510(k) device clearances. Field-scoped searches, date ranges, no API key.
Pricing
from $30.00 / 1,000 search runs
Rating
0.0
(0)
Developer
Benjamin Jerez
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
openFDA — Drug Labels, Adverse Events, Recalls and Device Clearances
Six FDA datasets behind one input form. Ask for a drug by brand or ingredient, a firm by name, a hazard class or a date range, and get back the prescribing information, the adverse event reports, the recalls and the device clearances that match.
No API key. The data is US federal government work in the public domain, queried live on every run.
What is in each dataset
| Dataset | Endpoint | Records | Date field used for filtering |
|---|---|---|---|
| Drug labels | /drug/label.json | 262 883 | effective_time |
| Adverse events (FAERS) | /drug/event.json | 20 692 627 | receiptdate |
| Drug recalls | /drug/enforcement.json | 17 965 | recall_initiation_date |
| Food recalls | /food/enforcement.json | 29 406 | recall_initiation_date |
| Device recalls | /device/enforcement.json | 39 949 | recall_initiation_date |
| Device clearances (510k) | /device/510k.json | 176 070 | decision_date |
The date field differs per dataset and so does the field a manufacturer lives in. You give one date range and one list of company names; the Actor translates them per endpoint, and the summary row prints the search string it actually sent.
What a run returns
Every dataset produces a summary row first, then the records.
Searching foodEnforcement for Listeria, Class I, initiated between 2025-01-01 and 2025-06-30:
rowType summarydataset foodEnforcementsearchString (product_description:"Listeria" OR reason_for_recall:"Listeria")AND recall_initiation_date:[20250101 TO 20250630]AND classification:"Class I"totalMatching 127returned 4capped false
and the records:
recallInitiationDate | classification | recallingFirm | productDescription | reasonForRecall |
|---|---|---|---|---|
| 20250527 | Class I | AND GO CONCEPTS DBA SALAD AND GO | FG20004 Cucumber, Sliced, poly bag | Potential to be contaminated with Listeria monocytogenes |
| 20250510 | Class I | Fresh & Ready Foods LLC | Fresh Take Crave Away Club Supreme Sub Sandwich, 6oz | Listeria monocytogenes detected on food contact surfaces |
A drug label search for Lipitor returns one record: generic ATORVASTATIN CALCIUM, labeller Viatris Specialty LLC, application NDA020702, UNII 48A5M73Z4Q, eight RxCUI codes, four NDCs, effective 20240415, plus the indications, dosage, contraindications, warnings, adverse reactions, interactions, pregnancy, paediatric and geriatric sections as plain text.
A device clearance search for insulin pump decided in 2024 or 2025 returns five: K253074 Tandem Mobi (Tandem Diabetes Care, decided 2025-11-06), K251032 MiniMed 780G (Medtronic Minimed, 2025-07-01), and three more Tandem filings. All product code QFG, class 2, regulation 880.5730, Traditional 510(k), Substantially Equivalent.
How the search is built
Every value you supply is quoted and prefixed with a field name. This is the difference between a search and a word count.
| Query | Hits | What comes back |
|---|---|---|
openfda.brand_name:"Tylenol" | 111 | Tylenol products |
Tylenol | 3 142 | Any label mentioning the word, mostly other painkillers |
openfda.brand_name:"Advil PM" | 6 | Advil PM |
openfda.brand_name:Advil PM | 10 235 | An OR of two common words |
openFDA scores rather than filters when you leave the field off, so an unscoped term ranks the whole index and hands back the top of it. Unquoted multi-word terms are split into an OR. Neither failure raises an error; both just return plausible-looking rows about the wrong thing. The Actor never emits either form, and the searchString field on the summary row lets you check.
Within one filter, values are combined with OR, so two brand names widen the search. Between filters they are combined with AND, so a brand plus a date range narrows it.
Reading FAERS adverse events correctly
A FAERS report lists every drug the patient was on, not only the one suspected of causing the reaction. openFDA's patient.drug.* fields cover all of them, so searching a drug returns reports where it was merely background medication.
This is not a small effect. Searching serious 2025 reports for semaglutide matches 10 866 reports; of the first twelve, eleven list semaglutide only as a concomitant drug and one as a suspect drug. The suspect drugs in the other eleven were Xolair, Xyrem, Actemra, Revlimid and others.
Each adverse event row therefore carries queryDrugRole:
suspect— the reporter named the drug you searched for as a causeconcomitant— the patient was also taking it- empty — no drug on the report matched your term, which happens when a free-text term matched a reaction name instead; searching
insulinreturns report 10032297 because it lists the reaction "Insulin-like growth factor decreased"
Filter on suspect before counting anything. The row also carries suspectDrugs and concomitantDrugs separately, and outcomes as words rather than the FAERS digit codes — death, hospitalisation, disabling, life-threatening, congenital anomaly, other serious.
A brand name may not mean the brand
openFDA harmonises each reported drug against its product index and attaches every brand name that shares the ingredient. The aspirin entry carries more than 130 of them, from Bayer to Ecotrin to a supermarket own-label.
The consequence is blunt. patient.drug.openfda.brand_name:"Ecotrin" matches 515 357 reports; only 8 538 reports actually named Ecotrin. The rest reported plain aspirin and were harmonised into the same brand list.
So every adverse event row also carries queryDrugReportedAs — the product string the reporter actually wrote for the drug that matched your search. Searching Ecotrin and reading that column shows ASPIRIN on nine rows out of ten and ECOTRIN on one. If you need reports that named the brand, filter on it.
Distinctive brands do not suffer this. Lipitor matches 248 030 reports against 180 902 that named it, an expansion of atorvastatin generics rather than a different drug.
A report is a report. FAERS submissions are unvalidated, unverified and carry no denominator, so they do not establish that a drug caused anything.
Label text is truncated
Drug label sections are arrays of long prose. The longest single section seen while building this Actor was 69 834 characters; several routinely pass 30 000. In one test run of forty labels, sixteen had at least one section over the limit.
Each section is joined, whitespace-collapsed and cut at 4 000 characters, with […] marking the cut. The row lists every section it shortened in truncatedFields, and labelUrl points at the complete label on DailyMed.
The sections returned are boxed warning, indications and usage, dosage and administration, contraindications, warnings and cautions, adverse reactions, drug interactions, pregnancy, paediatric use, geriatric use and mechanism of action. hasBoxedWarning is a boolean you can filter on directly.
Empty results are not errors
openFDA answers a search that matches nothing with HTTP 404 and {"error":{"code":"NOT_FOUND","message":"No matches found!"}}. That is a valid answer: the query was understood, the index holds nothing for it.
The Actor treats it as such. You get a summary row with totalMatching: 0 and a note saying so, not a failed run. Searching Ozempic across food recalls, device recalls and device clearances produces three such rows in a single run, alongside the 18 767 adverse events that do exist.
The 26 000 record ceiling
openFDA refuses limit above 1 000 and skip above 25 000, which puts a hard ceiling of 26 000 records on any single search. Past that it returns HTTP 400 with Skip value must 25000 or less.
When a run hits the ceiling, the summary row sets capped: true and the note says how many records matched against how many were reachable. To get the rest, split the run into narrower date ranges — the dateFrom and dateTo inputs exist partly for this.
Who uses this
Pharmacovigilance and drug safety teams pulling FAERS signals for a molecule without maintaining their own extract of a twenty-million-row dataset. Regulatory affairs staff tracking competitor 510(k) clearances by product code or applicant. Food safety and supply chain teams watching recalls by firm, state or hazard class. Clinical decision support and formulary tools that need the current prescribing information keyed to an NDC or RxCUI. Health journalists and researchers who need a defensible, citable query rather than a screenshot of a search page.
Scope and limits
Labels are current, not historical. /drug/label.json holds the label in force now, one record per SPL set id. effective_time is when that version took effect. A date range on it selects labels whose current version took effect in that window, which is not the same as labels that were in force then. Ozempic has four label records with effective times in 2023 and 2026 and none in 2025, so a 2025 range returns nothing.
FAERS is a passive reporting system. No denominator, no verification, heavy reporting bias toward newly marketed and heavily litigated drugs, and duplicate reports are common enough that the raw records carry a duplicate flag.
Recalls are what the firm and the FDA district office wrote down. Product descriptions are free text, so a brand may be spelled several ways across a single event. Search the product description with more than one spelling if the brand matters.
510(k) covers clearances, not approvals. A cleared device was found substantially equivalent to a predicate. PMA approvals and De Novo grants are separate datasets, not covered here.
Rate limits. Without a key openFDA allows 240 requests per minute and 1 000 per day, shared across everyone calling from the same address. One dataset at the 26 000 ceiling costs 26 requests, so a normal run is nowhere near either limit.
Source and licence
openFDA at api.fda.gov, operated by the US Food and Drug Administration. US federal government works in the public domain; terms at open.fda.gov/terms, licence at open.fda.gov/license.
The FDA's own disclaimer applies and is worth repeating: the data is not validated, and it is not a basis for decisions about medical care.
Index freshness at the time of writing: drug labels 2026-09-18, recalls 2026-09-09, device clearances 2026-09-07, adverse events 2026-07-30. Each response carries its own last_updated.
Frequently asked
Why did my brand name return nothing?
Because openfda.brand_name is populated from the structured label, not from the text. Generic and repackaged products often carry the generic name only. Try the ingredient in Generic names, or put the term in Search terms, which covers brand, generic and substance fields at once.
Why does one drug return several label records?
One record per SPL set id. Repackagers and relabellers file their own, so Ozempic has four and a common generic can have hundreds. manufacturerName tells them apart; setId is the stable identifier.
Can I get more than 26 000 records for one search? Not in one search. Split it by date range and run again. The Actor tells you when you have hit the ceiling rather than silently stopping.
Are the adverse event counts a safety signal?
No. They are report counts with no exposure denominator, and the total on the summary row counts every report the drug appears anywhere in. Use queryDrugRole: suspect as a floor, check queryDrugReportedAs for what was actually reported, treat the rest as context, and read the FDA's own guidance before drawing a conclusion.
Why is a field empty?
openFDA harmonises records against its own product index and leaves the openfda block out when it cannot match. Drug recalls in particular frequently have no openfda block at all, which is why recalls are searched on product_description and recalling_firm rather than on structured names.
What counts as a charged record?
One search-run event per dataset per run, including one that legitimately returns nothing, and one record-returned event per record pushed.