Product/Exposure Registry
An organized, prospective observational system that enrolls patients on the basis of a specific exposure (a drug, device, or biologic) and follows them with standardized data collection to characterize utilization, safety, and effectiveness in routine care.
In plain language
A product registry is a study where patients are enrolled specifically because they are using a particular drug or medical device, and then followed over time to track their health outcomes. Unlike a disease registry — where you enroll anyone with a certain diagnosis regardless of what they are taking — a product registry starts from the exposure: the question is what happens to the people who received this specific product. It is a descriptive tool by default, meaning it tells you rates and patterns among users of the product, but it cannot by itself tell you whether the product caused good or bad outcomes compared to an alternative.
A product (exposure) registry is a study design in which the entry criterion is the exposure itself — patients are enrolled because they received a particular drug, biologic, vaccine, or device — and are then followed prospectively with a pre-specified, standardized data-collection protocol. It is distinct from a disease/condition registry (entry criterion = a diagnosis) and from a health-services registry (entry criterion = an encounter or procedure). The product registry is the workhorse of post-authorization safety and effectiveness commitments: pregnancy exposure registries, biologic/DMARD registries (e.g., rheumatology and IBD biologics), rare-disease enzyme-replacement registries, and device registries are all instances of this design. Because enrollment is anchored to exposure, the registry is, at its core, an exposure cohort without a built-in comparator — and that single structural fact drives almost everything about when it is useful and when it is dangerous.
Core conceptual distinction
Three design features define a product registry and separate it from neighboring designs. (1) Exposure-anchored enrollment: the cohort is assembled by identifying exposed patients (often at or near initiation), not by sampling a source population and observing who gets exposed. (2) Prospective, protocolized primary data collection: unlike a secondary-use claims/EHR study, a registry typically collects new, purpose-built data (clinical severity, outcomes adjudicated against definitions, patient-reported outcomes) on a fixed schedule. (3) Open-ended descriptive estimand by default: the native output is a non-comparative incidence/rate or proportion among the exposed — "what is the rate of outcome Y in patients taking drug X." The moment a causal contrast (drug X vs an alternative) is required, the registry must borrow comparative machinery from cohort methodology (an internal or external active comparator, time-zero alignment, new-user restriction, propensity adjustment). A registry is therefore best understood as a data-collection platform that hosts cohort studies, not as a causal method in itself. Conflating "we ran a registry" with "we estimated an effect" is the single most common interpretive error.
Pros, cons, and trade-offs
(comparative, naming alternatives). - vs secondary-use claims studies: A registry can capture variables claims never see — disease severity, biomarker/lab values, indication nuance, dosing, patient-reported outcomes, and adjudicated endpoints — and can target rare exposures or orphan products that are invisible or miscoded in claims. Cost: it is expensive, slow to accrue, prone to selective enrollment (sicker or more engaged patients), and suffers loss to follow-up; person-time is only as complete as voluntary return visits. Prefer a registry when the key confounders/outcomes are unmeasurable in claims, when the product is rare, or when a regulator mandates adjudicated safety follow-up. Prefer claims when you need population-representative person-time, a concurrent active comparator, and large numbers cheaply. - vs disease/condition registry: The product registry answers "what happens to users of X," the disease registry answers "what happens to patients with condition D regardless of treatment." A disease registry yields a natural within-population comparator (treated vs untreated for the same disease) and better external validity for the disease; a product registry yields cleaner exposure ascertainment and dosing but typically no internal untreated comparator. Prefer the disease registry when the question is comparative within an indication; prefer the product registry when exposure detail, a specific safety signal, or a regulatory product commitment is the driver. - vs single-arm registry with an external comparator (RWD or historical control): Adding an external comparator (matched claims cohort, natural-history disease registry, or trial control arm) lets a product registry support a comparative estimand. Cost: external-control comparisons import every threat of non-randomized, non-concurrent comparison — different measurement instruments, calendar time, case mix, and unmeasured confounding — and are accepted by regulators only in narrow circumstances (e.g., serious disease, large effect, no equipoise). Prefer an internal active comparator whenever the registry can enroll initiators of an alternative therapy. - vs target-trial / active-comparator new-user cohort in routine data: An ACNU cohort in claims/EHR is usually a stronger causal design for a head-to-head question and is far cheaper. Prefer the registry only when the comparative design cannot measure the confounders or outcomes that matter, or when the data simply do not exist outside primary collection.
When to use
(decision rules). Use a product registry when: (a) a regulator requires post-authorization safety/effectiveness follow-up of a specific product (PASS/PAES, REMS, conditional-approval commitment, pregnancy exposure registry); (b) the exposure is rare or newly launched and not yet reliably captured in administrative data; (c) the outcomes or confounders of interest (severity, biomarkers, PROs, adjudicated events) are unobtainable from claims/EHR; or (d) you need a durable platform to host multiple nested cohort and case-control analyses over a product's lifecycle. Build a credible comparator into the protocol from the outset (internal active comparator preferred; a pre-specified external comparator with a transparent bias framing otherwise).
When NOT to use — and when it is actively misleading or dangerous
(decision rules). - Do not use a single-arm product registry to make a comparative effectiveness claim. A bare exposed-only rate has no counterfactual; comparing it informally to "what we expected" or to a literature rate is an external-control comparison in disguise, with all its confounding, and regulators/HTA bodies will (rightly) reject it for anything but the most extreme effects in serious disease. - Do not use it when selective enrollment threatens the estimand. Voluntary, physician-initiated, or consent-gated enrollment can enrich for severity, adherence, or healthy-volunteer effects; an incidence rate from such a cohort does not generalize and can be biased in either direction. If you cannot characterize who enrolls versus the source population, the rate is uninterpretable. - Do not use it for a head-to-head question that a routine-data ACNU cohort can answer. Spending years accruing a registry to estimate something a propensity-adjusted new-user claims cohort delivers in months is poor methodology and poor stewardship. - Beware immortal time and prevalent-user enrollment. If enrollment occurs at a prevalent clinic visit rather than at initiation, survivors are over-represented (depletion of susceptibles) and the gap between true initiation and enrollment is immortal person-time. Enroll incident users and set time zero at initiation, or model the left truncation explicitly. - Beware differential loss to follow-up. Because registry person-time depends on returning, patients who do poorly (or die) may stop contributing; informative censoring biases rates downward unless mortality is captured via linkage and censoring is modeled.
Data-source operational depth
- Primary registry data (the registry's own CRFs): Greatest control over exposure detail, severity, dosing, and adjudicated outcomes, but completeness hinges on site behavior. Failure modes: selective/non-consecutive enrollment, missing follow-up visits, site-to-site definition drift, and over-representation of academic centers. Workarounds: enrollment logs to quantify the consecutive-eligible fraction, central adjudication with explicit endpoint definitions, query rules for missing visits, and source-data verification audits. - Claims linkage (to enrich/validate a registry): Linking the registry to claims fills the person-time and outcome gaps that voluntary follow-up leaves — continuous-enrollment spans define observability, and inpatient/ED/pharmacy claims capture events that occur outside study visits. Failure modes: Medicare Advantage (MA) person-time lacks fee-for-service claims, so a registrant who is MA-only contributes exposure but no claims-based outcome capture, biasing rates among the elderly; sample fills, 90-day mail-order, and free product distort apparent exposure duration. Workaround: restrict claims-based person-time to enrollees with observable benefit (FFS Parts A/B/D or a commercial pharmacy benefit) and treat MA-only spans as censored for claims-ascertained outcomes. - EHR linkage: Adds labs, problem lists, and notes to sharpen indication and baseline severity, but capture is visit-driven and bounded by the network; a patient who seeks care elsewhere is differentially unobserved. Reconcile order/administration dates with the registry's recorded initiation date before assigning time zero. - Linked registry–claims–vital records: The strongest substrate — registry severity + claims completeness + a death index to handle the differential competing risk of death that varies by exposure in elderly cohorts (treating death as a censoring event rather than a competing risk overstates the cumulative incidence of non-fatal outcomes). Cost: linkage introduces selection (only the linkable subset) and date-discrepancy reconciliation.
Worked claims-linked example
Commitment: a pregnancy exposure registry for a new biologic, with a claims-linked safety analysis of major congenital malformations (MCM). (1) Exposure-anchored enrollment: a pregnant person is registered upon a pharmacy fill of the study biologic (NDC + `fill_date` + `days_supply`) during a defined gestational window, with `index_date` = first qualifying fill in pregnancy. (2) Continuous enrollment / observability: require continuous medical + pharmacy enrollment from the estimated last-menstrual-period through delivery + 90 days, with no MA-only spans, so both the exposure and the infant's diagnoses are observable in claims; mother–infant linkage establishes the outcome denominator. (3) Washout / incident use (if a comparative arm is added): no fill of the biologic in the 180 days before LMP, defining incident gestational exposure; the comparator arm enrolls incident users of a guideline alternative for the same indication. (4) Outcome: MCM coded from infant inpatient/outpatient claims in the first year (first-event coding: earliest qualifying malformation dx per infant), adjudicated against the registry's MACDP-style algorithm where charts are available. (5) Person-time / censoring: follow from `index_date` to first MCM, fetal loss, disenrollment, or end of data; capture fetal and infant death via the linked vital-records/death index so that pregnancy loss is handled as a competing event, not silently censored. (6) Analysis: report the exposed MCM proportion with exact confidence intervals as the primary descriptive estimand; for the comparative arm, align time zero, adjust pre-pregnancy confounders with a propensity score measured only in the baseline window, and pre-specify the external-comparison bias framing (national MCM baseline) only as a secondary benchmark, not the primary inference.
Worked example
Scenario
A pharmaceutical company launches a new biologic for rheumatoid arthritis and is required by regulators to track its real-world safety for five years. They open a product registry: any adult who starts this biologic at a participating rheumatology clinic is invited to enroll. Three patients enroll on the day of their first infusion. The registry records each infusion date, the dose given, any serious infections or hospitalizations, and a disease-severity score at every visit. We want to see what basic information the registry collects for each patient and understand what the registry can and cannot answer.
Dataset
Registry enrollment table: one row per patient at the time they join. Enrollment is triggered by the first dose of the product — this is what makes it a product registry rather than a disease registry.
| person_id | enrollment_date | product | indication | enrolled_because_of |
|---|---|---|---|---|
| PT-001 | 2023-03-05 | BiologicX 200mg | Rheumatoid arthritis | Started BiologicX today |
| PT-002 | 2023-04-12 | BiologicX 200mg | Rheumatoid arthritis | Started BiologicX today |
| PT-003 | 2023-07-20 | BiologicX 200mg | Rheumatoid arthritis | Started BiologicX today |
Steps
Each patient's enrollment date is the date of their first BiologicX dose. That date becomes their time zero — the starting line for all follow-up.
From time zero onward, the registry collects structured data at each scheduled clinic visit: infusion records, lab values, disease severity scores, and any serious adverse events reported by the treating physician.
If PT-002 is hospitalized for a serious infection on 2023-09-01, that event is recorded and counted. The registry can then report: among all enrolled patients, how many serious infections occurred per 100 patient-years of follow-up.
Notice who is NOT in this registry: a patient with rheumatoid arthritis who was never prescribed BiologicX would not appear here, even if they have the same diagnosis as PT-001. That is the defining feature of a product registry versus a disease registry.
Because there is no comparison group of patients who did NOT take BiologicX, the registry alone cannot tell you whether BiologicX causes more or fewer infections than, say, a different biologic. It only tells you the rate among BiologicX users.
Result
With 3 patients enrolled on different dates and each followed through 2023-12-31, total follow-up is approximately (301 + 263 + 164) = 728 patient-days, or about 2.0 patient-years. If 1 serious infection occurred (PT-002 in September), the crude rate is 1 event / 2.0 patient-years = 0.50 infections per patient-year, or 50 per 100 patient-years. This number describes BiologicX users only; whether that rate is high or low requires either a comparator group enrolled in the same registry or a separately designed comparison — it cannot be read from this registry alone.
Runnable example
python implementation
Build a product/exposure-registry cohort table from registry enrollment + claims-linked observability. This is COHORT CONSTRUCTION (the registry hosts the analysis), not effect estimation. Required inputs (cleaned, de-duplicated): enroll_reg : registry...
import pandas as pd
import numpy as np
PRE_WASHOUT_DAYS = 180 # incident-use lookback: no prior product fill
OUTCOME_CODES = {"Q00", "Q01", "Q02"} # example outcome dx prefixes (first-event coded)
def build_registry_cohort(enroll_reg, rx, coverage, dx):
# Time zero = first product fill at/after registry enrollment (anchor on EXPOSURE, not the clinic visit).
prod = rx.merge(enroll_reg[["person_id", "product_ndc", "reg_enroll_date"]], on="person_id")
prod = prod[(prod["ndc"] == prod["product_ndc"]) & (prod["fill_date"] >= prod["reg_enroll_date"])]
idx = (prod.sort_values(["person_id", "fill_date"])
.groupby("person_id").first().reset_index()
.rename(columns={"fill_date": "index_date"})[["person_id", "index_date"]])
# Incident-user restriction: no product fill in the PRE_WASHOUT_DAYS before time zero (avoid prevalent-user enrollment).
p = rx.merge(idx, on="person_id")
prevalent = p[(p["fill_date"] < p["index_date"]) &
(p["fill_date"] >= p["index_date"] - pd.Timedelta(days=PRE_WASHOUT_DAYS)) &
(p["ndc"].isin(enroll_reg["product_ndc"].unique()))]["person_id"].unique()
idx = idx[~idx["person_id"].isin(prevalent)].copy()
# Claims-observable follow-up: continuous coverage from time zero, EXCLUDING MA-only person-time (no FFS claims).
c = coverage.merge(idx, on="person_id")
c = c[(~c["ma_only"]) & (c["cov_end"] >= c["index_date"]) & (c["cov_start"] <= c["index_date"])]
obs = c.groupby("person_id")["cov_end"].max().reset_index(name="obs_end")
cohort = idx.merge(obs, on="person_id") # registrants without observable FFS coverage drop out of the rate denominator
# First-event outcome on/after time zero within observable follow-up.
dx = dx.copy()
dx["is_outcome"] = dx["dx_code"].str[:3].isin(OUTCOME_CODES)
ev = dx[dx["is_outcome"]].merge(cohort, on="person_id")
ev = ev[(ev["dx_date"] >= ev["index_date"]) & (ev["dx_date"] <= ev["obs_end"])]
first_ev = ev.groupby("person_id")["dx_date"].min().reset_index(name="event_date")
cohort = cohort.merge(first_ev, on="person_id", how="left")
cohort["event"] = cohort["event_date"].notna().astype(int)
end = cohort["event_date"].fillna(cohort["obs_end"])
cohort["person_days"] = (end - cohort["index_date"]).dt.days.clip(lower=0)
return cohort[["person_id", "index_date", "obs_end", "event", "event_date", "person_days"]]
# Non-comparative incidence rate (the registry's native descriptive estimand):
# rate_per_1000_py = 1000 * cohort["event"].sum() / (cohort["person_days"].sum() / 365.25)r implementation
Registry cohort construction with data.table. Inputs mirror the Python version: enroll_reg : person_id, reg_enroll_date (Date), product_ndc, indication rx : person_id, fill_date (Date), ndc, days_supply coverage : person_id, cov_start, cov_end, ma_only...
library(data.table)
PRE_WASHOUT_DAYS <- 180L
OUTCOME_CODES <- c("Q00", "Q01", "Q02")
build_registry_cohort <- function(enroll_reg, rx, coverage, dx) {
setDT(enroll_reg); setDT(rx); setDT(coverage); setDT(dx)
# Time zero = first product fill at/after registry enrollment (exposure-anchored).
prod <- merge(rx, enroll_reg[, .(person_id, product_ndc, reg_enroll_date)], by = "person_id")
prod <- prod[ndc == product_ndc & fill_date >= reg_enroll_date]
setorder(prod, person_id, fill_date)
idx <- prod[, .(index_date = fill_date[1L]), by = person_id]
# Incident-user restriction: drop prevalent users with a product fill in the pre-washout window.
p <- merge(rx, idx, by = "person_id")
prevalent <- unique(p[fill_date < index_date &
fill_date >= index_date - PRE_WASHOUT_DAYS &
ndc %chin% unique(enroll_reg$product_ndc), person_id])
idx <- idx[!person_id %chin% prevalent]
# Claims-observable follow-up excluding MA-only person-time.
c <- merge(coverage, idx, by = "person_id")
c <- c[!ma_only & cov_end >= index_date & cov_start <= index_date]
obs <- c[, .(obs_end = max(cov_end)), by = person_id]
cohort <- merge(idx, obs, by = "person_id")
# First-event outcome within observable follow-up.
dx[, is_outcome := substr(dx_code, 1L, 3L) %chin% OUTCOME_CODES]
ev <- merge(dx[is_outcome == TRUE], cohort, by = "person_id")
ev <- ev[dx_date >= index_date & dx_date <= obs_end]
first_ev <- ev[, .(event_date = min(dx_date)), by = person_id]
cohort <- merge(cohort, first_ev, by = "person_id", all.x = TRUE)
cohort[, event := as.integer(!is.na(event_date))]
cohort[, end_date := fifelse(is.na(event_date), obs_end, event_date)]
cohort[, person_days := pmax(as.integer(end_date - index_date), 0L)]
cohort[, .(person_id, index_date, obs_end, event, event_date, person_days)]
}