# ClinicalTrials.gov Scraper – Condition, Phase & Site Mode (`fetchsmith/clinicaltrials-scraper`) Actor

Scrape ClinicalTrials.gov's official NIH API: condition, intervention, sponsor, location, status, type and phase filters. Optional one-row-per-site mode for site-selection. No contact PII shipped, ever. $0.0015/result, no start fee.

- **URL**: https://apify.com/fetchsmith/clinicaltrials-scraper.md
- **Developed by:** [Fetch Smith](https://apify.com/fetchsmith) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 result items

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

## ClinicalTrials.gov Scraper – Condition, Phase & Site Mode

Pulls studies from **ClinicalTrials.gov**, the US NIH/NLM registry of clinical trials, using its own official API v2 — no API key, no login, no proxy. 602,520+ studies covered.

### What you get

25 flat fields per study, including the ones most ClinicalTrials.gov Actors skip:

| Field | Why it matters |
| --- | --- |
| `rowsPerStudy: "site"` mode | One row per **trial site** instead of one per study — facility name, city, state, country and lat/lon, so a site-selection or patient-recruitment buyer doesn't have to explode the array themselves. A study averages 5 sites (max seen: 110), so this mode returns roughly 5x more billable rows for the same query. |
| `phases`, `studyType`, `overallStatus` | Filterable and returned flat, not nested. |
| `enrollmentCount`, `sex`, `minimumAge`, `maximumAge`, `healthyVolunteers` | The eligibility snapshot without parsing free-text criteria. |
| `hasResults` | Whether the trial has posted a results section — filterable via `hasResultsOnly`. |
| `interventions` | Type + name for every drug/device/procedure arm. |
| `studyUrl` | Direct link to the public study page. |

**We do not ship contact people, phone numbers or emails — ever.** ClinicalTrials.gov's own API returns named individuals and personal email addresses in `centralContacts`/location `contacts` (we found a real `@gmail.com` in a live sample). Several competitor Actors resell that as a "contact finder." We deliberately drop it; `locations`/`site` carries facility, city, state, country and geo-coordinates only.

### Who uses this

- **Pharma / CRO business development** tracking competitor trials by condition or sponsor.
- **Site-selection teams** finding which facilities run trials for a given condition (`rowsPerStudy: "site"`).
- **Investor / market research** watching a sponsor's pipeline by phase and status.
- **Patient-advocacy and recruitment groups** finding actively recruiting trials near a location.

### Input

```json
{
  "conditions": "breast cancer",
  "overallStatus": ["RECRUITING"],
  "phases": ["PHASE3"],
  "maxResults": 100
}
```

| Input | Notes |
| --- | --- |
| `nctIds` | Comma/space/newline-separated NCT IDs (e.g. `NCT04368728, NCT03854955`) for a direct lookup by ID instead of a search — what other Actors call "search by direct URL". **Exclusive mode**: when set, every filter below is ignored (so a mixed batch of unrelated trials all come back), and a malformed or nonexistent ID is dropped individually with a named warning instead of failing the whole batch. |
| `conditions` / `interventions` / `sponsors` / `locations` | Free-text, each maps to the API's own `query.cond` / `query.intr` / `query.spons` / `query.locn`. ANDed together. |
| `searchQuery` | General free-text search across titles, outcomes and eligibility text. |
| `overallStatus` | e.g. `RECRUITING`, `COMPLETED`, `TERMINATED`. All 14 official values supported. |
| `studyTypes` | `INTERVENTIONAL`, `OBSERVATIONAL`, `EXPANDED_ACCESS`. |
| `phases` | `EARLY_PHASE1`..`PHASE4`, `NA`. Only meaningful for interventional studies — about 1 in 5 studies overall have no phase at all. |
| `hasResultsOnly` | Only studies with a posted results section. |
| `rowsPerStudy` | `"study"` (default) or `"site"`. |
| `maxResults` | Up to 50,000. Token-based paging, no offset wall. |

### Sample output (`rowsPerStudy: "study"`)

```json
{
  "nctId": "NCT04137653",
  "briefTitle": "Treatment of Triple-negative Breast Cancer With Albumin-bound Paclitaxel as Neoadjuvant Therapy",
  "overallStatus": "RECRUITING",
  "studyType": "INTERVENTIONAL",
  "phases": ["PHASE3"],
  "enrollmentCount": 1498,
  "leadSponsor": "Shengjing Hospital",
  "conditions": ["Breast Cancer"],
  "interventions": [{"type": "DRUG", "name": "nab-Paclitaxel+carboplatin"}],
  "locationCount": 1,
  "studyUrl": "https://clinicaltrials.gov/study/NCT04137653"
}
```

### The pageSize trap

Ask the API for `pageSize=1001` and it doesn't 400 — it silently returns **200 with only 1000 rows**, no warning. This Actor always clamps to 1000 and pages with the API's own `nextPageToken`, which has no offset wall (5,000+ unique rows walked in one run during testing, no rate limiting).

### Pricing

**$0.0015 per result, no Actor-start fee.** The 41-user Store leader in this niche charges **$0.16 to start plus $0.012/result** — about 8x more per row, with a start fee we don't charge at all. 1,000 studies costs $1.50 here vs. $12.16 there.

### FAQ

**I already have a list of NCT IDs — can I just fetch those?**
Yes, set `nctIds` (e.g. `"NCT04368728, NCT03854955"`) instead of the search filters. ClinicalTrials.gov's own API 400s the *entire* request if even one ID in a batch is malformed or doesn't exist — we've verified this live and handle it for you: bad IDs are dropped individually with a named warning, and the rest of your batch still comes back.

**Why did I get zero rows?**
Filters are ANDed — combining a narrow condition, sponsor and location at once often genuinely matches nothing. Drop one filter and retry. Also, `phases` only applies to interventional studies with a phase assigned; pairing it with `studyTypes: ["OBSERVATIONAL"]` always returns nothing.

**Are `phases`, `maximumAge` and `collaborators` always present?**
No. Measured on a live 50-study sample: `phases` populated on ~70%, `maximumAge` on ~48%, `collaborators` on ~24%. Don't treat a missing value as a scraping error — most studies genuinely don't set these fields.

**Does this return contact names, phone numbers or emails?**
No, by design — see above. If you need to contact a trial's coordinator, use the `studyUrl` to view the listing directly on ClinicalTrials.gov.

**Is this legal?**
Yes. ClinicalTrials.gov is run by the US National Library of Medicine and publishes this API for public reuse. All returned data (excluding the contact fields we deliberately drop) is public-interest study/sponsor/site metadata, not personal data about trial participants.

### Related guides

- [The ClinicalTrials.gov API silently caps pageSize at 1000 — and its phase filter doesn't exist where you'd look for it](https://fetchsmith.com/blog/clinicaltrials-gov-json-api)
- [All FetchSmith tools](https://fetchsmith.com/tools)
- [Source code](https://github.com/Fetchsmith/fetchsmith/tree/main/actors/clinicaltrials-scraper)

# Actor input Schema

## `nctIds` (type: `string`):

One or more ClinicalTrials.gov study IDs (e.g. "NCT04368728, NCT03854955" — comma, space or newline separated). When set, this is an EXCLUSIVE lookup mode: every other filter below (conditions, status, phase, etc.) is ignored, so a mixed batch of trials on unrelated topics still all come back. Malformed or nonexistent ids are dropped individually with a named warning instead of failing the whole run.

## `conditions` (type: `string`):

Condition or disease terms, e.g. "breast cancer". Maps to query.cond. Leave empty with a search query or overallStatus filter, or every study since 1999 matches.

## `interventions` (type: `string`):

Drug, device or procedure name, e.g. "pembrolizumab". Maps to query.intr.

## `sponsors` (type: `string`):

Lead sponsor or collaborator organization name. Maps to query.spons.

## `locations` (type: `string`):

Facility location text, e.g. "Boston, Massachusetts". Maps to query.locn.

## `searchQuery` (type: `string`):

General search term across titles, outcomes and eligibility text. Maps to query.term.

## `overallStatus` (type: `array`):

Filter by recruitment status. Leave empty for all statuses.

## `studyTypes` (type: `array`):

Interventional, observational or expanded-access. Leave empty for all.

## `phases` (type: `array`):

Trial phase. Only meaningful for interventional studies; ~19% of all studies have no phase at all (observational studies, device trials). Leave empty for all.

## `hasResultsOnly` (type: `boolean`):

Restrict to studies that have posted a results section on ClinicalTrials.gov.

## `rowsPerStudy` (type: `string`):

"study" = one row per trial (default). "site" = one row per trial site/facility — what site-selection and patient-recruitment buyers need. A single study averages 5 sites (max seen: 110), so site mode returns roughly 5x more billable rows for the same query.

## `maxResults` (type: `integer`):

Stop after this many rows (studies, or sites if rowsPerStudy="site"). Token-based paging has no offset wall.

## Actor input object example

```json
{
  "conditions": "breast cancer",
  "hasResultsOnly": false,
  "rowsPerStudy": "study",
  "maxResults": 100
}
```

# 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 = {
    "conditions": "breast cancer"
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetchsmith/clinicaltrials-scraper").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 = { "conditions": "breast cancer" }

# Run the Actor and wait for it to finish
run = client.actor("fetchsmith/clinicaltrials-scraper").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 '{
  "conditions": "breast cancer"
}' |
apify call fetchsmith/clinicaltrials-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fetchsmith/clinicaltrials-scraper"
        }
    }
}

```

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/e1d1LPdo9TQwaKsbx/builds/IVFDgA8r4kqULzPEz/openapi.json
