Disease Registry
An organized, prospective system that uses observational methods to collect uniform, often adjudicated data on a defined population of patients sharing a particular disease or condition, to study natural history, outcomes, quality of care, or treatment effectiveness and safety.
In plain language
A disease registry is a study that signs up patients who all share one disease (say, pulmonary arterial hypertension) at participating clinics, then follows them over time and records the same set of clinical details for everyone on a fixed schedule. Unlike billing records, which only capture what someone paid for, a registry deliberately collects things like disease stage, lab biomarkers, and carefully reviewed outcomes, so it can describe how a disease unfolds and how patients fare. The catch: it only sees patients at the clinics that chose to take part (often big academic centers), so it is rich in clinical detail but not a representative snapshot of every patient with the disease.
A disease (condition) registry is a primary-data-collection observational study: investigators define a population by a disease or clinical condition (e.g., pulmonary arterial hypertension, idiopathic pulmonary fibrosis, a specific cancer) and prospectively enroll those patients at participating sites, capturing a predefined minimum dataset on a fixed schedule. This is the defining contrast with secondary-data RWD: claims and EHR are repurposed byproducts of billing and care, whereas a registry collects fit-for-purpose variables — disease severity, adjudicated events, patient-reported outcomes — that claims simply do not contain. Scope note: this entry covers disease registries. Product/exposure registries (anchored on a drug or device, the typical EU PASS or pregnancy-exposure registry) and health-services registries (anchored on an encounter or procedure) are close cousins with the same machinery but a different enrollment anchor; treat them as separate concepts.
Core conceptual distinction
. The registry is defined by its enrollment anchor and data provenance, not by an analytic contrast. Three things distinguish it from a claims/EHR cohort. (1) Anchor: entry is the date a patient is enrolled at a participating site after meeting clinical inclusion criteria — typically incident (newly diagnosed) or a mix of incident and prevalent patients, which must be declared because prevalent enrollment reintroduces left-truncation and survivor bias. (2) Provenance: variables are collected for the study, so severity, stage, ejection fraction, and adjudicated endpoints are available, but completeness depends on site staff and patient retention rather than a claim being filed. (3) Sampling frame: patients come from participating sites, which are rarely a probability sample of all care settings — academic and specialty centers are over-represented. The registry does not, by itself, deliver a causal estimand; it is a data platform on which natural-history description, quality benchmarking, or a comparative analysis (often an active-comparator new-user contrast nested within the registry, frequently with claims linkage for complete exposure and outcomes) is built.
Pros, cons, and trade-offs
. - vs claims/EHR secondary-data cohorts: the registry captures clinical depth claims cannot — disease severity, functional class, adjudicated outcomes, PROs — and applies uniform definitions across sites. Cost: it is expensive and slow, enrolls a non-random slice of patients seen at participating sites, and suffers active loss to follow-up that passive claims do not (claims keep accruing as long as the person is enrolled in the plan). Prefer the registry when the scientific question hinges on variables absent from administrative data. - vs a randomized trial: the registry reflects routine practice, includes patients trials exclude (elderly, comorbid, pregnant), and supports long-term and rare-disease follow-up at scale. Cost: no randomization, so confounding by indication and channeling remain; it answers what happens in practice, not the internally valid average treatment effect. Prefer the registry for external validity, natural history, and rare diseases where a trial is infeasible. - vs a registry-claims linked study: linkage to claims and a death index buys complete exposure (every fill, every hospitalization, reliable mortality) on top of registry clinical depth. Cost: only the linkable subset is analyzable (a new selection layer), and registry, claims, and vital-records dates must be reconciled. Prefer linkage whenever exposure or outcome completeness is the binding constraint and consent/linkage is feasible.
When to use
. Natural-history and prognostic studies of a defined disease; rare-disease research where no other source has adequate numbers; quality-of-care benchmarking across sites; regulatory commitments that require primary data — FDA post-marketing requirements (PMRs), EMA post-authorization safety/efficacy studies (PASS/PAES), HTA managed-entry / outcomes-based agreements, and CMS Coverage with Evidence Development (CED). Use it when the decision-grade variables (severity, adjudicated endpoints, PROs) do not exist in claims or EHR and uniform prospective capture across sites is worth the cost.
When NOT to use — and when it is actively misleading or dangerous
. - When you need a representative population estimate but enrollment is by convenience. Site-level and patient consent selection make the registry a poor frame for incidence/prevalence or population-attributable burden; presenting registry proportions as population rates is misleading. - When sites cherry-pick patients. Differential enrollment of healthier (or sicker) patients, or enrolling only those who survive to a referral visit, inflates apparent benefit and biases survival — a covert immortal-time/left-truncation problem if enrollment lags diagnosis. - When the comparison is across registries or across calendar time without harmonization. Secular drift in capture, evolving diagnostic criteria, and site mix changes confound time trends; registry-to-registry contrasts without common data definitions are unreliable. - When loss to follow-up is differential by exposure or prognosis. Patients who deteriorate may stop attending the enrolling center; naive complete-case analysis then overstates benefit. Treat dropout as potentially informative and quantify it. - When the registry is used as a single-arm external control without a defensible comparator. Comparing a new drug's registry arm to historical registry patients invites confounding by indication and period effects unless eligibility, time zero, and covariates are explicitly emulated.
Data-source operational depth
. - Registry (primary): Strongest for indication, disease severity/stage, adjudicated endpoints, and PROs; enrollment date is the natural index. Failure modes: voluntary site participation and patient consent (selection on both); differential loss to follow-up; secular drift as criteria and site mix change; gaps between the registry data cutoff and current practice that make recent patients look incomplete. Workarounds: predefine a minimum dataset and adjudication charter; restrict to consecutive (not convenience) enrollment where possible; model site as a random effect; censor at last documented contact and conduct loss-to-follow-up sensitivity analyses; restrict to overlapping enrollment calendar time for trend or cross-cohort work. - Claims: Used for linkage to a disease registry to complete exposure (NDC + `fill_date` + `days_supply`) and outcomes (hospitalization, procedures, death). Failure modes specific to claims under linkage: Medicare Advantage-only person-time lacks fee-for-service claims, so a registry enrollee who is MA-only appears to have no fills/events — exclude MA-only person-time and require continuous Parts A/B (and D for drug exposure). Differential competing risks by exposure in elderly registry cohorts: deaths captured by the registry but not the claims feed (or vice versa) distort cause-specific event rates — link to a death index and use a competing-risk framework, not naive Kaplan-Meier. Immortal time in procedure-anchored sub-studies: time between enrollment and a later procedure must be classified, not silently attributed to the post-procedure arm. - EHR: A registry can be partly auto-populated from a site's EHR, gaining labs and notes cheaply, but visit-driven capture means patients who leave the system are differentially missing; provenance of each variable (entered by abstractor vs pulled from EHR) should be tracked because the two have different error structures. - Linked registry-claims-vital records: The ideal substrate (clinical depth + exposure/outcome completeness + reliable mortality), but only the linkable, consented subset is analyzable, and registry enrollment dates, claims service dates, and vital-records death dates must be reconciled before time-zero and censoring assignment.
Worked claims-linked example
Question: 3-year all-cause mortality and heart-failure hospitalization among newly diagnosed pulmonary arterial hypertension (PAH) patients, using a PAH disease registry (REVEAL-style) linked to Medicare. (1) Eligibility: registry-confirmed incident PAH (right-heart-catheterization-adjudicated, enrolled within 90 days of diagnosis to limit left-truncation), age ≥65, and successful registry→Medicare linkage. (2) Continuous-enrollment / observability window: require continuous Medicare Parts A and B (plus Part D if PAH-drug exposure is studied) for the 12 months before and throughout follow-up after the registry enrollment date, and exclude any MA-only person-time because fee-for-service claims — and therefore HF hospitalizations and fills — are not observable then. (3) Index date (time zero): registry enrollment date; baseline covariates (WHO functional class, 6-minute walk, hemodynamics) come from the registry visit, comorbidities from the 12-month claims lookback. (4) Outcome ascertainment from both sources: HF hospitalization from a claims inpatient stay with a qualifying primary diagnosis, and the registry-adjudicated clinical-worsening event; flag and tabulate disagreement (registry event with no claim, or claim with no registry capture) rather than silently trusting one. (5) Death: take the earliest of registry-recorded death and the linked death-index date; treat death as a competing risk for HF hospitalization (Fine-Gray / cumulative incidence), not as censoring. (6) Censor at the minimum of last documented registry contact, Medicare disenrollment (or MA switch), death, and study end; run a loss-to-follow-up sensitivity analysis comparing those lost vs retained, because PAH patients who deteriorate may stop attending the enrolling center.
Worked example
Scenario
We have three newly diagnosed pulmonary arterial hypertension (PAH) patients enrolled in a PAH disease registry. We want to see what a registry record actually looks like and why it captures clinical detail that an insurance claims table never would. Each registry row carries the patient's diagnosis date, disease stage, a biomarker, which treatment arm they are on, and a reviewer-confirmed outcome.
Dataset
A few rows from a disease-registry table: clinical fields collected on purpose for the study, the same way at every site.
| patient_id | diagnosis_date | stage | biomarker | protocol_arm | outcome |
|---|---|---|---|---|---|
| 2001 | 2023-02-14 | WHO FC III | NT-proBNP 1450 pg/mL | endothelin-receptor antagonist | clinical worsening |
| 2002 | 2023-04-03 | WHO FC II | NT-proBNP 320 pg/mL | PDE5 inhibitor | stable |
| 2003 | 2023-05-21 | WHO FC IV | NT-proBNP 3100 pg/mL | combination therapy | death |
Steps
Each row is one enrolled patient. The registry recorded their diagnosis date and disease severity (WHO functional class, where higher is sicker) at enrollment, on a fixed schedule, using the same definitions at every site.
It also stored a biomarker (NT-proBNP, a blood marker that rises with heart strain) and which drug arm the patient is on. These are exactly the decision-grade clinical variables a billing claims table does not contain.
The outcome column holds a reviewer-confirmed event, not a raw billing code: patient 2001 worsened, 2002 stayed stable, 2003 died. A claims table would at best show a hospital stay or a death payment flag, with no stage or biomarker to explain it.
Because only these three patients were seen at participating sites, the table is detailed but not a representative count of all PAH patients; sicker patients at academic centers can be over-represented.
Result
The registry rows tell you that of three incident PAH patients, the two sicker ones at enrollment (WHO FC III and IV, with high NT-proBNP of 1450 and 3100) went on to worsen or die, while the milder patient (WHO FC II, NT-proBNP 320) stayed stable. That severity-to-outcome story is visible only because the registry deliberately captured stage and biomarker, detail claims data lacks, and it applies only to patients enrolled at the participating sites.
Runnable example
python implementation
Disease-registry cohort construction with claims linkage (Study_Design, not estimation). Required inputs (cleaned, de-duplicated): reg : registry enrollment -> person_id, enroll_date (datetime), incident_flag (bool), dx_date (datetime), site_id,...
import pandas as pd
import numpy as np
BASELINE_DAYS = 365 # claims lookback for comorbidities / incident confirmation
INCIDENT_WINDOW = 90 # max days from diagnosis to enrollment (limit left-truncation)
STUDY_END = pd.Timestamp("2020-12-31")
def build_registry_cohort(reg, enroll, events, death):
# 1) Inception restriction: incident patients enrolled close to diagnosis.
reg = reg.copy()
reg["dx_to_enroll"] = (reg["enroll_date"] - reg["dx_date"]).dt.days
coh = reg[reg["incident_flag"] & (reg["dx_to_enroll"].between(0, INCIDENT_WINDOW))].copy()
coh["t0"] = coh["enroll_date"]
coh["baseline_start"] = coh["t0"] - pd.Timedelta(days=BASELINE_DAYS)
# 2) Observability: continuous, FFS-observable claims (no MA-only) across baseline through t0.
e = enroll.merge(coh[["person_id", "t0", "baseline_start"]], on="person_id")
e["covers"] = ((e["enroll_start"] <= e["baseline_start"]) &
(e["enroll_end"] >= e["t0"]) &
(~e["ma_only"])) # MA-only person-time lacks FFS claims
linkable = e.loc[e["covers"], "person_id"].unique()
coh = coh[coh["person_id"].isin(linkable)].copy() # consented + linkable subset only
# 3) Death from the earliest of registry death and death-index date (reconcile sources).
d = death.groupby("person_id")["death_date"].min().rename("dx_death")
coh = coh.merge(d, on="person_id", how="left")
# 4) Censoring = min(last registry contact, claims disenroll/MA switch, death, study end).
disenroll = (enroll[~enroll["ma_only"]].groupby("person_id")["enroll_end"].max()
.rename("ffs_end"))
coh = coh.merge(disenroll, on="person_id", how="left")
coh["censor_date"] = coh[["last_contact_date", "ffs_end", "dx_death"]].min(axis=1)
coh["censor_date"] = coh["censor_date"].clip(upper=STUDY_END)
# 5) Outcome from BOTH sources within follow-up; flag disagreement rather than trusting one.
ev = events[events["event_flag"]].merge(coh[["person_id", "t0", "censor_date"]], on="person_id")
ev = ev[(ev["service_date"] >= ev["t0"]) & (ev["service_date"] <= ev["censor_date"])]
claims_evt = ev.groupby("person_id")["service_date"].min().rename("claims_event_date")
coh = coh.merge(claims_evt, on="person_id", how="left")
coh["registry_event"] = coh["reg_event_date"].between(coh["t0"], coh["censor_date"])
coh["claims_event"] = coh["claims_event_date"].notna()
coh["event_disagree"] = coh["registry_event"] ^ coh["claims_event"] # source disagreement to tabulate
return coh[["person_id", "site_id", "t0", "baseline_start", "censor_date",
"registry_event", "claims_event", "event_disagree", "dx_death"]]r implementation
Disease-registry cohort construction with claims linkage using data.table. Inputs mirror the Python version: reg : person_id, enroll_date (Date), incident_flag (logical), dx_date (Date), site_id, last_contact_date (Date), reg_event_date (Date or NA)...
library(data.table)
BASELINE_DAYS <- 365L
INCIDENT_WINDOW <- 90L
STUDY_END <- as.Date("2020-12-31")
build_registry_cohort <- function(reg, enroll, events, death) {
setDT(reg); setDT(enroll); setDT(events); setDT(death)
# 1) Inception restriction: incident, enrolled close to diagnosis.
coh <- reg[incident_flag &
as.integer(enroll_date - dx_date) %between% c(0L, INCIDENT_WINDOW)]
coh[, t0 := enroll_date]
coh[, baseline_start := t0 - BASELINE_DAYS]
# 2) Observability: continuous FFS-observable claims (no MA-only) across baseline through t0.
e <- merge(enroll, coh[, .(person_id, t0, baseline_start)], by = "person_id")
linkable <- e[enroll_start <= baseline_start & enroll_end >= t0 & !ma_only,
unique(person_id)]
coh <- coh[person_id %chin% linkable]
# 3) Death = earliest of registry/death-index; 4) censor = min(last contact, FFS end, death, study end).
d <- death[, .(dx_death = min(death_date)), by = person_id]
ff <- enroll[!ma_only, .(ffs_end = max(enroll_end)), by = person_id]
coh <- merge(coh, d, by = "person_id", all.x = TRUE)
coh <- merge(coh, ff, by = "person_id", all.x = TRUE)
coh[, censor_date := pmin(last_contact_date, ffs_end, dx_death, STUDY_END, na.rm = TRUE)]
# 5) Outcome from BOTH sources; flag disagreement.
ev <- merge(events[event_flag == TRUE], coh[, .(person_id, t0, censor_date)], by = "person_id")
ev <- ev[service_date >= t0 & service_date <= censor_date,
.(claims_event_date = min(service_date)), by = person_id]
coh <- merge(coh, ev, by = "person_id", all.x = TRUE)
coh[, registry_event := reg_event_date >= t0 & reg_event_date <= censor_date]
coh[, claims_event := !is.na(claims_event_date)]
coh[, event_disagree := xor(registry_event %in% TRUE, claims_event)]
coh[, .(person_id, site_id, t0, baseline_start, censor_date,
registry_event, claims_event, event_disagree, dx_death)]
}