# FDA Intel: Device Clearance Monitor (`iceni-data/fda-device-clearance-monitor`) Actor

Every new FDA 510(k), PMA, and De Novo device decision by product code, applicant, or review panel — with weekly diff mode. Clean rows, summary links, $0.005 per decision.

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

## Pricing

from $5.00 / 1,000 510(k) or pma decision rows

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: Device Clearance Monitor

**Monitor new FDA 510(k), PMA, and De Novo device decisions** by product code, applicant, or review panel — with a diff mode that returns only decisions since a given date. Built on [openFDA](https://open.fda.gov/)'s `/device/510k`, `/device/pma`, and `/device/classification` endpoints, plus a weekly-refreshed cache of FDA's De Novo database (which has no official API). Runs on the [Apify platform](https://apify.com), so you get scheduling, an API, webhooks, and monitoring for free.

### What does FDA Device Clearance Monitor do?

This Actor queries FDA's public device-decision data and returns **one flat row per decision** — a 510(k) clearance, a PMA approval/supplement, or a De Novo classification grant — filtered by product code, applicant name, or review panel. Point it at a product code you care about (say `QAS`, radiological triage software) and it tells you every clearance FDA has issued for it, who got it, and when.

Run it once for the full history, or schedule it daily/weekly with `decision_after` set to your last run date to get a **diff of only new decisions** — useful for competitive intelligence, regulatory tracking, or feeding a Slack/email alert when a competitor (or you) gets cleared.

### Why use FDA Device Clearance Monitor?

- **Competitive intelligence**: know the moment a competitor's device clears FDA, in which product code, under which review panel.
- **Regulatory tracking**: watch your own product codes for De Novo/PMA/510(k) activity across the whole category, not just your own filings.
- **Market research**: pull every decision for a product code or panel to size a device category by decision volume, applicant, and clearance pathway.
- No scraping of FDA's 510(k)/PMA data — it's read straight from openFDA's stable, documented JSON API. Schedule it, hit it via the Apify API, or wire it into a webhook/integration.

### How to use FDA Device Clearance Monitor

1. Click **Try for free** (or **Start**) on this Actor's page.
2. In the **Input** tab, set `product_codes`, `applicant_contains`, and/or `review_panel` to whatever you want to track. Leave them blank to match everything (not recommended without `decision_after` — see [Pricing](#pricing--cost-estimation)).
3. Optionally set `decision_after` to a date (`YYYY-MM-DD`) to only get decisions since then — this is the diff mode, and what you'd use on a recurring schedule.
4. Click **Start**. When the run finishes, open the **Dataset** tab to view, filter, or export the results (JSON, CSV, Excel, HTML, and more).
5. To track De Novo decisions too (`include_de_novo: true`, the default), someone first needs to have run this Actor once with `refresh_de_novo: true` to build the cache — see [De Novo data](#de-novo-data) below. If the cache doesn't exist yet, De Novo rows are simply omitted; everything else still works.

### 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. |
| `applicant_contains` | string | Case-insensitive substring match on applicant/requester name, e.g. `"Medtronic"`. |
| `review_panel` | string | Two-letter advisory committee code (`"CV"`) or full name (`"Cardiovascular"`). |
| `decision_after` | string (date) | `YYYY-MM-DD`. Only decisions on/after this date — the diff-mode knob. |
| `include_de_novo` | boolean | Include cached De Novo grants alongside 510(k)/PMA. Default `true`. |
| `refresh_de_novo` | boolean | Maintenance mode: refresh the De Novo cache and exit. No rows, no charges. Default `false`. |

#### Three worked inputs

**1. Everything FDA has cleared for a specific product code:**

```json
{
  "product_codes": ["QAS"],
  "include_de_novo": true
}
```

**2. Diff mode — new decisions across two product codes since a date, for a scheduled daily/weekly run:**

```json
{
  "product_codes": ["QAS", "OBO"],
  "decision_after": "2026-08-01",
  "include_de_novo": true
}
```

**3. Everything a specific applicant has gotten cleared in a review panel, all history:**

```json
{
  "applicant_contains": "Medtronic",
  "review_panel": "CV",
  "include_de_novo": false
}
```

**Maintenance run** (typically on its own weekly schedule, with no other filters):

```json
{
  "refresh_de_novo": true
}
```

### Output

One flat JSON object per decision, pushed to the default dataset. You can download it as JSON, CSV, Excel, HTML, XML, or RSS from the **Export results** button. Dates are ISO 8601 (`YYYY-MM-DD`); missing values are `null`, never empty strings.

#### Example output row

```json
{
  "decision_type": "510k",
  "number": "K261085",
  "device_name": "Rapid Vessel Occlusion (Rapid VO)",
  "applicant": "iSchemaView",
  "product_code": "QAS",
  "device_class": "2",
  "regulation_number": "892.2080",
  "review_panel": "Radiology",
  "decision_date": "2026-07-13",
  "decision_code": "SESE",
  "summary_url": "https://www.accessdata.fda.gov/cdrh_docs/pdf26/K261085.pdf",
  "applicant_city": "Golden",
  "applicant_state": "CO",
  "applicant_country": "US",
  "data_as_of": "2026-09-04",
  "source_urls": [
    "https://api.fda.gov/device/510k.json?search=k_number:\"K261085\"",
    "https://api.fda.gov/device/classification.json?search=product_code:\"QAS\""
  ]
}
```

#### Data table

| Field | Description |
|---|---|
| `decision_type` | `"510k"`, `"pma"`, or `"de_novo"`. |
| `number` | The decision's identifying number (`K123456`, `P123456` or `P123456/S001`, `DEN123456`). |
| `device_name` | Device/trade name as filed. |
| `applicant` | Applicant/requester company name. |
| `product_code` | FDA 3-letter product code. |
| `device_class` | `1`, `2`, or `3`, from the classification join. |
| `regulation_number` | 21 CFR regulation number, from the classification join. |
| `review_panel` | FDA medical specialty / advisory committee panel name. |
| `decision_date` | Date FDA issued the decision. |
| `decision_code` | FDA's short decision code (e.g. `SESE`, `APPR`, `DENG`). |
| `summary_url` | Link to the decision's public summary — a PDF for 510(k)/De Novo, FDA's database page for PMA. **Not parsed** — this Actor never opens or extracts text from these documents. |
| `applicant_city` / `applicant_state` / `applicant_country` | Applicant's filed address, where the source provides it. |
| `data_as_of` | Snapshot date this row's data reflects. |
| `source_urls` | The exact API/page URL(s) this row was built from. |

#### What it does not return

- No PDF text extraction or parsing of any kind — `summary_url` is a link, not content.
- No enrichment from third-party sources (company financials, news, LinkedIn, etc.) — every field comes directly from FDA/openFDA.
- No personal data — these are corporate regulatory filings, not individuals.
- PMA rows have no `applicant_country` — openFDA's `/device/pma` endpoint doesn't expose one.

### De Novo data

FDA has **no official API and no bulk-download file** for De Novo classification grants (openFDA doesn't cover it at all — verified against its own endpoint manifest). The only source is FDA's HTML search interface at `accessdata.fda.gov`, which is bot-protected. Because of that, De Novo works differently from 510(k)/PMA:

- A separate **maintenance run** with `refresh_de_novo: true` scrapes FDA's De Novo database (through a ScraperAPI-style proxy — set the `SCRAPER_API_KEY` environment variable) and stores a snapshot in the Actor's key-value store. This run returns no rows and charges nothing. **Schedule this weekly.**
- Normal monitoring runs with `include_de_novo: true` read that cached snapshot and filter it the same way as 510(k)/PMA results — they never hit FDA's site directly.
- If nobody has run a refresh yet, De Novo rows are simply omitted (a log warning explains why); 510(k)/PMA results are unaffected.
- De Novo rows are charged via the `de_novo_returned` event only when the cache is 14 days old or less. Older ("stale") cached rows are still returned — useful if a refresh has been failing — but aren't charged, and `data_as_of` reflects the cache's actual snapshot date, not today.
- The refresh is incremental (only fetches DEN numbers not already cached, newest first, capped per run) and self-heals a full backfill over a few weekly runs rather than one long one.

#### Refresh cadence by source

| Source | Refresh cadence |
|---|---|
| `/device/510k`, `/device/pma` | Live on every run — openFDA is a stable, documented JSON API. |
| `/device/classification` | Live on every run, joined by `product_code`. |
| De Novo | Weekly, via a dedicated `refresh_de_novo: true` run. Never fetched live from a monitoring run. |

### Pricing / Cost estimation

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

- `record_returned` — charged once per 510(k)/PMA row (**$0.005/row**).
- `de_novo_returned` — charged once per De Novo row, only when served from a fresh (≤14-day-old) cache.

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

**Free-plan users are capped at 25 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) — no partial charges, no crash. Narrow your filters (`product_codes`, `applicant_contains`, `review_panel`, `decision_after`) to stay under that on the free plan, or upgrade for unlimited rows.

An unfiltered run (no `product_codes`, no `applicant_contains`, no `review_panel`, no `decision_after`) queries FDA's entire device-decision history — expect a lot of rows and, on the free plan, hitting the cap almost immediately. Always set at least one filter.

### Tips / Advanced options

- Combine `product_codes` **and** `decision_after` for the tightest, cheapest diff-mode queries.
- `review_panel` accepts either the 2-letter advisory committee code or the descriptive name — both work, e.g. `"CV"` and `"Cardiovascular"` are equivalent.
- Run the `refresh_de_novo: true` maintenance task on a separate weekly [schedule](https://docs.apify.com/platform/schedules) from your monitoring runs.
- `source_urls` on every row is a deterministic, single-record openFDA (or FDA page) URL — reusable outside the Actor to spot-check any row.

### FAQ, disclaimers, and support

- **Is this legal?** Yes — 510(k), PMA, and De Novo decisions are public FDA regulatory records. The 510(k)/PMA/classification data comes from openFDA's public API, per its [terms of use](https://open.fda.gov/terms/). The De Novo cache-refresh step respects `robots.txt` and skips itself if disallowed.
- **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; treat all results as unvalidated and verify anything decision-critical directly against FDA's own systems.
- **Known limitations**: PMA rows have no applicant country (not in the source data). The constructed 510(k)/De Novo PDF `summary_url` follows FDA's standard document-path convention but isn't returned directly by openFDA, so it can occasionally 404 for older or corrected submissions. De Novo data depends on a separately-maintained weekly cache and a working `SCRAPER_API_KEY`.
- Found a bug or have a feature request? Use this Actor's **Issues** tab. Need a custom variant (different sources, extra filters, alerting)? Reach out via the same tab.

### Related tools

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

- **Recall & Enforcement Monitor** — coming soon.
- **Adverse Events (MAUDE)** — coming soon.

# Actor input Schema

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

FDA device product codes to filter on (e.g. the 3-letter classification codes assigned by FDA, such as 'QAS' or 'OBO'). Leave empty to match any product code — combine with applicant\_contains, review\_panel, or decision\_after to keep the result set reasonable, since an unfiltered query returns the entire FDA device history.

## `applicant_contains` (type: `string`):

Case-insensitive substring match against the applicant/requester company name (e.g. 'Medtronic'). Leave blank to match any applicant.

## `review_panel` (type: `string`):

FDA medical specialty / review (advisory committee) panel, as either the two-letter code (e.g. 'CV' for Cardiovascular, 'RA' for Radiology) or the full panel name (e.g. 'Cardiovascular'). Leave blank to match any panel.

## `decision_after` (type: `string`):

Only return decisions dated on or after this date (YYYY-MM-DD). Leave blank to return full matching history. Run the Actor on a schedule with yesterday's or last week's date to get a diff of only new decisions since the last run.

## `include_de_novo` (type: `boolean`):

Include FDA De Novo classification grants alongside 510(k) and PMA decisions. De Novo data has no official openFDA API or bulk-download file, so it is served from a weekly cache built by refresh\_de\_novo runs rather than fetched live on every run. If the cache hasn't been built yet, De Novo rows are simply omitted (no charge, no error).

## `refresh_de_novo` (type: `boolean`):

Maintenance mode, meant for a weekly schedule. When true, the Actor scrapes FDA's De Novo decision database, updates the cached copy in the key-value store, then exits immediately — it does not query 510(k)/PMA or return any decision rows in this run, and no events are charged. Requires the SCRAPER\_API\_KEY environment variable to be set; if it isn't, the refresh is skipped with a warning.

## Actor input object example

```json
{
  "product_codes": [
    "QAS",
    "OBO"
  ],
  "applicant_contains": "Medtronic",
  "review_panel": "CV",
  "decision_after": "2026-08-01",
  "include_de_novo": true,
  "refresh_de_novo": false
}
```

# Actor output Schema

## `decisions` (type: `string`):

All matching FDA device decisions with classification fields.

# 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"
    ],
    "applicant_contains": "Medtronic",
    "review_panel": "CV",
    "decision_after": "2026-08-01"
};

// Run the Actor and wait for it to finish
const run = await client.actor("iceni-data/fda-device-clearance-monitor").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",
    ],
    "applicant_contains": "Medtronic",
    "review_panel": "CV",
    "decision_after": "2026-08-01",
}

# Run the Actor and wait for it to finish
run = client.actor("iceni-data/fda-device-clearance-monitor").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"
  ],
  "applicant_contains": "Medtronic",
  "review_panel": "CV",
  "decision_after": "2026-08-01"
}' |
apify call iceni-data/fda-device-clearance-monitor --silent --output-dataset

```

## MCP server setup

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

```

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/iRPUrzYavREzv6jeE/builds/gdhU6A6eKTFA73flf/openapi.json
