# ClinicalTrials.gov + FDA Orange Book - Trial Delta API (`stefano_seggio/actor-24-clinical-trials-delta-engine`) Actor

Delta-tracks ClinicalTrials.gov trial status changes (RECRUITING, COMPLETED, TERMINATED) and FDA Orange Book patent/exclusivity data against verified live public APIs. Fingerprint-based diffing delivers only new or changed records per run, with full-jitter retry and strict ISO 8601 timestamps.

- **URL**: https://apify.com/stefano\_seggio/actor-24-clinical-trials-delta-engine.md
- **Developed by:** [Stefano Seggio](https://apify.com/stefano_seggio) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 new or changed trial/patent 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?

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

## Clinical Trial Data Extractor - ClinicalTrials.gov & FDA Orange Book Delta Monitor (Global Pharma Intelligence)

### Executive Value Proposition

Knowing that a trial's `overallStatus` just moved from `RECRUITING` to `TERMINATED`, or that an FDA Orange Book patent/exclusivity entry just changed, normally means manually re-opening the same ClinicalTrials.gov or Orange Book record over and over on a recurring basis - tedious enough that most sponsor-tracking, competitive-intelligence, and clinical-operations teams either skip it or only check sporadically. This actor automates that comparison against two verified-live, free, public government APIs: it fingerprints the fields that actually matter (`overallStatus`, `lastUpdatePostDate`, `statusVerifiedDate` for trials; patent/exclusivity data per `applNo`/`productNo` for Orange Book entries) against a persisted cross-run snapshot, and in delta mode delivers only records that are new or genuinely changed - not a full re-crawl you have to diff yourself every run.

### Use Cases

- **Sponsor and competitive-intelligence tracking.** Watch a competitor's pipeline for trial-status inflection points - a `PHASE3` study moving from `RECRUITING` to `COMPLETED` or `TERMINATED` is a real signal for BD, market-access, and competitive-intelligence teams, delivered as a `STATUS_CHANGE` event instead of something you'd only notice by re-reading the same trial page.
- **Clinical-operations self-monitoring.** Run this actor against your own organization's trials (via the `condition` filter or a saved query) to get an automated cross-run check that `overall_status` and `status_verified_date` are moving the way your team expects, without a person manually reloading each `NCT` record on a schedule.
- **Loss-of-exclusivity and generic-entry timing.** Track the FDA Orange Book source for a watchlisted ingredient or application number to see `PATENT_EXCLUSIVITY_CHANGE` and `NEW_LISTING` events as they happen - useful groundwork for generics-entry timing and patent-cliff monitoring.

### Input

```json
{
  "sources": ["clinicaltrials"],
  "condition": "non-small cell lung cancer",
  "maxPages": 5,
  "onlyChanged": true
}
```

| Field | Type | Default | Description |
|---|---|---|---|
| `sources` | array (`clinicaltrials`, `orangebook`) | `["clinicaltrials"]` | Which source(s) to run this call. `clinicaltrials` hits the ClinicalTrials.gov API v2; `orangebook` hits the openFDA Orange Book endpoint. |
| `condition` | string | - | Passed to ClinicalTrials.gov's `query.cond` filter, e.g. `"diabetes"`. |
| `orangeBookQuery` | string | - | Ingredient name or application number filter for the Orange Book source. |
| `maxPages` | integer | `20` | Hard cap on the number of 100-record ClinicalTrials.gov API pages walked per run. |
| `onlyChanged` | boolean | `false` (prefilled `true` in the Console) | Delta mode - only new or changed records are delivered. State persists in a named key-value store unique to this actor across scheduled runs. |
| `maxRetries` | integer | `5` | Max retry attempts (full-jitter exponential backoff) per page/request before that fetch is dead-lettered. |
| `fdaApiKey` | string (secret) | - | Optional openFDA API key for a higher Orange Book rate limit (1,000/day without a key vs. 120,000/day with one, both capped at 240/min). Not used by the ClinicalTrials.gov source. |

`sources` is the only required field.

### Output

One dataset item per delta event, carrying a shared envelope (`record_id`, `event_type`, `scraped_at`, `is_new`, `source_url`, `data_source`) plus source-specific fields. This is a real record from this actor's own smoke test:

```json
{
  "record_id": "NCT05823948",
  "event_type": "NEW_TRIAL",
  "scraped_at": "2026-09-08T19:15:01.188Z",
  "is_new": true,
  "source_url": "https://clinicaltrials.gov/study/NCT05823948",
  "data_source": "clinicaltrials-gov",
  "nct_id": "NCT05823948",
  "brief_title": "A Study Using Flash Glucose Measurements for a New Once-weekly Insulin (Insulin Icodec) in People With Type 2 Diabetes Who Have Not Used Insulin Before (ONWARDS 9)",
  "overall_status": "COMPLETED",
  "previous_status": null,
  "last_update_post_date": "2026-04-30",
  "status_verified_date": "2026-04",
  "lead_sponsor": "Novo Nordisk A/S",
  "conditions": ["Diabetes Mellitus, Type 2"],
  "phases": ["PHASE3"]
}
```

`overall_status` uses ClinicalTrials.gov's own controlled vocabulary verbatim (`RECRUITING`, `ACTIVE_NOT_RECRUITING`, `COMPLETED`, `TERMINATED`, `WITHDRAWN`, etc.) rather than a remapped generic enum, so no information is lost. `event_type` is `NEW_TRIAL` or `STATUS_CHANGE` for ClinicalTrials.gov records, `NEW_LISTING` or `PATENT_EXCLUSIVITY_CHANGE` for Orange Book records, or `SNAPSHOT_NO_DIFF` (only delivered when `onlyChanged` is off). On a `STATUS_CHANGE` event, `previous_status` carries the value seen on the prior run. An Orange Book record instead carries `application_number`, `product_number`, `trade_name`, `ingredient`, `te_code`, and the source's own `patent_data` object, left unflattened since patent entries vary in count per product. Download results as JSON, CSV, or Excel directly from the Apify platform.

### Reliability

- **Fingerprint-based delta engine.** Each trial's tracked fields (`overallStatus`, `lastUpdatePostDate`, `statusVerifiedDate`) and each Orange Book product's patent/exclusivity data are fingerprinted and persisted in a named, cross-run key-value store, so `STATUS_CHANGE` and `PATENT_EXCLUSIVITY_CHANGE` events reflect a real prior-run comparison, not a guess.
- **Global exception handler.** `installGlobalErrorHandlers` captures full stack trace, memory, and duration telemetry on any unhandled rejection or exception before the process exits, instead of failing silently.
- **Full-jitter backoff with a dead-letter queue.** Retryable fetches use full-jitter exponential backoff up to `maxRetries` attempts; a page or request that still fails is dead-lettered rather than silently dropped or left to crash the run.
- **Strict ISO 8601 timestamps.** Every timestamp field in the dataset schema enforces `format: date-time` plus an explicit regex pattern, so downstream consumers get consistent, parseable UTC timestamps on every record.
- **Verified-live sources.** ClinicalTrials.gov API v2 (`apiVersion: 2.0.5`) and the openFDA Orange Book endpoint were both confirmed live via direct API calls during this actor's development, not assumed from documentation alone.

### Pricing

Pay-per-event: **$0.002** per new or changed record (`result`), plus **$0.00005** per run start (`apify-actor-start`). An unchanged record in delta mode is never delivered and never billed - not a discounted tier, simply never an event. Check the Apify Store page for the current live pricing before running at volume.

### Support & Enterprise SLA

This is an independently developed and maintained actor, not a vendor product backed by a contractual SLA. Bug reports and feature requests go through the Apify Store's built-in issue tracker for this actor and are typically triaged within about 48 hours.

**What this actor does not do:** it does not track FDA Complete Response Letters. That data exists only as a static, infrequently-updated table/PDF archive with no queryable API, and the underlying disclosure policy has itself been paused and resumed at least once. Scraping a fragile, policy-unstable source for a low volume of records (hundreds of letters) isn't a good fit for this actor's delta-engine model - a genuine limitation, stated here rather than glossed over.

# Actor input Schema

## `sources` (type: `array`):

clinicaltrials = ClinicalTrials.gov API v2 trial-status delta tracking. orangebook = FDA Orange Book patent/exclusivity delta tracking.

## `condition` (type: `string`):

Passed to ClinicalTrials.gov's query.cond parameter, e.g. 'diabetes'. Leave empty to walk all trials matching other filters (not recommended without a narrow maxPages).

## `orangeBookQuery` (type: `string`):

Filter applied to the Orange Book query - an ingredient name or application number.

## `maxPages` (type: `integer`):

Hard cap on the number of 100-record ClinicalTrials.gov API pages walked per run.

## `onlyChanged` (type: `boolean`):

Returns only trials/products that are new or whose tracked fields (overall\_status, patent/exclusivity data) changed since a previous run. State persists in a named key-value store unique to this actor across scheduled runs.

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

Maximum retry attempts (full-jitter exponential backoff) for a single page/extract fetch before it is dead-lettered.

## `fdaApiKey` (type: `string`):

Optional. openFDA allows 1,000 requests/day without a key (240/min) or 120,000/day with a free key (still 240/min). Only matters for high-volume Orange Book runs - the ClinicalTrials.gov source does not use this key.

## Actor input object example

```json
{
  "sources": [
    "clinicaltrials"
  ],
  "maxPages": 20,
  "onlyChanged": true,
  "maxRetries": 5
}
```

# Actor output Schema

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

No description

## `resultsNewestFirst` (type: `string`):

No description

## `csv` (type: `string`):

No description

## `excel` (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 = {
    "onlyChanged": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("stefano_seggio/actor-24-clinical-trials-delta-engine").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 = { "onlyChanged": True }

# Run the Actor and wait for it to finish
run = client.actor("stefano_seggio/actor-24-clinical-trials-delta-engine").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 '{
  "onlyChanged": true
}' |
apify call stefano_seggio/actor-24-clinical-trials-delta-engine --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stefano_seggio/actor-24-clinical-trials-delta-engine"
        }
    }
}

```

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/PkYgfW33Sh6teGXUX/builds/GkaVeWTnOlgRnWrMd/openapi.json
