# ClinicalTrials.gov Search: Trials by Condition, Drug, Location (`devsolal/clinical-trials-search`) Actor

- **URL**: https://apify.com/devsolal/clinical-trials-search.md
- **Developed by:** [David-Solal Chalmeau](https://apify.com/devsolal) (community)
- **Categories:** Business
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Search: Find Trials by Condition, Drug, Location

Search the official ClinicalTrials.gov registry for clinical trials by condition, intervention/drug, free-text term, location, or recruitment status — or fetch specific studies directly by NCT ID. Each result is a flat JSON row ready for dashboards, screening lists, or an AI agent.

### What you get per study

| Field | Description |
|---|---|
| `nctId`, `title`, `officialTitle`, `url` | Identification |
| `status`, `startDate`, `primaryCompletionDate`, `completionDate`, `lastUpdatePosted` | Status & timeline |
| `phases`, `studyType` | Design |
| `conditions`, `interventions` (name + type) | What's being studied |
| `sponsor`, `leadSponsorClass` | Who runs it |
| `enrollmentCount`, `minimumAge`, `maximumAge`, `sex` | Eligibility |
| `locationsCount`, `countries` (deduped) | Where it's conducted |
| `briefSummary` (trimmed to 1500 chars), `hasResults` | Plain-language summary & whether results are posted |
| `totalCount`, `truncated` | Search results only: how many studies matched in total, and whether you did **not** receive everything the run asked for (a `maxStudies` cap, an unknown total that the cap cut short, or an early stop such as your spending limit) |
| `fetchedAt` | Fetch timestamp |

Each study is delivered, and billed, **at most once per run**: if ClinicalTrials.gov's page cursor serves the same NCT ID twice (the registry is edited continuously), the duplicate is dropped and counted in the run stats as `duplicatesDropped`.

### Example input

```json
{ "condition": "asthma", "statuses": ["RECRUITING"], "maxStudies": 2 }
```

You can instead (or additionally) supply `intervention`, `term`, `location`, or `nctIds` (fetches those studies directly, ignoring other filters). **At least one of `condition`, `intervention`, `term`, `location` or `nctIds` is required** — the run fails immediately with a clear error otherwise, before anything is charged. Each free-text field (`condition`, `intervention`, `term`, `location`) accepts at most 500 characters, also checked before anything is fetched or charged.

`maxStudies` only caps a **search**, and it counts distinct studies, so a duplicate cannot use up the budget. An explicit `nctIds` list is an exact lookup, so it is returned in full even when it is longer than `maxStudies`; duplicate IDs are fetched once, the list is hard-capped at 2000 IDs, and any extras become a free `TRUNCATED_NCT_IDS` row that names the supplied and unique counts and the dropped IDs.

### Example output (real run, trimmed)

```json
{
  "nctId": "NCT06311162",
  "title": "Early Life Intervention in Pediatrics Supported by E-health - SMOKE",
  "status": "RECRUITING",
  "phases": ["NA"],
  "studyType": "INTERVENTIONAL",
  "conditions": ["Smoking Reduction", "Asthma in Children", "Wheezing"],
  "interventions": [{ "name": "Life-Style app", "type": "BEHAVIORAL" }],
  "sponsor": "Insel Gruppe AG, University Hospital Bern",
  "leadSponsorClass": "OTHER",
  "enrollmentCount": 160,
  "maximumAge": "5 Years",
  "sex": "ALL",
  "locationsCount": 1,
  "countries": ["Switzerland"],
  "url": "https://clinicaltrials.gov/study/NCT06311162",
  "hasResults": false,
  "fetchedAt": "2026-10-28T05:24:47.151Z"
}
```

### Pricing

Pay per event: a small start fee per run, plus a charge for each study delivered as a dataset row. Rows that are not studies are always free:

- a search that matches **nothing** → one free `NO_MATCH` row (no per-study charge). It is delivered rather than omitted so a misspelled condition or term is visible instead of looking like a silent empty run; the row echoes what you searched for;
- an NCT ID that doesn't exist → one free `NOT_FOUND` row;
- input `nctIds` beyond the 2000-ID hard cap → one free `TRUNCATED_NCT_IDS` row naming the supplied/unique counts and the dropped IDs;
- your spending limit stopping the run early → one free `STOPPED_BY_CHARGE_LIMIT` row naming how many requested studies or IDs were never processed (see below);
- a study the API returned that could not be parsed → one free `CHECK_FAILED` row, which still carries `totalCount` and `truncated`;
- an upstream failure → the run fails with a clear error rather than delivering partial data.

If your spending limit is reached, the Actor stops cleanly instead of running unpaid. It delivers one free `STOPPED_BY_CHARGE_LIMIT` row saying how many of the requested studies or NCT IDs were never processed, sets `truncated` to `true`, and says the same in the run's status message — a short list can never look complete. Current prices are shown on this page.

### Good to know

- Data source: [ClinicalTrials.gov API v2](https://clinicaltrials.gov/data-api/api), run by the U.S. National Library of Medicine (NLM). The data is U.S. government work in the public domain. **This Actor is not affiliated with, endorsed by, or sponsored by the NLM or ClinicalTrials.gov, and nothing it returns is medical advice.**
- `maxStudies` defaults to 100 and is hard-capped at 2000 per run. It applies to searches, not to an explicit `nctIds` list (which has its own 2000-ID cap, reported as `TRUNCATED_NCT_IDS`). It counts distinct studies: a study the API serves twice is delivered and billed once.
- The API is asked for `countTotal` on the first page, so every search row (free `CHECK_FAILED` rows included) and the run stats carry `totalCount` and `truncated`: you can tell "3 of 50,000" from "3 of 3" instead of guessing whether a short list means a narrow match or a cap. If the API omits `totalCount` while `maxStudies` still cut the run, `truncated` is `true` — an unknown total is never reported as "not truncated".
- A `200` response from the API that has no `studies` array (a schema change or an interstitial page) is treated as an upstream failure. It is never mistaken for "end of results", which used to end a run with silent partial data.
- `condition`, `intervention`, `term` and `location` are limited to 500 characters each; a longer value fails the run before any request is made.
- `statuses` accepts `RECRUITING`, `ACTIVE_NOT_RECRUITING`, `COMPLETED`, `ENROLLING_BY_INVITATION`, `NOT_YET_RECRUITING`, `SUSPENDED`, `TERMINATED`, `WITHDRAWN`, `AVAILABLE`, `NO_LONGER_AVAILABLE`, `TEMPORARILY_NOT_AVAILABLE`, `APPROVED_FOR_MARKETING`, `WITHHELD`, `UNKNOWN`.
- Only the fields needed for this output are requested from the API (via its `fields` parameter), to keep the run fast and cheap.
- Requests are made politely: at most 2 concurrent requests to ClinicalTrials.gov, with automatic retry and backoff on HTTP 429/5xx.
- No login, no API key, no scraping — this is the official, documented, keyless public API.

# Actor input Schema

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

Condition or disease to search for, e.g. "asthma". Matched against the ClinicalTrials.gov query.cond parameter. Up to 500 characters.

## `intervention` (type: `string`):

Intervention, drug or treatment name, e.g. "metformin". Matched against query.intr. Up to 500 characters.

## `term` (type: `string`):

General keyword search across title, summary, conditions and interventions. Matched against query.term. Up to 500 characters.

## `location` (type: `string`):

Country, state or city where the trial is conducted, e.g. "France". Matched against query.locn. Up to 500 characters.

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

Only return studies with one of these overall statuses. Leave empty for all statuses.

## `nctIds` (type: `array`):

Fetch these specific studies directly by NCT ID (e.g. NCT06429475), ignoring condition/intervention/term/location/statuses filters. maxStudies does NOT apply to this list: up to 2000 IDs are fetched per run, duplicate IDs are fetched once, and any extras are dropped with a free TRUNCATED_NCT_IDS row naming them. If your spending limit stops the run, a free STOPPED_BY_CHARGE_LIMIT row says how many requested IDs were never processed.

## `maxStudies` (type: `integer`):

Upper bound on distinct studies returned by a search (hard limit 2000). Ignored when nctIds is given. Every search row and the run stats report totalCount and truncated, so you can see how many studies matched in total, and truncated is also true if your spending limit stops the run early.

## Actor input object example

```json
{
  "condition": "asthma",
  "maxStudies": 100
}
```

# Actor output Schema

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

All returned studies as dataset items.

# 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 = {
    "condition": "asthma"
};

// Run the Actor and wait for it to finish
const run = await client.actor("devsolal/clinical-trials-search").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 = { "condition": "asthma" }

# Run the Actor and wait for it to finish
run = client.actor("devsolal/clinical-trials-search").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 '{
  "condition": "asthma"
}' |
apify call devsolal/clinical-trials-search --silent --output-dataset

```

## MCP server setup

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

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/TN77PEYzEC5B5YelD/builds/q9CVCfx8Hzs1qkuXe/openapi.json
