# ClinicalTrials.gov Material Change Monitor (`frankycheese/clinical-trial-change`) Actor

Monitor ClinicalTrials.gov for first-seen recruiting studies (NEW_TRIAL) and later material record changes (SOURCE_CORRECTION), with exact study links, replay suppression, and bounded charges.

- **URL**: https://apify.com/frankycheese/clinical-trial-change.md
- **Developed by:** [franklin mccheese](https://apify.com/frankycheese) (community)
- **Categories:** Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $250.00 / 1,000 new clinical trial 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

## ClinicalTrials.gov Material Change Monitor

Monitor recruiting clinical studies. Pay only when a study is first seen (`NEW_TRIAL`) or its record materially changes later (`SOURCE_CORRECTION`).

- **buyer:** clinical operations, site-feasibility, competitive-intelligence, and research teams
- **result:** one source-linked trial record — either a first-seen recruiting study or a material correction to an already-tracked record
- **official source:** ClinicalTrials.gov API v2
- **first useful run:** use the bounded public example with `baselineMode=emit_matches`
- **maximum charge:** `$0.25` with `maxEvents=1`
- **unchanged replay:** `$0.00`; the identical stateful replay emits no dataset row

### buyer value

Enroll conditions and recruitment statuses once, then receive evidence-backed record deltas instead of repeatedly comparing bulk exports. Two distinct event types keep the signal honest:

- **`NEW_TRIAL`** — a study matching your watchlist that has never been seen by this state store before. First-seen recruiting trials. Priced at `$0.25`.
- **`SOURCE_CORRECTION`** — a study already tracked by this state store whose sponsor-submitted record changed materially (fingerprint mismatch). Later material record changes. Priced at `$0.05`.

Stable SHA-256 fingerprints, idempotent settlement, and hard event/spend caps prevent replay billing. Cap-deferred records are preserved in state for later replay when budget allows.

### source and scope

The Actor reads sponsor-submitted records from the official ClinicalTrials.gov API v2. Every delivered row links to the exact record at `https://clinicaltrials.gov/study/{nctId}` and includes a source fingerprint and screening disclaimer. A listing or status change is not proof of safety, efficacy, approval, enrollment availability, or medical advice.

### 60-second quick start

The public example is an intentionally bounded preview. It can emit at most one current melanoma recruiting record for a maximum event charge of `$0.25`.

```json
{
  "watchlistId": "melanoma-recruiting-preview",
  "conditions": ["melanoma"],
  "statuses": ["RECRUITING"],
  "lookbackDays": 30,
  "baselineMode": "emit_matches",
  "maxEvents": 1,
  "maxTotalChargeUsd": 0.25,
  "maxSourceRecords": 100,
  "stateStoreName": "melanoma-recruiting-preview",
  "resetState": false,
  "qualityTestMode": false
}
```

For recurring production monitoring, use a stable watchlist/store and `baselineMode=silent` for the initial baseline. Subsequent material source changes then emit as `SOURCE_CORRECTION` without rebilling unchanged records.

### Illustrative output shape

*Illustrative — not a run receipt.* The row shape below is illustrative; the named study evidence is independently source-verified.

#### verified source-backed example

Verified against ClinicalTrials.gov API v2 on November 3, 2026: [NCT07890415](https://clinicaltrials.gov/study/NCT07890415), “Using an Artificial Intelligence (AI) Tool for Melanoma Diagnosis,” was `RECRUITING`, first posted October 22, 2026, and sponsored by Memorial Sloan Kettering Cancer Center. The bounded 30-day preview emits it as `NEW_TRIAL` on fresh state. This is source evidence, not proof of safety, efficacy, approval, or enrollment availability.

A delivered row contains `eventType` (`NEW_TRIAL` or `SOURCE_CORRECTION`), NCT identifier, title, recruitment status, sponsor, updated date, exact study link as `sourceRecordUrl`, `sourceFingerprint`, and disclaimer.

### Pricing

- `NEW_TRIAL` (first-seen study) — `$0.25`
- `SOURCE_CORRECTION` (material record change) — `$0.05`

The bounded preview allows one primary event. Unmatched records, unchanged replays, silent baselines, and failed source fetches create no paid event; Apify platform usage may still apply under the user's plan.

### Schedule, webhook, and API recipe

After the preview, create a production watchlist with a stable `stateStoreName`, run a silent baseline once, and schedule the same input daily or weekly. Route dataset-item webhooks to a clinical-operations queue. API clients should preserve state identifiers and set an explicit maximum run charge.

### Empty-run troubleshooting

An empty dataset usually means no current record matched the condition/status/lookback, the silent baseline intentionally stored state, or the same record was unchanged. Inspect `REPORT`, broaden one condition deliberately, and widen the lookback within its schema limit. Do not reset state merely to manufacture a paid row.

### Buyer bundle

Pair with [Clinical Trial Fit Monitor](https://apify.com/frankycheese/clinical-trial-site-openings): the fit monitor finds recently posted recruiting opportunities; this Actor follows enrolled trial records for material changes. Add the drug-safety monitor for a broader life-sciences intelligence workflow.

# Actor input Schema

## `watchlistId` (type: `string`):

Stable identifier used to isolate this watchlist and its replay state.

## `conditions` (type: `array`):

Clinical condition terms sent to ClinicalTrials.gov.

## `statuses` (type: `array`):

ClinicalTrials.gov overall study statuses to include.

## `lookbackDays` (type: `integer`):

Only first-seen studies posted within this window are emitted; later material corrections to tracked studies remain eligible.

## `baselineMode` (type: `string`):

Silently establish a safe baseline by default; emit current matches only when charges are intended.

## `maxEvents` (type: `integer`):

Maximum paid events this run may emit.

## `maxTotalChargeUsd` (type: `number`):

Hard ceiling for this run’s event charges in US dollars.

## `maxSourceRecords` (type: `integer`):

Maximum source records fetched and evaluated per run.

## `stateStoreName` (type: `string`):

Named key-value store used for replay-safe source state and settlement receipts.

## `resetState` (type: `boolean`):

Clear saved source state before this run. Use only when intentionally re-baselining.

## `qualityTestMode` (type: `boolean`):

Apify Store automated smoke-test mode. It validates runtime and input startup, emits one unbilled summary, and does not query sources, mutate state, deliver business events, or charge.

## Actor input object example

```json
{
  "watchlistId": "melanoma-recruiting-preview",
  "conditions": [
    "melanoma"
  ],
  "statuses": [
    "RECRUITING"
  ],
  "lookbackDays": 30,
  "baselineMode": "emit_matches",
  "maxEvents": 1,
  "maxTotalChargeUsd": 0.25,
  "maxSourceRecords": 100,
  "stateStoreName": "melanoma-recruiting-preview",
  "resetState": false,
  "qualityTestMode": false
}
```

# Actor output Schema

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

No description

## `report` (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 = {
    "watchlistId": "melanoma-recruiting-preview",
    "conditions": [
        "melanoma"
    ],
    "statuses": [
        "RECRUITING"
    ],
    "lookbackDays": 30,
    "baselineMode": "emit_matches",
    "maxEvents": 1,
    "maxTotalChargeUsd": 0.25,
    "maxSourceRecords": 100,
    "stateStoreName": "melanoma-recruiting-preview",
    "resetState": false,
    "qualityTestMode": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("frankycheese/clinical-trial-change").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 = {
    "watchlistId": "melanoma-recruiting-preview",
    "conditions": ["melanoma"],
    "statuses": ["RECRUITING"],
    "lookbackDays": 30,
    "baselineMode": "emit_matches",
    "maxEvents": 1,
    "maxTotalChargeUsd": 0.25,
    "maxSourceRecords": 100,
    "stateStoreName": "melanoma-recruiting-preview",
    "resetState": False,
    "qualityTestMode": False,
}

# Run the Actor and wait for it to finish
run = client.actor("frankycheese/clinical-trial-change").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 '{
  "watchlistId": "melanoma-recruiting-preview",
  "conditions": [
    "melanoma"
  ],
  "statuses": [
    "RECRUITING"
  ],
  "lookbackDays": 30,
  "baselineMode": "emit_matches",
  "maxEvents": 1,
  "maxTotalChargeUsd": 0.25,
  "maxSourceRecords": 100,
  "stateStoreName": "melanoma-recruiting-preview",
  "resetState": false,
  "qualityTestMode": false
}' |
apify call frankycheese/clinical-trial-change --silent --output-dataset

```

## MCP server setup

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

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/qSgnmA8Rmg9tuVhYU/builds/85t5g0zOpVqz0yf7Q/openapi.json
