Skip to main content

searching-clinicaltrials

Searches ClinicalTrials.gov for studies by condition, intervention, and recruitment status using the modern v2 REST API with cursor (pageToken) pagination. Use when the user wants to find trials for a diagnosis or drug, screen patients against open studies, build a trial-matching feature, or pull a trial corpus for analysis. Trigger keywords: clinical trial, ClinicalTrials.gov, NCT number, trial search, recruiting studies, eligibility, query.cond, query.intr, pageToken, v2 API. Pairs adjacent to OpenMed: take Disease/Pharmaceutical entities from openmed.analyze_text and turn them into query.cond / query.intr filters; the returned eligibility text feeds parsing-trial-eligibility. ClinicalTrials.gov API v2 is fully public — no API key, no license.

Aller à l'installation

Informations de source

Dépôt
maziyarpanahi/openmed
Dernière activité de la source
20 juillet 2026 à 09:27
Langue détectée de SKILL.md
anglais
Étoiles
5 347
Forks
680

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
searching-clinicaltrials
description
Searches ClinicalTrials.gov for studies by condition, intervention, and recruitment status using the modern v2 REST API with cursor (pageToken) pagination. Use when the user wants to find trials for a diagnosis or drug, screen patients against open studies, build a trial-matching feature, or pull a trial corpus for analysis. Trigger keywords: clinical trial, ClinicalTrials.gov, NCT number, trial search, recruiting studies, eligibility, query.cond, query.intr, pageToken, v2 API. Pairs adjacent to OpenMed: take Disease/Pharmaceutical entities from openmed.analyze_text and turn them into query.cond / query.intr filters; the returned eligibility text feeds parsing-trial-eligibility. ClinicalTrials.gov API v2 is fully public — no API key, no license.
license
Apache-2.0
metadata
{"project":"OpenMed","category":"research-genomics","pairs":"adjacent","version":"1.0"}
# Searching ClinicalTrials.gov (v2 REST API) Query **ClinicalTrials.gov** — the U.S. registry of clinical studies — for trials matching a condition, intervention, and recruitment status. This skill uses the **modern v2 REST API** (`/api/v2/studies`), which returns structured JSON and paginates with an opaque cursor (`pageToken`), not page numbers. The v2 API is **fully public**: no API key, no registration, no license barrier. The legacy v1/classic API and the older `query_term`-style endpoints are deprecated — do not build on them. ## When to use - OpenMed extracted a diagnosis ("metastatic colorectal cancer") or a drug ("pembrolizumab") and you want open trials for it. - You are building a patient-to-trial matching feature and need candidate studies before applying eligibility logic (`parsing-trial-eligibility`). - You need a corpus of trial records (eligibility text, outcomes) to feed back into `openmed.analyze_text` for biomedical NER. If you already have an NCT number, fetch the single study directly (`/api/v2/studies/NCT01234567`) instead of searching. ## Quick start (real v2 API call) Base URL: `https://clinicaltrials.gov/api/v2`. No auth. JSON by default. ```python import requests BASE = "https://clinicaltrials.gov/api/v2" def search_trials(condition: str, intervention: str | None = None, status: str = "RECRUITING", page_size: int = 50) -> dict: """One page of studies for a condition (+ optional intervention).""" params = { "query.cond": condition, # condition / disease search "filter.overallStatus": status, # comma-separated enum values "pageSize": min(page_size, 1000), # max 1000; default 10 "countTotal": "true", # include totalCount on first page "format": "json", } if intervention: params["query.intr"] = intervention # drug / intervention search r = requests.get(f"{BASE}/studies", params=params, timeout=30) r.raise_for_status() return r.json() data = search_trials("breast cancer", intervention="trastuzumab") print(data["totalCount"]) # total matches (first page only) for study in data["studies"]: ps = study["protocolSection"] nct = ps["identificationModule"]["nctId"] title = ps["identificationModule"]["briefTitle"] print(nct, "-", title) ``` Equivalent cURL: ```bash curl "https://clinicaltrials.gov/api/v2/studies?query.cond=breast+cancer\ &query.intr=trastuzumab&filter.overallStatus=RECRUITING&pageSize=50&format=json" ``` ## Response shape Top level: `studies` (array), `nextPageToken` (present only if more results), and `totalCount` (only when `countTotal=true`, on the first page). Each study is a `protocolSection` of typed modules: | Field path | Meaning | | --- | --- | | `identificationModule.nctId` | `NCT........` study id | | `identificationModule.briefTitle` | short title | | `statusModule.overallStatus` | `RECRUITING`, `COMPLETED`, … | | `conditionsModule.conditions` | list of condition strings | | `armsInterventionsModule.interventions` | drugs / procedures | | `eligibilityModule.eligibilityCriteria` | free-text inclusion/exclusion | | `eligibilityModule.sex` / `minimumAge` / `maximumAge` | demographic gates | | `contactsLocationsModule.locations` | recruiting sites | ## Cursor pagination There are **no page numbers**. Loop until `nextPageToken` is absent. The token is opaque — pass it back verbatim. Do not re-send `countTotal` after page 1. ```python def iter_all(condition: str, status: str = "RECRUITING"): params = {"query.cond": condition, "filter.overallStatus": status, "pageSize": 1000, "format": "json"} while True: r = requests.get(f"{BASE}/studies", params=params, timeout=30) r.raise_for_status() page = r.json() yield from page.get("studies", []) token = page.get("nextPageToken") if not token: break params["pageToken"] = token # cursor for the next page ``` ### Trimming payloads Default responses are large. Restrict to the fields you need with `fields` (dotted paths or module names) to cut bandwidth: ```python params["fields"] = ("NCTId,BriefTitle,OverallStatus," "Condition,EligibilityCriteria") ``` ## Workflow 1. **Build the query from OpenMed facts.** Map extracted Disease spans → `query.cond`; Pharmaceutical spans → `query.intr`. Free-text keywords go in `query.term`. Combine status filters as `filter.overallStatus=RECRUITING,NOT_YET_RECRUITING`. 2. **Page through** with the cursor until `nextPageToken` is gone; cap total pulls. 3. **Persist** `nctId`, status, conditions, interventions, and the raw eligibility text. Eligibility goes to `parsing-trial-eligibility`. 4. **Optionally re-NER** the eligibility / outcomes text with `openmed.analyze_text` to structure inclusion criteria. ## Hand-off to / from OpenMed - **From OpenMed → trial search.** `openmed.analyze_text(note, model_name="disease_detection_superclinical")` yields Disease and Pharmaceutical entities. Use the surface forms (or a grounded term from `coding-icd10` / `normalizing-rxnorm`) as `query.cond` / `query.intr`. - **Trial text → OpenMed.** Feed `eligibilityModule.eligibilityCriteria` and brief summaries back through `openmed.analyze_text` to extract conditions, meds, and labs mentioned in the criteria. Then hand to `parsing-trial-eligibility` for inclusion/exclusion matching against patient facts. - Keep patient data local. The API call carries only the **query terms** (condition/drug names), never the patient note or any PHI. ## Edge cases & gotchas - **Synonyms & spelling.** The condition matcher is fuzzy but not infinite — "MI" will not match "myocardial infarction". Normalize OpenMed output first (ICD-10 / RxNorm) and consider issuing a few synonym variants. - **Status enums are exact.** Valid values include `RECRUITING`, `NOT_YET_RECRUITING`, `ENROLLING_BY_INVITATION`, `ACTIVE_NOT_RECRUITING`, `COMPLETED`, `SUSPENDED`, `TERMINATED`, `WITHDRAWN`, `UNKNOWN`. Comma-separate; do not lowercase. - **`totalCount` is first-page only.** Request `countTotal=true` once; it is not repeated on subsequent pages. - **Page size cap is 1000.** Larger values are silently clamped. - **Rate limits.** No key required, but throttle politely (a short sleep between pages); aggressive scraping can be blocked. For bulk/offline work, consider the full registry data dump rather than thousands of paged calls. - **`pageToken` expires** if the underlying index shifts; restart the query if a token is rejected. - **Not medical advice.** A trial appearing in results does not mean the patient qualifies — eligibility is decided downstream and reviewed by a clinician. ## Standards & references - ClinicalTrials.gov API v2 — https://clinicaltrials.gov/data-api/api - Study data structure (modules / field paths) — https://clinicaltrials.gov/data-api/about-api/study-data-structure - Search areas & query syntax — https://clinicaltrials.gov/data-api/about-api/search-areas - OpenAPI / interactive reference — https://clinicaltrials.gov/api/v2/
Voir sur GitHub