# ClinicalTrials.gov Scraper - Sites & Contacts (`dataio/clinicaltrials-sites-investigators`) Actor

Scrape ClinicalTrials.gov at site level: one row per trial site, not per trial, with facility, city, country, coordinates and the investigator's name, role, phone and email as published. Filter by condition, status and country for site selection and outreach.

- **URL**: https://apify.com/dataio/clinicaltrials-sites-investigators.md
- **Developed by:** [Tom Awake](https://apify.com/dataio) (community)
- **Categories:** Lead generation, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 trial sites

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

### What does ClinicalTrials.gov Scraper do?

Export clinical trial **sites** from ClinicalTrials.gov — one row per site,
with the investigator's name, role, phone number and email as published by
the sponsor.

**No login. No API key. No proxies.**

### Why one row per site

Every other tool gives you one row per *trial*, with the sites buried in a
nested field — and the leading alternative states plainly that it does **not
include site contacts or investigator details**.

That is the wrong shape for the people who actually need this data. A CRO
looking for investigators, a site network scouting partners, a patient
recruitment agency, a medical affairs team mapping KOLs — none of them want
a study. They want to know **who to call**.

So this Actor flattens the other way: one row per site, with the contact
attached.

Measured on recruiting breast cancer trials, 200 site rows:

| | Coverage |
|---|---|
| Phone number | **96 %** |
| Email address | **80 %** |
| Coordinates | **100 %** |

Real rows, real institutions — `caroli-bosc.p@chu-nice.fr` at CHU de Nice,
`louis.potier@aphp.fr` at Bichat-Claude Bernard.

### Output

| Field | Example |
|---|---|
| `facility` | Hadassah Medical Center |
| `siteCity`, `siteState`, `siteCountry` | Jerusalem, —, Israel |
| `latitude`, `longitude` | 31.7683, 35.2137 |
| `siteStatus` | RECRUITING |
| `contactName` | Tanir Michal Eloise, MD |
| `contactRole` | CONTACT |
| `contactPhone` | +972 2 677 7111 |
| `contactEmail` | tanir@hadassah.org.il |
| `contactSource` | `site`, `central` or `none` |
| **`investigatorName`** | **Saranya Chumsri, M.D.** |
| `investigatorRole` | PRINCIPAL\_INVESTIGATOR, STUDY\_DIRECTOR, … |
| `investigatorAffiliation` | Mayo Clinic |
| `investigatorSource` | `site`, `study` or `none` |
| `nctId`, `studyUrl` | NCT01234567 |
| `briefTitle`, `overallStatus`, `phase`, `studyType` | |
| `leadSponsor`, `sponsorClass` | |
| `conditions`, `interventions` | |
| `enrollment`, `startDate`, `completionDate` | |
| `minimumAge`, `sex`, `healthyVolunteers` | |
| `centralContactName`, `centralContactPhone`, `centralContactEmail` | |

`contactSource` tells you where the contact came from. When a site publishes
no contact of its own, the study's central contact is used rather than
leaving the row unreachable — and the field says so, so you can filter if you
only want site-level people.

#### The coordinator and the investigator are not the same person

A site's contact list mixes two roles, and the first entry is almost
always the administrative coordinator. Measured 17 September 2026 across
568 sites: 59 published an investigator, but only **4** had them listed
first — 41 sat at position 2, 14 at position 3. Reading the first contact
therefore loses 55 investigators out of 59 that the source does publish.

That matters, because they are the person who decides:

| Site | `contactName` | `investigatorName` |
|---|---|---|
| Mayo Clinic in Florida | Clinical Trials Referral Office | **Saranya Chumsri, M.D.** |
| Mayo Clinic in Rochester | Clinical Trials Referral Office | **Amy C. Degnim, M.D.** |
| Moffitt Cancer Center | Gina Bellenger | **Onyee Chan, MD** |

Both are now given. `investigatorSource` says which level the name came
from — `site` when the site named its own, `study` when it fell back to
the trial's overall official. `investigatorRole` carries the role as
published (`PRINCIPAL_INVESTIGATOR`, `SUB_INVESTIGATOR`,
`STUDY_DIRECTOR`, `STUDY_CHAIR`) rather than flattening them into one
label, so a study director is never passed off as a site investigator.

### Input

```json
{
  "condition": "breast cancer",
  "status": ["RECRUITING"],
  "onlyWithContact": true,
  "maxItems": 500
}
```

| Field | Default | Notes |
|---|---|---|
| `condition` | `breast cancer` | Condition or disease |
| `status` | `["RECRUITING"]` | Nine recruitment statuses |
| `onlyWithContact` | `true` | Keep only rows with a phone or email |
| `maxItems` | `500` | Counts **sites**, not trials |
| `country` | — | Country or city, e.g. `France` |
| `phase` | — | Early Phase 1 through Phase 4 |
| `intervention` | — | Drug or procedure, e.g. `pembrolizumab` |
| `sponsor` | — | Lead sponsor, e.g. `Sanofi` |
| `searchTerm` | — | Free text across the whole record |
| `maxSitesPerStudy` | `0` | Cap sites per trial; `0` means no cap |

**`maxSitesPerStudy` matters more than it looks.** Some phase 3 trials
register hundreds of sites and would fill your entire export from a single
study. Setting it to 2 or 3 spreads the export across many trials — in
testing, 60 rows covered 41 different trials instead of 2.

### Use cases

- **Site selection and feasibility** — find centres already recruiting in
  your indication, with the investigator named.
- **Patient recruitment** — reach the sites actively enrolling, by city.
- **Medical affairs and KOL mapping** — see which investigators run which
  trials, for which sponsor.
- **Competitive intelligence** — which sponsors are running what, where, at
  what enrollment.
- **CRO business development** — a contactable list filtered by indication,
  phase and country.

### Data quality, honestly

This Actor reports exactly what sponsors registered. That means:

- **Coverage varies by phase.** Academic and early-phase trials usually
  publish a named investigator with an institutional email. Large industry
  phase 3 trials often publish a central call centre instead — in testing, a
  phase 3 slice returned 100 % phone numbers but only 2 % emails.
- **Placeholder values exist.** Sponsors sometimes register `111-111-1111`
  or a contact named `Site 034`. These are in the source record; the Actor
  does not silently drop them, so filter if they matter to you.
- **Registered ≠ current.** A site listed as recruiting may have stopped.
  The registry lags reality.

### Personal data

Investigator names, phone numbers and email addresses are personal data.
They are published on a public government registry so that patients and
researchers can make contact **about those trials**.

Using them for unrelated commercial outreach is a different purpose, and in
the EU or UK that makes you the data controller: you need a lawful basis,
you must tell people where their data came from on first contact, and you
must honour objections. That obligation is yours, not the tool's.

### Notes

- Source: the official ClinicalTrials.gov API v2, public and unauthenticated.
- Requests are paced at roughly one per second out of courtesy to a free
  public service.
- Not affiliated with ClinicalTrials.gov, the NIH or the NLM.

### How much does it cost?

You pay per trial site returned: **$0.006 each**, that is $6.00 per 1,000. There is no start fee, and subscription plans pay less per trial site.

The example input below asks for up to 200 trial sites, so it costs **$1.20 at most**.

If a run reaches the spending limit you set, the output stops at that limit and never goes past it. You are never charged for rows that were not delivered.

### Use ClinicalTrials.gov Scraper as an API

Call it from your own code with the Apify client, here in Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("DataIO/clinicaltrials-sites-investigators").call(run_input={
    'condition': 'breast cancer',
    'status': ['RECRUITING'],
    'onlyWithContact': True,
    'maxItems': 200,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

It also works from JavaScript, Make, Zapier, n8n, and from AI agents through the Apify MCP server.

### Other actors you might like

- [FDA 510(k) Scraper](https://apify.com/DataIO/openfda-510k-device-clearances): Device Clearances Data
- [FDA Recalls Scraper](https://apify.com/DataIO/openfda-recalls-enforcement): openFDA Enforcement
- [NPI Registry Scraper](https://apify.com/DataIO/nppes-npi-provider-registry): US Healthcare Providers

### FAQ

#### Is it legal to use this data?

The actor reads public data from its official source, without logging in and without bypassing any access control. What you do with the data, for example contacting people listed in it, is your responsibility under the laws that apply to you, such as GDPR in Europe.

#### Can I run it on a schedule?

Yes. Create a schedule in Apify Console, daily or weekly for example, and each run delivers a fresh dataset, which you can send by email, webhook or integration.

#### Can AI agents use it?

Yes. It is available through the Apify MCP server, and every input field is described in its input schema, so an agent can call it directly.

# Actor input Schema

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

For example "breast cancer", "type 2 diabetes", "Crohn disease".

## `status` (type: `array`):

Leave as Recruiting to reach sites that are actively enrolling — the sites worth contacting.

## `onlyWithContact` (type: `boolean`):

Recommended when building a call or mail list. Sites with no site-level contact fall back to the study's central contact before being judged.

## `maxItems` (type: `integer`):

One row per site. A single trial can register hundreds of sites, so this counts sites, not trials.

## `country` (type: `string`):

Restrict to a location, for example "France", "Germany" or "Boston".

## `phase` (type: `array`):

Leave empty for every phase. Phase 2 and 3 trials run the most sites, so they yield the longest contact lists.

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

For example "pembrolizumab", "CAR-T", "semaglutide".

## `sponsor` (type: `string`):

Lead sponsor name, for example "Sanofi" or "Mayo Clinic".

## `searchTerm` (type: `string`):

Searched across the whole record when the fields above are not enough.

## `maxSitesPerStudy` (type: `integer`):

Some trials register over a thousand sites and would fill the whole export. 0 means no cap.

## Actor input object example

```json
{
  "condition": "breast cancer",
  "status": [
    "RECRUITING"
  ],
  "onlyWithContact": true,
  "maxItems": 500,
  "maxSitesPerStudy": 0
}
```

# Actor output Schema

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

Every row produced by the run, in JSON.

# 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": "breast cancer",
    "status": [
        "RECRUITING"
    ],
    "maxItems": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataio/clinicaltrials-sites-investigators").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": "breast cancer",
    "status": ["RECRUITING"],
    "maxItems": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("dataio/clinicaltrials-sites-investigators").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": "breast cancer",
  "status": [
    "RECRUITING"
  ],
  "maxItems": 500
}' |
apify call dataio/clinicaltrials-sites-investigators --silent --output-dataset

```

## MCP server setup

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

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/61628CLsJLRrcIt7o/builds/GJrIity2GRDobdjPt/openapi.json
