# FDA Intel: Adverse Event Summaries (`iceni-data/fda-adverse-event-summaries`) Actor

Aggregates FDA MAUDE device adverse event reports (openFDA /device/event) into summary rows by product code, manufacturer, or brand -- event-type counts, top device/patient problems, monthly trend, and report-source breakdown. No individual report rows or narratives.

- **URL**: https://apify.com/iceni-data/fda-adverse-event-summaries.md
- **Developed by:** [Martyn Gross](https://apify.com/iceni-data) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $250.00 / 1,000 adverse event summaries

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

*Part of Iceni Data · FDA Intel*

## FDA Intel: Adverse Event Summaries

**Aggregate FDA MAUDE device adverse event reports into summary rows** by product code, manufacturer, or brand — event-type breakdown, top device/patient problems, monthly trend, and report-source mix, all in one row per group. Built on [openFDA](https://open.fda.gov/)'s `/device/event` endpoint (the public API over FDA's MAUDE database). Runs on the [Apify platform](https://apify.com), so you get scheduling, an API, webhooks, and monitoring for free.

### What does FDA Intel: Adverse Event Summaries do?

Point it at a product code, manufacturer, or brand and a received-date window, and it pulls every matching MAUDE report from openFDA, groups them by `group_by`, and returns **one summary row per group** — not one row per report. Each row gives you the report count, a death/injury/malfunction/other breakdown, the top 5 device problems and top 5 patient problems reported, a month-by-month trend across the window, and a breakdown of who filed the reports (manufacturer, user facility, or voluntary). It's built for "how bad is this, and is it getting worse" at a glance, not for reading individual case narratives.

### Why use FDA Intel: Adverse Event Summaries?

- **Competitive/market intelligence**: track adverse event volume and severity trend for a competitor's product code or brand without building a MAUDE aggregation pipeline yourself.
- **Regulatory/quality monitoring**: watch your own product codes for a rising malfunction or death count, or a new top device problem, month over month.
- **Due diligence**: before partnering with, acquiring, or competing against a device maker, get their adverse-event profile — report volume, severity mix, and top failure modes — in one pull.
- No scraping — openFDA's `/device/event` is a stable, documented JSON API. Schedule this Actor weekly (MAUDE itself refreshes on that cadence) or hit it on demand via the Apify API.

### How to use FDA Intel: Adverse Event Summaries

1. Click **Try for free** (or **Start**) on this Actor's page.
2. In the **Input** tab, set `product_codes`, `manufacturer_contains`, and/or `brand_contains` to whatever you want to summarize. Leave all three blank to match every device event in the window (not recommended — see [Pricing](#pricing--cost-estimation)).
3. Set `received_after`/`received_before` (`YYYY-MM-DD`) to your window. `received_after` defaults to 365 days before the run date if left blank; `received_before` defaults to no upper bound.
4. Set `group_by` to `product_code` (default), `manufacturer`, or `brand` — this is the only thing that changes what `group_key` means on each output row.
5. Click **Start**. When the run finishes, open the **Dataset** tab's **Summaries** view to see one row per group, or export as JSON, CSV, Excel, HTML, and more.

### Input

All fields are optional and every field has a description and example in the **Input** tab. Full schema: [`.actor/input_schema.json`](.actor/input_schema.json).

| Field | Type | Description |
|---|---|---|
| `product_codes` | array of strings | FDA product codes to filter on, e.g. `["QAS", "OBO"]`. Empty = match any. |
| `manufacturer_contains` | string | Case-insensitive substring match on the device manufacturer name, e.g. `"Medtronic"`. |
| `brand_contains` | string | Case-insensitive substring match on the device brand/trade name. |
| `received_after` | string (date) | `YYYY-MM-DD`. Only reports FDA received on/after this date. Defaults to 365 days before the run date if left blank. |
| `received_before` | string (date) | `YYYY-MM-DD`. Only reports FDA received on/before this date. No upper bound if left blank. |
| `group_by` | string | `"product_code"` (default), `"manufacturer"`, or `"brand"` — which dimension `group_key` groups on. |

#### Three worked inputs

**1. A product code's adverse event trend over the last year (the default):**

```json
{
  "product_codes": ["QAS"],
  "group_by": "product_code"
}
```

**2. Compare manufacturers across two related product codes:**

```json
{
  "product_codes": ["QAS", "OBO"],
  "group_by": "manufacturer",
  "received_after": "2025-01-01"
}
```

**3. One brand within a product code, narrowed to a specific window:**

```json
{
  "product_codes": ["QAS"],
  "brand_contains": "Rapid",
  "group_by": "brand",
  "received_after": "2025-09-07",
  "received_before": "2026-03-01"
}
```

### Output

One flat JSON object per group (product code, manufacturer, or brand — whichever `group_by` selected), pushed to the default dataset. Never one row per individual MAUDE report. You can download it as JSON, CSV, Excel, HTML, XML, or RSS from the **Export results** button. Missing values are `null`, never empty strings.

#### What it does not return

- **No individual report rows.** `report_number`, dates, and every other per-report field stay internal to the aggregation — only group-level counts are returned. If you need individual MAUDE reports, openFDA's `/device/event` is free and public; query it directly.
- **No report narratives.** `mdr_text` (the free-text "Description of Event or Problem") is never read into a row, at any point in the pipeline.
- **No incidence rates.** `total_reports` is a raw count of reports filed, not a rate against devices sold, patients treated, or any denominator — MAUDE contains no exposure data to compute one. See the `caveat` field, present on every row.
- **No enrichment from third-party sources** (company financials, news, litigation records, etc.) — every field comes directly from openFDA.
- **No personal data** — MAUDE reports are already de-identified by FDA before openFDA exposes them.

#### Example output row

```json
{
  "group_key": "QAS",
  "group_by": "product_code",
  "product_codes": ["QAS"],
  "manufacturer": null,
  "total_reports": 187,
  "event_type_counts": { "death": 2, "injury": 41, "malfunction": 138, "other": 6 },
  "top_5_device_problems": [
    { "code_or_text": "Software Issue", "count": 52 },
    { "code_or_text": "Device Difficult to Program", "count": 24 },
    { "code_or_text": "Break", "count": 19 },
    { "code_or_text": "Material Deficiency", "count": 11 },
    { "code_or_text": "Failure to Alarm", "count": 7 }
  ],
  "top_5_patient_problems": [
    { "code_or_text": "No Clinical Signs, Symptoms or Conditions", "count": 96 },
    { "code_or_text": "Other", "count": 33 },
    { "code_or_text": "Death", "count": 2 }
  ],
  "monthly_trend": [
    { "month": "2025-09", "count": 14 },
    { "month": "2025-10", "count": 18 },
    { "month": "2025-11", "count": 12 },
    { "month": "2025-12", "count": 21 },
    { "month": "2026-01", "count": 19 },
    { "month": "2026-02", "count": 16 }
  ],
  "report_source_breakdown": { "manufacturer": 152, "user_facility": 29, "voluntary": 6, "other": 0 },
  "caveat": "MAUDE reports are unverified and are not incidence rates",
  "data_as_of": "2026-09-07",
  "source_urls": ["https://api.fda.gov/device/event.json?search=date_received:[20250907 TO 99991231] AND device.device_report_product_code:\"QAS\""],
  "partial_data": false
}
```

#### Data table

| Field | Description |
|---|---|
| `group_key` | This row's group: a product code, manufacturer name, or brand name, per `group_by`. |
| `group_by` | Which dimension `group_key` is: `"product_code"`, `"manufacturer"`, or `"brand"`. |
| `product_codes` | Distinct FDA product code(s) seen among this group's reports. |
| `manufacturer` | Populated only when `group_by` is `"manufacturer"` (equal to `group_key`). `null` for `product_code`/`brand` grouping — those groups can span multiple manufacturers, so no single value would be accurate. |
| `total_reports` | Number of MAUDE reports in this group within the received-date window. |
| `event_type_counts` | `{death, injury, malfunction, other}` report counts. `other` folds in "No Answer Provided", "Invalid Data", and anything else openFDA returns. |
| `top_5_device_problems` | Up to 5 most frequent `product_problems` values, most frequent first, as `{code_or_text, count}`. |
| `top_5_patient_problems` | Up to 5 most frequent `patient_problems` values, same shape. |
| `monthly_trend` | `{month, count}` per calendar month across the full window, zero-filled — never skips a quiet month. |
| `report_source_breakdown` | `{manufacturer, user_facility, voluntary, other}` report counts, from openFDA's `report_source_code` (who filed the MDR with FDA). `other` folds in "Distributor report" and anything unrecognized. |
| `caveat` | Always `"MAUDE reports are unverified and are not incidence rates"`. |
| `data_as_of` | Date this row's data was current as of. |
| `source_urls` | The openFDA search URL this group's reports were pulled from — narrowed to this one group, so you can spot-check the count directly against openFDA. |
| `partial_data` | `true` if at least one raw report in this run couldn't be parsed (missing `report_number`). |

### Refresh cadence

openFDA republishes its MAUDE data **weekly**. This Actor queries `/device/event` live on every run, subject to a 7-day **maude-cache** on the raw pull (see [Tips](#tips--advanced-options)) — re-running with the same filters inside that window re-uses the cached pull instead of re-querying openFDA, since the underlying source itself only moves weekly.

### Pricing / Cost estimation

This Actor uses the **pay-per-event** pricing model — you pay per summary row returned, not per report or per compute second:

- `summary_returned` — charged once per summary row (one per group).

(Event price is configured in Apify Console under this Actor's monetization settings, not in code.)

**Free-plan users are capped at 3 summary rows per run.** Once that's hit, the Actor stops, sets the status message to `Free tier limit reached`, and exits normally (not an error). Narrow `product_codes`/`manufacturer_contains`/`brand_contains` or switch `group_by` to stay under that on the free plan, or upgrade for unlimited rows.

An unfiltered run (no `product_codes`, `manufacturer_contains`, or `brand_contains`) queries the full MAUDE history for the received-date window across every group `group_by` produces — always set at least one filter.

### Tips / Advanced options

- Set the `OPENFDA_API_KEY` environment variable (a free key from [openFDA](https://open.fda.gov/apis/authentication/)) to page through results faster and get a higher openFDA rate limit. Without one, this Actor still works, just at openFDA's lower unauthenticated per-page limit for `/device/event`.
- Combine `product_codes` with a tight `received_after`/`received_before` window for the cheapest, fastest runs.
- Raw `/device/event` pulls are cached per exact filter combination (`product_codes` + `manufacturer_contains` + `brand_contains` + date window) for 7 days under a `maude-cache:*` key in this Actor's key-value store. Re-running the same filters inside that window costs nothing extra in openFDA calls; changing any filter creates its own independent cache entry.
- Switch `group_by` to `manufacturer` to see whether an adverse-event pattern is specific to one manufacturer's implementation of a product code, or spread across the whole category.
- `source_urls` on every row is a deterministic openFDA query URL for that exact group — reusable outside the Actor to independently verify any row's report count.

### FAQ, disclaimers, and support

- **Is this legal?** Yes — MAUDE adverse event reports are public FDA records, already de-identified before openFDA exposes them. Data is read directly from openFDA's public API, per its [terms of use](https://open.fda.gov/terms/).
- **This isn't medical or regulatory advice.** Per openFDA's own disclaimer, don't rely on this data (or on openFDA) to make decisions regarding medical care. Report counts reflect what was *filed*, not confirmed causation, and — per the `caveat` field on every row — are not incidence rates: MAUDE has no denominator of devices in use or patients treated, and the same real-world event can generate multiple reports from different reporters.
- **Known limitations**: a MAUDE report can list more than one device; this Actor attributes each report to whichever device entry matches a requested `product_codes` filter (or the first device entry if none match/no filter is set), so a rare multi-device combination report could be attributed to the "wrong" device for your purposes. `manufacturer`/`brand` fields come from the device's own record and can be blank or inconsistently spelled across reports for the same real manufacturer/brand — openFDA does not normalize company or brand names.
- Found a bug or have a feature request? Use this Actor's **Issues** tab. Need a custom variant (different groupings, alerting, other openFDA endpoints)? Reach out via the same tab.

### Related tools

Part of the **FDA Intel** family on Apify:

- [FDA Intel: Device Watchlist](https://apify.com/iceni-data/fda-device-clearance-monitor) — FDA device clearances (510(k)/PMA/De Novo), recalls & enforcement reports, and establishment registrations & listings.
- **FDA Intel: Adverse Event Summaries** (this Actor) — MAUDE adverse event report summaries by product code, manufacturer, or brand.

# Actor input Schema

## `product_codes` (type: `array`):

FDA device product codes to filter on (the 3-letter classification codes assigned by FDA, e.g. 'QAS' or 'OBO'). Leave empty to match any product code -- combine with manufacturer\_contains, brand\_contains, or the received-date window to keep the result set reasonable.

## `manufacturer_contains` (type: `string`):

Case-insensitive substring match against the device manufacturer name (e.g. 'Medtronic'). Leave blank to match any manufacturer.

## `brand_contains` (type: `string`):

Case-insensitive substring match against the device brand/trade name. Leave blank to match any brand.

## `received_after` (type: `string`):

Only include reports FDA received on or after this date (YYYY-MM-DD). Leave blank to default to 365 days before the run date.

## `received_before` (type: `string`):

Only include reports FDA received on or before this date (YYYY-MM-DD). Leave blank for no upper bound (through the most recent data openFDA has).

## `group_by` (type: `string`):

Which dimension to group summary rows by. 'Product code' (default) gives one row per product code. 'Manufacturer' gives one row per device manufacturer, spanning every matching product code. 'Brand' gives one row per device brand/trade name.

## Actor input object example

```json
{
  "product_codes": [
    "QAS",
    "OBO"
  ],
  "manufacturer_contains": "Medtronic",
  "brand_contains": "Rapid",
  "received_after": "2025-09-07",
  "received_before": "",
  "group_by": "product_code"
}
```

# Actor output Schema

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

No description

# 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 = {
    "product_codes": [
        "QAS",
        "OBO"
    ],
    "manufacturer_contains": "",
    "brand_contains": "",
    "received_after": "2025-09-07",
    "received_before": "",
    "group_by": "product_code"
};

// Run the Actor and wait for it to finish
const run = await client.actor("iceni-data/fda-adverse-event-summaries").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 = {
    "product_codes": [
        "QAS",
        "OBO",
    ],
    "manufacturer_contains": "",
    "brand_contains": "",
    "received_after": "2025-09-07",
    "received_before": "",
    "group_by": "product_code",
}

# Run the Actor and wait for it to finish
run = client.actor("iceni-data/fda-adverse-event-summaries").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 '{
  "product_codes": [
    "QAS",
    "OBO"
  ],
  "manufacturer_contains": "",
  "brand_contains": "",
  "received_after": "2025-09-07",
  "received_before": "",
  "group_by": "product_code"
}' |
apify call iceni-data/fda-adverse-event-summaries --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,iceni-data/fda-adverse-event-summaries"
        }
    }
}
```

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/4ebG70N1rWBBXAqkW/builds/SrA3iNNGuSVjkEP7A/openapi.json
