# openFDA Scraper — FDA Recalls, 510(k), NDC & Adverse Events (`haketa/openfda-scraper`) Actor

Scrape the official openFDA API — drug/device/food recalls, device 510(k) clearances, the drug NDC directory and FAERS adverse events. Keyless, full Lucene search. For pharma and med-device intel, recall monitoring, pharmacovigilance and litigation research.

- **URL**: https://apify.com/haketa/openfda-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Business
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## openFDA Scraper — FDA Recalls, 510(k) Clearances, Drug NDC & Adverse Events

[![Apify Actor](https://img.shields.io/badge/Apify%20Actor-Ready-brightgreen.svg?style=flat-square\&logo=apify)](https://apify.com/haketa/openfda-scraper)
[![Maintenance](https://img.shields.io/badge/Maintained-Active-blue.svg?style=flat-square)](https://apify.com/haketa/openfda-scraper)
[![Data Format](https://img.shields.io/badge/Format-JSON%20%7C%20CSV%20%7C%20Excel-orange.svg?style=flat-square)](https://apify.com/haketa/openfda-scraper)
[![Records Per Run](https://img.shields.io/badge/Scale-Up%20to%2025%2C000%20Records-blueviolet.svg?style=flat-square)](https://apify.com/haketa/openfda-scraper)
[![Official FDA Data](https://img.shields.io/badge/Source-Official%20FDA%20Open%20Data-success.svg?style=flat-square)](https://apify.com/haketa/openfda-scraper)

Extract official, structured regulatory data from the US Food and Drug Administration's **openFDA** database. Retrieve clean, standardized records across **drug, medical device, and food recalls (Enforcement Reports)**, **510(k) medical device premarket clearances**, the **National Drug Code (NDC) Directory**, and **FAERS post-marketing drug adverse event reports**.

Execute full openFDA Lucene queries with Boolean filters, field scoping, and custom sorting. Every record is normalized into tidy columns with unified summary fields, unpacked nested clinical arrays, and standardized ISO dates.

No API keys needed, no browser overhead, and zero complex infrastructure. Built for life sciences regulatory analysts, medical device competitive intelligence teams, pharmacovigilance specialists, clinical researchers, mass-tort / product-liability legal teams, and pharmaceutical supply chain monitors.

***

### ⚡ At a glance

| Feature | Specification |
|---|---|
| **Data Source** | Official US FDA Public API (`api.fda.gov`) |
| **Authentication** | Keyless & public (optional free API key supported to increase rate limits) |
| **Datasets Supported** | Drug Recalls, Device Recalls, Food Recalls, 510(k) Clearances, NDC Directory, FAERS Adverse Events |
| **Search Syntax** | Full Apache Lucene search queries (`field:value`, `AND`, `OR`, `NOT`, wildcards) |
| **Batch Efficiency** | Up to 1,000 records per individual request (ultra-fast 2–5s execution) |
| **Output Formats** | Dataset (JSON, CSV, XML, Excel), Live API, Webhooks, Google Sheets |
| **Scale & Pagination** | Automated `skip` pagination supporting up to 25,000 records per query |
| **Date Normalization** | Automatic conversion from FDA `YYYYMMDD` strings to ISO `YYYY-MM-DD` |
| **Proxy Requirement** | Apify Datacenter Proxy with automated session rotation |

***

### ⚖️ Comparison: openFDA Scraper vs Alternatives

| Criteria | openFDA Scraper (This Actor) | Raw openFDA API | FDA FOIA Requests |
|---|---|---|---|
| **Setup & Coding** | 🟢 Zero code, web UI + direct API | 🔴 Complex custom REST integration | 🔴 Manual paperwork & legal filings |
| **Data Normalization** | 🟢 Tidy flat columns + unified summary | 🔴 Deeply nested JSON / arrays | 🔴 Scanned PDFs and paper copies |
| **Date Formatting** | 🟢 ISO standard (`YYYY-MM-DD`) | 🔴 Raw integer strings (`YYYYMMDD`) | 🟡 Varies by document |
| **Pagination Handling** | 🟢 Auto-paging up to 25,000 records | 🔴 Manual skip/limit looping | 🔴 Not applicable |
| **Export Formats** | 🟢 Instant CSV, Excel, JSON, XML | 🔴 JSON only | 🔴 Static PDFs / paper records |
| **Turnaround Time** | 🟢 Instant (seconds) | 🟢 Instant (seconds) | 🔴 Weeks to months |

***

### 🎯 Key Use Cases

#### 1. Drug, Device & Food Recall Surveillance

Set up automated compliance pipelines to monitor urgent Class I (high risk of serious injury or death), Class II, and Class III recalls. Track specific pharmaceutical manufacturers (e.g. `recalling_firm:Pfizer`), therapeutic classes, or affected states to safeguard hospital supply chains and retail inventory.

#### 2. Medical Device Competitive Intelligence & Clearance Tracking

Track competitor 510(k) premarket clearance submissions (e.g. `applicant:Medtronic`, `applicant:Stryker`) and clearance dates (`decision_date:desc`). Monitor medical device market entry timelines, product codes, predicate device classifications, and advisory committee reviews.

#### 3. Pharmacovigilance & Adverse Event Analysis

Analyze real-world post-marketing safety data from the FDA Adverse Event Reporting System (FAERS). Query reported patient adverse reactions (MedDRA preferred terms), concomitant suspect medications, patient demographics, and seriousness indicators (hospitalization, life-threatening, death).

#### 4. Pharmaceutical Directory & National Drug Code (NDC) Enrichment

Build or enrich master pharmaceutical catalogs using authoritative NDC directory records. Extract proprietary brand names, non-proprietary generic names, active ingredient strengths, dosage forms, administration routes, and labeler/distributor corporate details.

#### 5. Product Liability & Legal Litigation Research

Construct authoritative evidence bases for medical device defect investigations, pharmaceutical mass-tort cases, and corporate regulatory compliance audits.

***

### 📊 Extracted Data Fields by Dataset

Every record includes standardized top-level fields: `recordType`, `title`, `date`, `summary`, and `scrapedAt`. Dataset-specific fields are detailed below:

#### 🚨 1. Recall Enforcement Reports (`drug-enforcement`, `device-enforcement`, `food-enforcement`)

| Field | Type | Description | Coverage |
|---|---|---|---|
| `recallNumber` | String | Official FDA recall tracking number (e.g. `D-0084-2027`) | 🟢 High (100%) |
| `classification` | String | Recall hazard level (`Class I`, `Class II`, `Class III`) | 🟢 High (100%) |
| `status` | String | Current status (`Ongoing`, `Completed`, `Terminated`) | 🟢 High (100%) |
| `recallingFirm` | String | Full corporate name of the firm initiating the recall | 🟢 High (100%) |
| `productType` | String | Regulated product category (`Drugs`, `Devices`, `Food`) | 🟢 High (100%) |
| `productDescription` | String | Detailed description of the recalled product and packaging | 🟢 High (100%) |
| `reasonForRecall` | String | Official medical/regulatory reason for the recall | 🟢 High (100%) |
| `distributionPattern`| String | Geographic distribution territory (e.g. `US Nationwide`, `CA, NY`) | 🟢 High (95%) |
| `voluntaryMandated` | String | Whether voluntary or FDA-mandated | 🟢 High (95%) |
| `city` / `state` / `country` | String | Corporate headquarters location of the recalling firm | 🟢 High (95%) |
| `recallInitiationDate` | String | Date the firm first initiated the recall (`YYYY-MM-DD`) | 🟢 High (95%) |
| `reportDate` | String | Date the recall was officially published by the FDA (`YYYY-MM-DD`)| 🟢 High (100%) |
| `brandNames` | Array | Brand name aliases extracted from the record | 🟡 Conditional (75%) |

#### 🩺 2. Medical Device 510(k) Clearances (`device-510k`)

| Field | Type | Description | Coverage |
|---|---|---|---|
| `kNumber` | String | Premarket 510(k) clearance number (e.g. `K231450`) | 🟢 High (100%) |
| `deviceName` | String | Trade name of the medical device | 🟢 High (100%) |
| `applicant` | String | Device sponsor / manufacturing company name | 🟢 High (100%) |
| `contact` | String | Primary corporate contact person | 🟢 High (90%) |
| `productCode` | String | Three-letter FDA product classification code | 🟢 High (98%) |
| `decisionCode` | String | FDA review outcome (e.g. `SESE` - Substantially Equivalent) | 🟢 High (100%) |
| `decisionDate` | String | Date the clearance decision was issued (`YYYY-MM-DD`) | 🟢 High (100%) |
| `dateReceived` | String | Date the FDA originally received the 510(k) application | 🟢 High (98%) |
| `clearanceType` | String | Application type (`Traditional`, `Special`, `Abbreviated`) | 🟢 High (95%) |
| `advisoryCommittee` | String | Review panel (e.g. `Cardiovascular`, `Orthopedic`, `General Hospital`) | 🟢 High (95%) |
| `deviceClass` | String | Regulatory risk classification (`1`, `2`, `3`) | 🟢 High (95%) |

#### 💊 3. National Drug Code (NDC) Directory (`drug-ndc`)

| Field | Type | Description | Coverage |
|---|---|---|---|
| `productNdc` | String | Standard National Drug Code identifier (e.g. `50580-449`) | 🟢 High (100%) |
| `brandName` | String | Proprietary commercial brand name (e.g. `TYLENOL`) | 🟢 High (95%) |
| `genericName` | String | Active pharmaceutical ingredient generic name | 🟢 High (95%) |
| `labelerName` | String | Name of the pharmaceutical distributor or manufacturer | 🟢 High (100%) |
| `dosageForm` | String | Physical form (e.g. `TABLET`, `CAPSULE`, `INJECTION`) | 🟢 High (98%) |
| `route` | Array | Administration route (e.g. `ORAL`, `INTRAVENOUS`) | 🟢 High (95%) |
| `marketingCategory`| String | Regulatory pathway (`NDA`, `ANDA`, `OTC MONOGRAPH FINAL`) | 🟢 High (95%) |
| `activeIngredients` | Array | Active substance ingredients with strength measurements | 🟢 High (95%) |
| `packaging` | Array | Commercial packaging units and NDC package codes | 🟢 High (95%) |

#### ⚠️ 4. FAERS Adverse Event Reports (`drug-event`)

| Field | Type | Description | Coverage |
|---|---|---|---|
| `safetyReportId` | String | Unique FDA safety report identifier | 🟢 High (100%) |
| `serious` | String | Seriousness code (`1` = serious event, `2` = other) | 🟢 High (100%) |
| `seriousnessDeath`| String | Indication if the adverse event resulted in patient death | 🟡 Conditional (when reported) |
| `receiveDate` | String | Date report was logged into the FDA database (`YYYY-MM-DD`) | 🟢 High (100%) |
| `patientSex` | String | Patient biological sex (`1` = Male, `2` = Female) | 🟢 High (90%) |
| `patientOnsetAge` | String | Numerical age at adverse event onset | 🟡 Conditional (75%) |
| `reactions` | Array | MedDRA preferred terms for adverse reactions | 🟢 High (100%) |
| `drugs` | Array | Suspect and concomitant medications administered | 🟢 High (100%) |
| `indications` | Array | Medical indications for which suspect drugs were taken | 🟢 High (85%) |
| `primarySourceCountry`| String | ISO country code of the reporting healthcare provider | 🟢 High (95%) |

***

### ⚙️ Input Parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `dataset` | String | `"drug-enforcement"` | Target endpoint: `"drug-enforcement"`, `"device-enforcement"`, `"food-enforcement"`, `"device-510k"`, `"drug-ndc"`, or `"drug-event"`. |
| `search` | String | `""` | openFDA Apache Lucene query string. Supports field qualifiers and Boolean operators. |
| `sort` | String | `""` | Sort expression (`field:desc` or `field:asc`), e.g. `report_date:desc`, `decision_date:desc`. |
| `maxItems` | Integer | `0` *(prefill: 100)* | Maximum records to extract (up to 25,000 per query). Set `0` for default 100. |
| `apiKey` | String | `""` | Optional free openFDA API key to increase rate limits. Not required for standard runs. |
| `proxyConfiguration` | Object | `{ "useApifyProxy": true }` | Apify proxy settings. Standard datacenter proxy handles all endpoints cleanly. |

***

### 🔍 Proven Lucene Search Query Recipes

Use these high-impact query templates in the `search` input field:

| Objective | Dataset | Lucene Query Expression |
|---|---|---|
| Urgent Class I Drug Recalls | `drug-enforcement` | `classification:"Class I" AND status:Ongoing` |
| Recalls by Specific Pharma Firm | `drug-enforcement` | `recalling_firm:Pfizer` |
| Medical Device Clearances by Company | `device-510k` | `applicant:Medtronic` |
| Cardiovascular Device Clearances | `device-510k` | `advisory_committee:CV` |
| Drug Product Search by Brand Name | `drug-ndc` | `brand_name:Tylenol` |
| Prescription Only Injectable Drugs | `drug-ndc` | `dosage_form:INJECTION AND marketing_category:NDA` |
| Adverse Events for Specific Medication | `drug-event` | `patient.drug.medicinalproduct:aspirin AND serious:1` |
| Pediatric Adverse Drug Reactions | `drug-event` | `patient.patientonsetageunit:801 AND patient.patientonsetage:[1 TO 12]` |

***

### 📦 Output Sample

Here is a representative JSON record output from the `drug-enforcement` dataset:

```json
{
  "recordType": "drug-enforcement",
  "title": "Greenwich Rx",
  "date": "2026-10-28",
  "summary": "Microbial Contamination of Sterile Products",
  "recallNumber": "D-0084-2027",
  "status": "Ongoing",
  "classification": "Class I",
  "recallingFirm": "Greenwich Rx",
  "productType": "Drugs",
  "productDescription": "Glutathione Injection, 200 mg/mL, 10 mL multi-dose vial, Rx only",
  "reasonForRecall": "Microbial Contamination of Sterile Products identified during sterility audit",
  "distributionPattern": "US Nationwide",
  "voluntaryMandated": "Voluntary: Firm initiated",
  "city": "Tomball",
  "state": "TX",
  "country": "United States",
  "recallInitiationDate": "2026-10-01",
  "reportDate": "2026-10-28",
  "brandNames": [
    "Glutathione"
  ],
  "eventId": "94812",
  "scrapedAt": "2026-11-10T14:40:00.000Z"
}
```

***

### ⚠️ Understanding FDA Recall Hazard Classifications

The FDA classifies recalls into three numeric classes based on the relative degree of health hazard:

| Hazard Classification | FDA Statutory Definition | Example Scenarios | Action Urgency |
|---|---|---|---|
| **Class I** | Dangerous or defective products that could cause serious adverse health consequences or death. | Non-sterile injectable drugs, endotoxin contamination, undeclared lethal allergens, defective life-supporting defibrillators. | 🚨 Urgent public warnings & immediate product removal |
| **Class II** | Products that might cause temporary or medically reversible adverse health consequences, or where the probability of serious injury is remote. | Subpotent prescription drugs, mislabeled dosage instructions, particulate matter in oral solutions. | 🟡 Standard commercial recall & patient notification |
| **Class III** | Products that violate FDA labeling or manufacturing regulations but are unlikely to cause adverse health consequences. | Minor container defects, minor labeling omissions, technical compliance issues without therapeutic compromise. | 🟢 Administrative product return or relabeling |

***

### 🏛️ Medical Device 510(k) Review Panels Reference

When filtering 510(k) medical device premarket clearances using `advisory_committee:` in your Lucene queries, use these standard two-letter panel codes:

| Panel Code | Advisory Committee Review Panel | Common Cleared Device Types |
|---|---|---|
| **`AN`** | Anesthesiology | Ventilators, gas delivery systems, monitors |
| **`CV`** | Cardiovascular | Vascular stents, heart valve catheters, ECG devices |
| **`DE`** | Dental | Dental implants, orthodontic aligners, bone graft matrix |
| **`GU`** | Gastroenterology & Urology | Endoscopes, hemodialysis machines, urinary catheters |
| **`HO`** | General Hospital & Personal Use | Infusion pumps, hypodermic syringes, hospital beds |
| **`NE`** | Neurological | Neurostimulators, cranioplasty plates, EEG monitors |
| **`OP`** | Ophthalmic | Intraocular lenses, diagnostic lasers, contact lens solutions |
| **`OR`** | Orthopedic | Spinal fusion cages, hip/knee prosthetic implants |
| **`RA`** | Radiology | CT scanners, MRI systems, medical imaging PACS software |

***

### 💻 API & Integration Examples

Integrate live FDA regulatory data directly into your Python analytical pipelines, Node.js services, or automation webhooks.

#### Python Example (Pharma Compliance Monitor)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run_input = {
    "dataset": "drug-enforcement",
    "search": "classification:\"Class I\" AND status:Ongoing",
    "sort": "report_date:desc",
    "maxItems": 100
}

run = client.actor("haketa/openfda-scraper").call(run_input=run_input)

for recall in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"[{recall['classification']}] {recall['recallingFirm']} - {recall['title']}: {recall['reasonForRecall'][:80]}...")
```

#### Node.js Example (Device Clearance Tracker)

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const input = {
    dataset: 'device-510k',
    search: 'decision_date:[20260101 TO 20261231]',
    sort: 'decision_date:desc',
    maxItems: 50
};

const run = await client.actor('haketa/openfda-scraper').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();

console.log(`Retrieved ${items.length} 510(k) clearances.`);
console.table(items.map(d => ({ kNumber: d.kNumber, device: d.deviceName, applicant: d.applicant, date: d.decisionDate })));
```

#### cURL Example

```bash
curl --request POST \
  --url "https://api.apify.com/v2/acts/haketa~openfda-scraper/runs?token=YOUR_APIFY_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "dataset": "drug-ndc",
    "search": "brand_name:Amoxicillin",
    "maxItems": 50
  }'
```

#### Webhook Alert Example for Compliance Teams

Set up an Apify webhook to instantly alert your regulatory affairs team on Slack, Microsoft Teams, or PagerDuty whenever a Class I recall is detected:

```json
{
  "eventType": "ACTOR.RUN.SUCCEEDED",
  "actorId": "haketa/openfda-scraper",
  "datasetId": "YOUR_DATASET_ID",
  "recordsCount": 100,
  "dataset": "drug-enforcement",
  "alert": "Class I Recall Published",
  "recallingFirm": "Greenwich Rx",
  "hazardSummary": "Microbial Contamination of Sterile Products"
}
```

***

### 🚀 Tips for High-Volume Extraction

- **Instant 1,000-Record Pulls:** The actor requests 1,000 items per batch. Standard pulls under 1,000 items complete in a single lightning-fast HTTP call.
- **Sorting for Freshness:** Always include `sort: "report_date:desc"` (recalls) or `sort: "decision_date:desc"` (device clearances) to ensure your dataset prioritizes newly published actions.
- **Targeted Lucene Filtering:** Use exact phrase quotes (e.g. `classification:"Class I"`) to avoid false positive term matching.
- **Handling openFDA Limits:** openFDA limits standard skip-based pagination to 25,000 records per search expression. For corpora larger than 25,000 records, partition your queries by year or geographic state.

***

### ❓ Frequently Asked Questions (FAQ)

##### Do I need to obtain an official openFDA API key?

No. The openFDA API is publicly accessible without an API key. For high-frequency automated polling, you can optionally provide a free API key from `open.fda.gov` in the `apiKey` field to lift rate limits.

##### How frequently are FDA datasets refreshed?

The FDA typically updates recall enforcement reports weekly on Wednesdays, medical device 510(k) clearances monthly, and FAERS adverse events on a quarterly basis.

##### Can I export results to Excel, CSV, or Google Sheets?

Yes. Every dataset can be downloaded immediately as Excel (XLSX), CSV, JSON, or XML from the Apify Console or integrated automatically using live dataset API endpoints.

##### Why are some `brandNames` empty in recall records?

The FDA's underlying recall records originate from enforcement field reports. When an official product matches the NDC directory, openFDA attaches an `openfda` annotation block containing brand names. When not matched, this field remains null, which is expected behavior.

##### How do I load FDA recall data directly into pandas?

Use the Apify Python client or load the dataset CSV endpoint directly:

```python
import pandas as pd
df = pd.read_csv("https://api.apify.com/v2/datasets/YOUR_DATASET_ID/items?format=csv")
print(df[["classification", "recallingFirm", "reportDate"]].head())
```

##### Can I schedule weekly recall checks?

Yes. Create a scheduled task in the Apify Console with the cron expression `0 14 * * 3` (every Wednesday at 2:00 PM UTC) to align with the FDA's standard weekly enforcement report publishing cycle.

##### Does the scraper support wildcards in Lucene queries?

Yes. You can use standard Lucene single-character (`?`) and multiple-character (`*`) wildcards (e.g., `brand_name:Amox*` or `recalling_firm:Pharma*`).

### 📋 Regulatory Compliance & Legal Use Notes

- **Authoritative Primary Source:** Data is directly queried from `api.fda.gov`, reflecting official FDA database records without intermediary alteration.

- **Audit Trail Compliance:** Every extracted record contains an immutable ISO 8601 UTC timestamp (`scrapedAt`), supporting regulatory audit trail requirements for life sciences quality management systems (QMS).

- **Public Domain Information:** FDA recall enforcement reports, premarket 510(k) summary decisions, and NDC directory filings reside in the public domain under US government open data statutes.

- **Data Freshness Guarantee:** Live queries dynamically retrieve the most up-to-date entries in the FDA repositories at execution time.

- **Deduplication Safeguards:** Output records feature natural composite keys (such as `recallNumber`, `kNumber`, `productNdc`, or `safetyReportId`) ensuring seamless database ingestion.

- **Automated Field Normalization:** Nested clinical objects are unpacked into tidy array strings, eliminating parsing overhead for data science pipelines.

- **Enterprise Cloud Scalability:** Runs on resilient Apify cloud workers capable of streaming large historical cohorts into persistent datasets without timeouts.

***

### 🔗 Related Healthcare & Registry Scrapers

- **ClinicalTrials.gov Scraper** — Global clinical study protocols and trial results.
- **NPPES NPI Registry Scraper** — US National Provider Identifier doctor and clinic registry.
- **Healthgrades Doctor Scraper** — Physician ratings, patient reviews, and hospital affiliations.
- **SEC EDGAR Scraper** — Public biotech and pharmaceutical 10-K / 10-Q filing extractor.
- **European Medicines Agency (EMA) Scraper** — European drug regulatory decisions.

***

### 📋 Changelog

#### Version 1.2 (2026-11)

- **Unlocked 1,000+ Deep Pagination:** Removed restrictive pagination ceilings; streamlined skip-pagination engine to traverse up to 25,000 records per query cleanly.
- **Fast Prefill Execution:** Optimized default batch parameters to complete test runs in under 10 seconds while providing 100 rich sample records.
- **Enhanced Clinical Array Parsing:** Standardized flattening of FAERS adverse drug reactions, concomitant medication lists, and MedDRA clinical terms.
- **Robust 429 Retry Engine:** Integrated progressive exponential backoff on high-volume rate-limited requests.

#### Version 1.1 (2026-10)

- Added automatic ISO date formatting (`YYYY-MM-DD`) from raw FDA integer timestamps.
- Unified top-level `title`, `date`, and `summary` schema across all six distinct endpoints.

#### Version 1.0 (2026-09)

- Initial release supporting drug, device, and food recalls, 510(k) clearances, NDC directory, and FAERS adverse events.

# Changelog

This Actor's version history is a separate document: https://apify.com/haketa/openfda-scraper/changelog.md

# Actor input Schema

## `dataset` (type: `string`):

Which openFDA endpoint to pull.

## `search` (type: `string`):

Optional openFDA search. Examples: classification:"Class I"  ·  recalling_firm:Pfizer  ·  state:CA+AND+status:Ongoing  ·  patient.drug.medicinalproduct:aspirin  ·  applicant:Medtronic. Leave empty for the whole dataset (most recent first if you set sort).

## `sort` (type: `string`):

Optional sort, field:asc|desc. Examples: report_date:desc  ·  decision_date:desc  ·  receivedate:desc.

## `apiKey` (type: `string`):

Optional free openFDA API key to raise the rate limit. Not required.

## `maxItems` (type: `integer`):

Maximum records to return (0 = auto/default; openFDA allows paging to 25,000 per query).

## `proxyConfiguration` (type: `object`):

Apify Proxy. Datacenter is sufficient.

## Actor input object example

```json
{
  "dataset": "drug-enforcement",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `recordType` (type: `string`):

Source dataset

## `title` (type: `string`):

Firm / device / brand / drug

## `date` (type: `string`):

Primary date

## `summary` (type: `string`):

Short summary

## `classification` (type: `string`):

Recall classification

## `status` (type: `string`):

Recall status

## `recallingFirm` (type: `string`):

Recalling firm

## `productType` (type: `string`):

Product type

## `deviceName` (type: `string`):

Device name (510k)

## `applicant` (type: `string`):

510(k) applicant

## `decisionDate` (type: `string`):

510(k) decision date

## `brandName` (type: `string`):

NDC brand name

## `genericName` (type: `string`):

NDC generic name

## `labelerName` (type: `string`):

NDC labeler

## `safetyReportId` (type: `string`):

FAERS safety report id

## `reactions` (type: `string`):

FAERS reactions

## `drugs` (type: `string`):

FAERS drugs

## `city` (type: `string`):

City

## `state` (type: `string`):

State

## `scrapedAt` (type: `string`):

ISO timestamp

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/openfda-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "maxItems": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/openfda-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call haketa/openfda-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,haketa/openfda-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RQimhq4SNWGZJ6HGI/builds/JIAqcrtc6NLtTXuGT/openapi.json
