Pragmatic Trial
A randomized trial designed to measure the effectiveness of an intervention under usual-care conditions in a broadly eligible population, typically embedded in routine-care data (EHR, registry, or claims) rather than a dedicated research infrastructure.
In plain language
A pragmatic trial is a randomized experiment designed to answer a simple question: does this treatment actually work for real patients in real clinics? Unlike a tightly controlled lab-style trial that recruits only ideal patients and enforces every dose, a pragmatic trial enrolls the broad, messy population that shows up for care, lets clinicians deliver treatment the way they normally would, and tracks outcomes using records that already exist, such as electronic health records or insurance claims. It keeps the one thing that makes experiments trustworthy, namely random assignment, while deliberately relaxing everything else so the answer reflects what happens in the world, not what happens under perfect conditions.
A pragmatic clinical trial (PCT) preserves randomization — the one design feature observational RWE cannot buy — while deliberately relaxing every other feature of the classic explanatory trial so the result generalizes to ordinary practice. Eligibility is broad (few exclusions for comorbidity, age, or polypharmacy), the intervention is delivered with usual flexibility by usual clinicians in usual settings, adherence is not artificially enforced, follow-up uses routine-care touchpoints, and outcomes are ascertained from data that already exist (EHR, disease registries, dispensing records, claims, vital records). The canonical modern examples — the Salford Lung Study (linked primary-care EHR + community-pharmacy dispensing), TASTE (the SWEDEHEART registry-based randomized trial), and ADAPTABLE (PCORnet EHR-embedded aspirin-dose trial) — randomize within a real-world data substrate, which is precisely why pragmatic trials sit inside the RWE catalog rather than beside it.
Core conceptual distinction
The defining contrast is pragmatic vs explanatory (Schwartz & Lellouch, 1967), and it is a continuum, not a binary — the central thesis of the PRECIS-2 tool, which scores a design from 1 (very explanatory) to 5 (very pragmatic) on nine domains: eligibility, recruitment, setting, organization, flexibility of the experimental intervention's delivery, flexibility of adherence, follow-up intensity, primary outcome, and primary analysis. An explanatory trial maximizes internal validity and asks can this work under ideal conditions (efficacy); a pragmatic trial maximizes external validity and asks does this work in routine care (effectiveness). The estimand differs accordingly: a PCT targets the effectiveness of a treatment strategy under usual-care conditions, analyzed intention-to-treat in a broadly eligible population, with non-adherence and treatment switching treated as part of the real-world effect rather than nuisance to be censored away. This is the same effectiveness estimand a target-trial emulation tries to recover from observational data — but the PCT gets it with actual randomization, so confounding (including unmeasured confounding) is handled by design rather than by adjustment, instrumental variables, or sensitivity analysis. What randomization does not buy is freedom from the operational biases of routine-data outcome ascertainment, blinding-related performance bias (most PCTs are open-label), or the loss of mechanistic interpretability that tight explanatory control provides.
Pros, cons, and trade-offs
(specific & comparative). - vs the explanatory RCT: A PCT trades some internal validity and precision for direct generalizability and far lower cost per patient (routine-data outcomes eliminate dedicated CRFs and study visits). Cost: open-label delivery invites performance and ascertainment bias, broad eligibility plus real-world non-adherence shrinks the effect size toward the null and demands a larger sample, and "soft" or clinician-judged outcomes captured in routine data are more vulnerable to detection bias than blinded adjudicated endpoints. Prefer the PCT when efficacy is already established and the decision-relevant question is real-world effectiveness, value, or comparative benefit among active options. - vs target-trial emulation (observational): The PCT randomizes, so it is the gold standard for the same effectiveness estimand the emulation approximates; it removes confounding by indication, healthy-user bias, and immortal time by design. Cost: it requires prospective consent/randomization infrastructure, takes years, and cannot be done where equipoise or ethics forbid randomization. Prefer emulation when randomization is infeasible, too slow, or unethical, and treat the PCT as the benchmark the emulation should reproduce. - vs single-arm trial with an external control: A PCT has a concurrent randomized comparator, eliminating the comparability threats that dominate external-control studies. Cost: it needs enough eligible patients to randomize a control arm, which external-control designs avoid in ultra-rare diseases. Prefer external controls only when a randomized concurrent arm is genuinely impossible. - registry-based / cluster-randomized variants: Embedding randomization in a registry (TASTE) or randomizing sites/clinics rather than patients (cluster-PCT) lowers burden and enables system-level interventions, at the price of registry-capture gaps, clustering-induced loss of power (the design effect), and identification/recruitment bias when sites — not blinded individuals — know their allocation.
When to use
(decision rules). Use a pragmatic trial when: (1) efficacy is established and the open question is effectiveness, comparative value, or implementation under routine care; (2) equipoise exists and randomization is ethical and feasible; (3) a suitable routine-data substrate (linked EHR, a mature disease registry, or near-complete claims) can capture the primary outcome with acceptable accuracy and timeliness; (4) the decision-maker (payer, guideline body, HTA) explicitly wants real-world effectiveness rather than ideal-condition efficacy; and (5) the intervention can be delivered within usual workflows without a dedicated research apparatus.
When NOT to use — and when it is actively misleading or dangerous
(decision rules). - Efficacy and mechanism are still unknown. A pragmatic effectiveness trial run before efficacy is established conflates "the drug doesn't work" with "it wasn't taken correctly" — the diluted ITT effect under poor adherence can hide a real biological effect and kill a useful therapy, or conversely mask a safety signal. - The primary outcome cannot be captured well from routine data. If the endpoint requires standardized imaging, central adjudication, or scheduled biomarker draws that routine care does not perform, claiming "pragmatic" ascertainment introduces differential, open-label detection bias — dangerous when the arm influences how aggressively the outcome is looked for. - Blinding is essential and impossible pragmatically. For subjective or clinician-determined outcomes with an unblinded intervention, the pragmatic frame can manufacture a spurious effect; this is where pragmatic ascertainment is actively misleading, not merely imprecise. - No equipoise / ethics forbid randomization, or the intervention is unsafe to deliver under usual flexibility. Then a PCT is infeasible and an observational target-trial emulation or external-control design is the honest alternative. - Beware "pragmatic" as a label of convenience. A trial that is explanatory on eligibility and analysis but calls itself pragmatic to borrow generalizability claims fails PRECIS-2 scrutiny; reviewers will (correctly) demand the nine-domain wheel.
Data-source operational depth
The pragmatic promise lives or dies on the routine-data substrate used for eligibility screening and outcome capture, and each substrate has distinct failure modes. - Claims (FFS or commercial): Excellent for complete dispensing, procedures, and encounters within an enrolled, fee-for-service window; ideal for randomizing among already-marketed therapies and ascertaining hospitalization/procedure/mortality-proxy outcomes. Failure modes: Medicare Advantage and capitated person-time silently drop FFS claims, so a patient who switches to MA mid-trial appears to have zero events — restrict outcome person-time to observable FFS+Part D coverage and treat MA enrollment as administrative censoring, not as an event-free interval. Adjudication/ascertainment lag (claims mature over 3–6 months) means interim outcome counts undercount recent events; lock data only after a run-out window. Diagnosis-code outcomes need a validated algorithm with a known PPV. - EHR-embedded (e.g., Salford Lung, ADAPTABLE/PCORnet): Rich on labs, vitals, problem lists, and clinician notes for broad eligibility screening and severity capture; supports point-of-care randomization. Failure mode: visit-driven, leaky capture — a patient who seeks care outside the network is differentially unobserved, and if leaving correlates with the outcome (or with the arm) the effect is biased. Salford addressed this by linking community-pharmacy dispensing and hospital records to its primary-care EHR so events outside the index practice were still caught; without such linkage, define the observation window explicitly and treat out-of-network loss as potentially informative. - Registry-based randomized trial (e.g., TASTE / SWEDEHEART): Near-complete enrollment of the target population, adjudicated clinical outcomes, and randomization folded into an existing data-entry workflow at trivial marginal cost. Failure mode: the registry captures only what it was built to capture — off-protocol medication switches, outcomes treated at non-participating hospitals, and out-of-country events fall outside it, so concomitant-therapy contamination and some events go unrecorded; link to national dispensing and death registries to close the gap. - Linked claims–EHR–registry–vital records: The strongest substrate (EHR severity + claims completeness + registry adjudication + reliable mortality), but linkage selection (only the linkable subset randomizes/contributes) and date-discrepancy reconciliation across order, dispense, and service dates must be resolved before randomization-date and outcome-window assignment.
Worked claims/EHR example
Question: among adults with COPD in routine primary care, does once-daily fluticasone furoate–vilanterol reduce moderate-or-severe exacerbations vs continuing usual maintenance therapy, as delivered in practice (the Salford Lung effectiveness estimand)? (1) Pragmatic eligibility (broad, few exclusions): age ≥40, ≥1 recorded COPD diagnosis in the EHR problem list, ≥1 maintenance-inhaler dispensing in the prior 12 months, and continuous, FFS-observable medical+pharmacy coverage for a 365-day baseline window (so prior-therapy and comorbidity history is real, not missing); do not exclude for common comorbidity, polypharmacy, or mild-to-moderate renal/hepatic impairment, which an explanatory trial would. (2) Randomization unit & assignment: randomize the patient 1:1 at the point of care (EHR flag at the index encounter), record `index_date` = randomization date; for a cluster variant, randomize the practice and stamp every enrolled patient with the site allocation. (3) Real-world delivery: no enforced adherence — the intervention arm is prescribed the study inhaler and then followed exactly as routine patients are (refills via `fill_date` + `days_supply`, switches and discontinuations left to occur). (4) Outcome ascertainment from routine data: a moderate exacerbation = an outpatient claim with a COPD-exacerbation diagnosis plus a dispensing of an oral corticosteroid and/or antibiotic within a 14-day window; a severe exacerbation = an inpatient/ED claim with a primary COPD-exacerbation code — both via a validated algorithm with documented PPV. (5) Person-time rules: follow from `index_date` to first qualifying exacerbation; administratively censor at MA enrollment, disenrollment, death, or data-end, and exclude MA-only spans from the at-risk denominator because their claims are unobservable (an event there would be silently missed). (6) Analysis: intention-to-treat by randomized arm, counting events under as-prescribed routine care; report the effectiveness rate ratio with a pre-specified run-out window so claims-maturation lag does not undercount late events, and a per-protocol/on-treatment sensitivity analysis with inverse-probability-of-censoring weights to bracket the contamination from real-world switching.
Worked example
Scenario
Imagine a study asking: among adults with a common lung disease called COPD, does a new combination inhaler reduce flare-ups compared to whatever maintenance inhaler patients are already using? The team wants to know what happens in routine primary-care clinics, not in a specialized research center. Below is a side-by-side comparison of how a pragmatic trial and a classic explanatory trial would each be designed to answer that question.
Dataset
Pragmatic trial vs. explanatory trial across five design dimensions. Each row is a design choice; the contrast shows why the two trials answer different questions.
| Design dimension | Explanatory trial (efficacy) | Pragmatic trial (effectiveness) |
|---|---|---|
| Population | Narrow: age 40-65, no other lung disease, no other medications, non-smoker for 5+ years | Broad: any adult with a recorded COPD diagnosis, common co-diseases allowed, smokers included |
| Setting | Specialist respiratory clinics at academic medical centers | Any primary-care practice that already cares for COPD patients |
| How treatment is delivered | Fixed dose, fixed schedule, monitored by study nurse at every visit | Clinician prescribes and adjusts as they see fit; no study-mandated visits |
| Comparator | Placebo inhaler (identical-looking dummy device) | Usual maintenance therapy the patient was already taking |
| How outcomes are measured | Lung-function tests performed on a schedule by trained technicians | Exacerbation events pulled from routine EHR records and pharmacy dispensing data |
Steps
Look at the population row: the explanatory trial screens out everyone with complicating factors, so its results apply to a narrow slice of patients. The pragmatic trial enrolls almost anyone with COPD, so its results apply to the full range of people a clinician will actually treat.
Look at the comparator row: placebo tells you whether the drug beats nothing under perfect conditions. Usual care tells you whether the drug beats the real alternative a doctor would otherwise prescribe, which is the question a payer or guideline committee actually needs to answer.
Look at the delivery and outcomes rows together: in a pragmatic trial nobody enforces the dose and outcomes come from routine records rather than scheduled lab visits. This means the measured effect includes real-world non-adherence and the noise of routine data capture, so the effect size is often smaller than in the explanatory trial even if the drug genuinely works.
Now apply the PRECIS-2 lens: each of these five rows corresponds to one or more of its nine design domains (eligibility, setting, flexibility of delivery, flexibility of adherence, comparator, primary outcome). Rate each domain from 1 (very explanatory) to 5 (very pragmatic) and the overall profile tells you how generalizable the trial is.
Both trial types randomize, so both remove the concern that sicker patients ended up in one arm by chance. The pragmatic trial does not sacrifice that protection; it only relaxes the features that would restrict who the answer applies to.
Result
A pragmatic trial answers: does this treatment produce better outcomes than the alternative patients would actually receive, for the real population of patients who have this condition, delivered the way clinicians would actually deliver it? That is an effectiveness answer. An explanatory trial answers a narrower efficacy question: can this treatment outperform placebo in an ideal population under ideal conditions?
Runnable example
python implementation
Pragmatic-trial cohort/eligibility construction and routine-data outcome ascertainment (NOT effect estimation). Required inputs (already cleaned and de-duplicated): dx : diagnoses -> person_id, dx_date (datetime), dx_code, setting in...
import pandas as pd
import numpy as np
BASELINE_DAYS = 365 # observable-coverage lookback so history is real, not missing
OCS_ABX_WINDOW = 14 # days: outpatient COPD dx + steroid/antibiotic = moderate exacerbation
COPD_DX = {"J44.0", "J44.1", "J44.9"}
EXAC_OCS_ABX = {"OCS", "ANTIBIOTIC"} # drug_class values flagging an exacerbation treatment
def screen_eligibility(dx, rx, enroll, arms):
"""arms: DataFrame[person_id, index_date (randomization date), arm] from the registry/EHR/RNG."""
elig = arms.merge(enroll, on="person_id", how="left")
# Pragmatic: require only observable FFS coverage spanning the baseline window through randomization.
elig["covered"] = (
(elig["enroll_start"] <= elig["index_date"] - pd.Timedelta(days=BASELINE_DAYS))
& (elig["enroll_end"] >= elig["index_date"])
& (~elig["ma_only"])
)
# Require a recorded COPD diagnosis and >=1 maintenance fill in the baseline window (broad inclusion).
base_dx = dx.merge(arms[["person_id", "index_date"]], on="person_id")
has_copd = base_dx[
base_dx["dx_code"].isin(COPD_DX)
& (base_dx["dx_date"] <= base_dx["index_date"])
& (base_dx["dx_date"] >= base_dx["index_date"] - pd.Timedelta(days=BASELINE_DAYS))
]["person_id"].unique()
keep = elig.loc[elig["covered"] & elig["person_id"].isin(has_copd),
["person_id", "index_date", "arm"]]
return keep.drop_duplicates("person_id")
def first_exacerbation(cohort, dx, rx, enroll):
"""First moderate (outpatient COPD dx + OCS/abx within 14d) OR severe (inpatient/ED COPD dx) event.
Person-time during MA-only spans is unobservable -> such events are dropped and the span censored upstream."""
d = dx.merge(cohort[["person_id", "index_date"]], on="person_id")
d = d[(d["dx_code"].isin(COPD_DX)) & (d["dx_date"] >= d["index_date"])]
severe = d[d["setting"].isin(["INPATIENT", "ED"])][["person_id", "dx_date"]].assign(severity="severe")
out_copd = d[d["setting"] == "OUTPATIENT"][["person_id", "dx_date"]]
exac_rx = rx[rx["drug_class"].isin(EXAC_OCS_ABX)][["person_id", "fill_date"]]
m = out_copd.merge(exac_rx, on="person_id")
m = m[(m["fill_date"] >= m["dx_date"])
& (m["fill_date"] <= m["dx_date"] + pd.Timedelta(days=OCS_ABX_WINDOW))]
moderate = m[["person_id", "dx_date"]].drop_duplicates().assign(severity="moderate")
events = pd.concat([severe, moderate], ignore_index=True)
first = (events.sort_values(["person_id", "dx_date"])
.groupby("person_id").first().reset_index()
.rename(columns={"dx_date": "event_date"}))
return cohort.merge(first, on="person_id", how="left") # event_date NaT => no event in observed timer implementation
Pragmatic-trial eligibility screening + routine-data outcome ascertainment with data.table (mirrors the Python version). Inputs: dx : person_id, dx_date (Date), dx_code, setting in {'OUTPATIENT','INPATIENT','ED'} rx : person_id, fill_date (Date),...
library(data.table)
BASELINE_DAYS <- 365L
OCS_ABX_WINDOW <- 14L
COPD_DX <- c("J44.0", "J44.1", "J44.9")
screen_eligibility <- function(dx, rx, enroll, arms) {
setDT(dx); setDT(enroll); setDT(arms)
e <- merge(arms, enroll, by = "person_id", all.x = TRUE)
# Pragmatic: only require observable FFS coverage across the baseline window through randomization.
e[, covered := enroll_start <= index_date - BASELINE_DAYS &
enroll_end >= index_date & !ma_only]
bdx <- merge(dx, arms[, .(person_id, index_date)], by = "person_id")
has_copd <- bdx[dx_code %chin% COPD_DX &
dx_date <= index_date &
dx_date >= index_date - BASELINE_DAYS, unique(person_id)]
keep <- e[covered == TRUE & person_id %chin% has_copd,
.(person_id, index_date, arm)]
unique(keep, by = "person_id")
}
first_exacerbation <- function(cohort, dx, rx, enroll) {
setDT(cohort); setDT(dx); setDT(rx)
d <- merge(dx, cohort[, .(person_id, index_date)], by = "person_id")
d <- d[dx_code %chin% COPD_DX & dx_date >= index_date]
severe <- d[setting %chin% c("INPATIENT", "ED"),
.(person_id, event_date = dx_date, severity = "severe")]
out_copd <- d[setting == "OUTPATIENT", .(person_id, dx_date)]
exac_rx <- rx[drug_class %chin% c("OCS", "ANTIBIOTIC"), .(person_id, fill_date)]
m <- merge(out_copd, exac_rx, by = "person_id", allow.cartesian = TRUE)
m <- m[fill_date >= dx_date & fill_date <= dx_date + OCS_ABX_WINDOW]
moderate <- unique(m[, .(person_id, event_date = dx_date)])[, severity := "moderate"]
events <- rbind(severe, moderate)
setorder(events, person_id, event_date)
first <- events[, .SD[1L], by = person_id]
merge(cohort, first, by = "person_id", all.x = TRUE) # event_date NA => no observed event
}