# openFDA Scraper: adverse events, recalls, labels, 510(k) (`bepolabs/openfda`) Actor

Monitor patient-safety signals and compliance news: type a plain name like metformin and get readable records for analysts, regulatory teams and AI agents.

- **URL**: https://apify.com/bepolabs/openfda.md
- **Developed by:** [BEPO Labs](https://apify.com/bepolabs) (community)
- **Categories:** Business, Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### 💊 What is openFDA Data?

Skip the query syntax: this Actor reads the US Food and Drug Administration's [openFDA API](https://open.fda.gov) for any brand, generic or manufacturer and returns one flat row per entry. Choose among half a dozen sources: FAERS adverse events, medicine recalls, package inserts, 510(k) clearances, device recalls and MAUDE events. Newest items come first.

- **Pharmacovigilance and safety**: adverse event reports for a drug with reactions, seriousness and patient age and sex
- **Recall monitoring**: new drug or device recalls for your products or suppliers since a date, on a schedule
- **Regulatory and competitor research**: 510(k) clearances by device type or company, with decision dates and product codes
- **Medical writing and AI**: label sections (indications, warnings, interactions) as text for analysis or an AI agent
- **Supply chain and quality**: recalling firm, reason, quantity, distribution and lot codes in one table

![openFDA Data: FDA adverse events, recalls, drug labels and 510(k) clearances for any drug or device, as clean rows.](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/openfda-hero.png)

#### ✨ Why use this Actor?

- ✅ **Plain names work**: no openFDA query syntax needed: a name is searched across generic, brand, product and firm fields
- ✅ **Half a dozen sources, one Actor**: medicine events, recalls, labels, 510(k) and equipment events
- ✅ **Readable rows**: FDA codes turned into words (seriousness, reporter, patient sex, drug role) and dates as YYYY-MM-DD
- ✅ **Power users welcome**: a query with a colon goes to openFDA as raw search syntax
- ✅ **No credentials needed**: works without an openFDA token; add your free one for heavy daily use
- ✅ **Fair price**: 1 USD per 1,000 records; names without a match are free

### 📦 What data can you get with openFDA Data?

| | | |
|---|---|---|
| 🗂️ Dataset and your query | 🆔 Record id (report, recall or K number) | 📅 Report, decision or label date |
| 🏷️ Title (product, reactions or device) | 🚨 Recall class, status and reason | 🏭 Recalling firm or applicant |
| 📦 Product, quantity, lot codes | 🗺️ Distribution and location | 🤒 Reactions and serious outcomes |
| 👤 Patient age and sex, reporter | 💊 Drugs with role, dose, indication | 📖 Label sections (warnings, dosage...) |
| ✅ 510(k) decision and device class | 🔧 Device problems and event text | 🔗 FDA page URL |

> Each dataset has its own fields after `dataset`, `query`, `id`, `date` and `title`, which every row shares.

### 🚀 How to use openFDA Data

openFDA Data works in a few clicks, no coding needed:

1. [Create a free Apify account](https://console.apify.com/sign-up) (the free plan includes 5 USD of monthly credit).
2. Open [openFDA Data](https://apify.com/bepolabs/openfda) and click **Try for free**.
3. Pick the dataset, enter your drug, device or firm names, and set a start date and how many records per name.
4. Click **Start** and wait for the run to finish (most runs take seconds).
5. Download your data as JSON, CSV, Excel, XML or HTML, or send it straight to Google Sheets, Make, Zapier or your AI agent.

![How openFDA Data works](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/openfda-workflow.png)

### ⬇️ Input

Choose one dataset and give up to 100 drug, device or firm names. Everything else is optional.

##### Pick a dataset

`drug-events` (FAERS), `drug-recalls`, `drug-labels`, `device-510k` (premarket clearances), `device-recalls` and `device-events` (MAUDE reports). One dataset per run; start a second run for another.

##### Names or raw syntax

A plain name is searched in the dataset's naming fields: generic and brand for drugs, device and applicant for 510(k), product description and firm for recalls. A 510(k) number like K181956 works too. A query with a colon is passed on as raw openFDA syntax, e.g. `classification:"Class I"`.

##### Dates and limits

`since` keeps records on or after a day (report, decision or publication stamp). Results come newest first; `maxResultsPerQuery` caps each name (up to 25,000). `maxTextLength` cuts long label sections and event narratives.

| Field | Type | What it does | Default |
|---|---|---|---|
| **Dataset** (`dataset`) | string | Which FDA records to fetch. | `"drug-recalls"` |
| **Drug or device names** (`queries`) | array | Generic or brand drug names, device names, firms or 510(k) numbers (e.g. | `["metformin"]` |
| **Since** (`since`) | string | Keep records on or after this date (report, decision or label date), e.g. |  |
| **Maximum records per query** (`maxResultsPerQuery`) | integer | Cap per query, newest first. | `100` |
| **Maximum text length** (`maxTextLength`) | integer | Long label sections and event narratives are cut to this many characters. | `2000` |
| **openFDA API key (optional)** (`apiKey`) | string | Free key from open.fda.gov/apis/authentication: 120,000 requests a day instead of 1,000 per IP. |  |
| **Maximum retries** (`maxRetries`) | integer | Retries per request with exponential backoff on network errors, 429 and 5xx. | `3` |

![openFDA Data input form](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/openfda-input.png)

#### Input example

```json
{
    "dataset": "drug-recalls",
    "queries": [
        "metformin",
        "valsartan"
    ],
    "since": "2018-01-01",
    "maxResultsPerQuery": 10
}
```

### ⬆️ Output

Every record becomes one flat row: `dataset`, `query`, `id`, `date` and `title` first, then the fields of that dataset. An entry matching nothing is no error: it adds no lines. The run summary in the key-value store (`OUTPUT`) lists every name with the count saved, the total at the FDA and the failure if one occurred.

![openFDA Data output table](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/openfda-output.png)

#### Output example

One row of the dataset (drug recalls for metformin since 2018):

```json
{
    "dataset": "drug-recalls",
    "query": "metformin",
    "id": "D-0657-2026",
    "date": "2026-07-08",
    "title": "Synjardy XR Tablets (empagliflozin and metformin hydrochloride extended-release tablets), 12.5/1000 mg, 60 Tablets per Bottle, Rx only, Distributed by: Boehringer Ingelheim Pharmaceuticals, Inc., Ridg...",
    "classification": "Class II",
    "status": "Ongoing",
    "recallingFirm": "Boehringer Ingelheim Pharmaceuticals, Inc.",
    "location": "Ridgefield, CT, United States",
    "reason": "CGMP Deviations: An incorrect detergent was used and the required swab sampling was not performed on a production hopper that had previously been used for a different product.",
    "product": "Synjardy XR Tablets (empagliflozin and metformin hydrochloride extended-release tablets), 12.5/1000 mg, 60 Tablets per Bottle, Rx only, Distributed by: Boehringer Ingelheim Pharmaceuticals, Inc., Ridgefield, CT 06877 USA.  NDC: 00597-0300-45",
    "quantity": "560 bottles",
    "distribution": "OH",
    "initiatedBy": "Voluntary: Firm initiated",
    "initiationDate": "2026-06-12",
    "classificationDate": "2026-06-30",
    "terminationDate": null,
    "codeInfo": "Lot 3244413; Exp. 12/31/2028",
    "eventId": "99233",
    "brandNames": [],
    "genericNames": [],
    "url": "https://www.accessdata.fda.gov/scripts/ires/index.cfm?Event=99233"
}
```

#### Drug adverse event row (drug-events)

One FAERS report for Ozempic from a real run:

```json
{
    "dataset": "drug-events",
    "query": "Ozempic",
    "id": "26940200",
    "date": "2026-06-30",
    "title": "Monoplegia, Back pain, Product use in unapproved indication",
    "serious": true,
    "seriousOutcomes": [
        "hospitalization",
        "other serious"
    ],
    "country": "PK",
    "reporter": "consumer",
    "patientSex": "female",
    "patientAge": "45 years",
    "reactions": [
        "Monoplegia",
        "Back pain",
        "Product use in unapproved indication"
    ],
    "drugs": [
        {
            "name": "OZEMPIC",
            "activeSubstance": "SEMAGLUTIDE",
            "role": "suspect",
            "indication": "Obesity",
            "dose": null
        }
    ],
    "company": "PK-NOVOPROD-3616663",
    "url": null
}
```

#### 510(k) clearance row (device-510k)

One clearance for a pulse oximeter from a real run:

```json
{
    "dataset": "device-510k",
    "query": "pulse oximeter",
    "id": "K252448",
    "date": "2026-02-27",
    "title": "AViTA Pulse Oximeter (SP61)",
    "applicant": "Avita Corporation",
    "decision": "Substantially Equivalent",
    "clearanceType": "Traditional",
    "dateReceived": "2025-08-04",
    "productCode": "DQA",
    "deviceClass": "2",
    "regulationNumber": "870.2700",
    "specialty": "Cardiovascular",
    "location": "New Taipei City, CN",
    "url": "https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfpmn/pmn.cfm?ID=K252448"
}
```

View the results as a table or JSON in the Output tab and download them as JSON, CSV, Excel, XML, HTML or RSS, all fields or only those you pick.

### 💰 How much does openFDA Data cost?

openFDA Data is priced **per event**: **1 USD per 1,000 records** (0.001 USD each), with no monthly rental. Each record saved to the dataset is billed once; a name without a match is free.

| You get | You pay |
|---|---|
| 100 records | 0.1 USD |
| 1,000 records | 1 USD |
| 10,000 records | 10 USD |
| 100,000 records | 100 USD |

💡 Apify's free plan gives you 5 USD of credit every month, enough for about **5,000 records** at no cost. Set a spending limit per run and the Actor stops there.

### ⚖️ openFDA Data vs. the alternatives

| | openFDA Data | openFDA API directly | FDA website search |
|---|---|---|---|
| **Plain drug or device names** | ✅ | query syntax per dataset | ✅ |
| **Six datasets with one input** | ✅ | ✅ six endpoints | separate tools |
| **Readable fields instead of FDA codes** | ✅ | ❌ raw codes | partly |
| **Paging and retries handled** | ✅ | your code | manual |
| **Export to CSV, Excel, JSON** | ✅ | your code | limited |
| **Schedules and MCP for AI agents** | ✅ | ❌ | ❌ |

### 🔌 Integrations, API and MCP

#### Connect openFDA Data to your AI agent (MCP)

Give Claude, ChatGPT, Cursor or any MCP client direct access to openFDA Data through the [Apify MCP server](https://mcp.apify.com). Add this URL to its settings:

```text
https://mcp.apify.com/?actors=bepolabs/openfda
```

For Claude Desktop, add it under `mcpServers` in `claude_desktop_config.json`:

```json
{
    "mcpServers": {
        "openfda": {
            "command": "npx",
            "args": [
                "-y",
                "@apify/actors-mcp-server",
                "--actors",
                "bepolabs/openfda"
            ],
            "env": {
                "APIFY_TOKEN": "<your Apify API token>"
            }
        }
    }
}
```

Then ask: *"Show me all Class I drug recalls from the last 12 months and the reason for each."*

#### Run it from your code

Python (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("bepolabs/openfda").call(run_input={"dataset":"drug-recalls","queries":["metformin","valsartan"],"since":"2018-01-01","maxResultsPerQuery":10})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

JavaScript (`npm install apify-client`):

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('bepolabs/openfda').call({"dataset":"drug-recalls","queries":["metformin","valsartan"],"since":"2018-01-01","maxResultsPerQuery":10});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### No-code integrations

Send results to **Google Sheets, Slack, Airtable, HubSpot, Make, Zapier, n8n** and more from the Integrations tab, start runs on a **schedule**, or trigger your own endpoint with a **webhook** when a run finishes. The [Apify API](https://docs.apify.com/api/v2) gives you full control over runs and datasets.

### ❓ FAQ

##### Where does the data come from?

From the official [openFDA API](https://open.fda.gov/apis/) of the US Food and Drug Administration. Every run asks it live.

##### How fresh is the data?

As fresh as openFDA: recalls are updated about weekly, adverse event reports about quarterly, labels and 510(k) clearances as the FDA publishes them.

##### Do I need an openFDA API key?

No. Without one openFDA allows 1,000 requests daily per IP; for heavy use add your free key from open.fda.gov/apis/authentication in `apiKey` (120,000 allowed).

##### Does an adverse event report prove the drug caused it?

No. FAERS and MAUDE entries are unverified notes sent to the FDA; they do not prove that a drug or device caused the event. Use them as signals, not as conclusions.

##### How many records can I get?

Up to 25,000 per name (the paging cap of openFDA) and up to 100 names per run. Narrow with `since` to stay below it.

##### Is it legal to use openFDA Data?

Yes. openFDA data is public domain (CC0) and the Actor reads it through the FDA's official API. The FDA asks users not to imply FDA endorsement and to remember that adverse event reports alone do not establish causation. The data is not medical advice.

##### What if something is missing or does not work?

Open an issue on the **Issues** tab; we read each one and reply. Feature requests are welcome too.

### 💬 Your feedback

Tell us what openFDA Data should add on the **Issues** tab or leave a review; your notes decide what we work on next.

### 🔗 Related Actors

| Actor | What it does |
|---|---|
| 🏛️ [SEC EDGAR Filings](https://apify.com/bepolabs/sec-edgar) | Tickers or CIK numbers to SEC filings: 10-K, 10-Q, 8-K, Form 4 and any other form, with document links. |
| 📄 [PDF to Text and Markdown](https://apify.com/bepolabs/pdf-to-text) | PDFs to clean text and Markdown, per page, per document or as RAG chunks, with columns in reading order and headers and footers removed. |
| 🌦️ [US Weather Forecast](https://apify.com/bepolabs/us-weather) | Official National Weather Service forecasts, hourly and 7-day, plus active weather alerts for any US point or state. |
| 📈 [Wikipedia Pageviews](https://apify.com/bepolabs/wikipedia-pageviews) | Daily or monthly views of any Wikipedia article in any language, with totals and averages, from the official Wikimedia API. |
| ⭐ [App Store Reviews](https://apify.com/bepolabs/app-store-reviews) | iOS App Store reviews with stars, text, app version and date, plus the app's rating and details, for any store country. |

# Changelog

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

# Actor input Schema

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

Which FDA records to fetch.

## `queries` (type: `array`):

Generic or brand drug names, device names, firms or 510(k) numbers (e.g. metformin, Ozempic, pulse oximeter, K181956). A query with a colon is passed on as raw openFDA search syntax (e.g. classification:"Class I"). Up to 100.

## `since` (type: `string`):

Keep records on or after this date (report, decision or label date), e.g. 2025-01-01.

## `maxResultsPerQuery` (type: `integer`):

Cap per query, newest first. openFDA pages stop at 25,000.

## `maxTextLength` (type: `integer`):

Long label sections and event narratives are cut to this many characters.

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

Free key from open.fda.gov/apis/authentication: 120,000 requests a day instead of 1,000 per IP.

## `maxRetries` (type: `integer`):

Retries per request with exponential backoff on network errors, 429 and 5xx.

## Actor input object example

```json
{
  "dataset": "drug-recalls",
  "queries": [
    "metformin"
  ],
  "maxResultsPerQuery": 100,
  "maxTextLength": 2000,
  "maxRetries": 3
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset items, one row per result, in the overview table view.

# 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 = {
    "dataset": "drug-recalls",
    "queries": [
        "metformin"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bepolabs/openfda").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 = {
    "dataset": "drug-recalls",
    "queries": ["metformin"],
}

# Run the Actor and wait for it to finish
run = client.actor("bepolabs/openfda").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 '{
  "dataset": "drug-recalls",
  "queries": [
    "metformin"
  ]
}' |
apify call bepolabs/openfda --silent --output-dataset

```

## MCP server setup

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

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/bGx9FZ6Rtflsa0qC7/builds/kSQlaYb7j2XmRkYEX/openapi.json
