Pregnancy Exposure Window
A protocol-specified set of gestational timing rules that maps maternal dispensings, administrations, or procedures onto etiologically relevant developmental periods (periconceptional, first/second/third trimester, peripartum, lactation) so that in-utero exposure is attributed to the window in which a given fetal or neonatal outcome can plausibly arise.
On this page
A pregnancy exposure window is a specific slice of pregnancy time when a drug could actually cause a birth defect or developmental problem. Instead of simply asking whether a mother took a drug at any point during pregnancy, researchers pin down which biological stage the baby was in when the pills were on hand. For example, the first eight weeks after conception are when the heart, spine, and limbs are being formed, so a drug fill during that window matters far more to birth-defect risk than the same drug taken in the final weeks of pregnancy. In a health insurance claims database, analysts figure out the pregnancy start date, divide the pregnancy into developmental stages, and then check whether any prescription fills overlap each stage, producing a yes/no (or days-of-overlap) score per stage.
A pregnancy exposure window is the date logic that converts a raw maternal exposure record (a pharmacy fill, an infusion administration, a procedure) into the analytic statement "exposed during the developmental period relevant to this outcome." Most teratogenic and developmental effects are time-specific — organogenesis (roughly gestational weeks 3-8) governs the majority of major structural malformations, while later gestation governs fetal growth, neonatal adaptation/withdrawal, and neurodevelopment.
Because of this, a single "any use during pregnancy" indicator is usually the wrong exposure: it dilutes a true window-specific signal toward the null by averaging in person-time when the drug could not have caused the outcome, and it invites confounding by indication when women who continue a drug into later trimesters differ systematically from those exposed only periconceptionally.
Every window is anchored to an estimated pregnancy start date — usually last menstrual period (LMP) or an estimated conception date — which in claims and most EHR data must itself be derived (delivery date minus a gestational-age estimate, or earliest prenatal-ultrasound/dating code).
Once the anchor is set, the analyst applies pre-specified day or week intervals (e.g., LMP-90 to LMP-1 days periconceptional; LMP to LMP+90/97 days first trimester) and computes overlap between the drug's covered-days interval and each gestational interval. The output is a set of per-window exposure variables (binary, days-exposed, or dose-in-window) on the maternal timeline that are then carried into the mother-infant linked outcome analysis.
Core conceptual distinction
the estimand is window-specific, not pregnancy-wide, and the window must be named a priori from biology — e.g., "first-trimester exposure to drug X versus an active comparator and the risk of major congenital malformation among live births." This differs sharply from three superficially similar definitions.
- Versus an any-pregnancy ever-exposed indicator: that variable answers a different, usually less interpretable question and is biased toward the null whenever the causal window is narrow.
- Versus cumulative dose across the whole pregnancy: that matches a cumulative-toxicity model but mis-specifies a pulse/critical-window mechanism.
- Versus exposure-lag/induction windows in non-pregnancy pharmacoepidemiology: pregnancy windows are forward-anchored to a developmental clock (the conceptus's gestational age), not backward-lagged from outcome onset.
Getting the anchor and the window boundaries right is the entire game; the downstream regression is comparatively routine.
Pros, cons, and trade-offs
versus an any-use-during-pregnancy binary, window-specific classification preserves etiologic specificity, raises power for the relevant period, and reduces exposure misclassification from irrelevant person-time — at the cost of requiring a credible LMP estimate, explicit rules for fills that straddle two windows, and a bank of dating-sensitivity analyses. Versus trimester-only buckets (first/second/third with no periconceptional or lactation window), windows let you capture pre-recognition exposures (folate antagonists, retinoids acting before a woman knows she is pregnant) and lactation transfer for some neonatal endpoints, which crude trimester buckets miss.
Versus cumulative-dose-over-pregnancy, a window is easier to communicate ("first-trimester exposed") and correct when the risk is a single critical pulse, but it loses power and is mis-specified when the true relationship is dose-cumulative across gestation — in which case a dose-in-window or time-updated cumulative-dose metric is preferable. The window approach also shares the active-comparator logic of mainstream pharmacoepidemiology: comparing first-trimester initiators of drug X to first-trimester initiators of a clinically interchangeable comparator beats a drug-versus-unexposed contrast, which is confounded by the underlying maternal indication.
When NOT to use — and when it is actively misleading or dangerous
do not impose a window when the outcome has no plausible gestational specificity (e.g., a maternal injury months postpartum); the window only adds noise. Do not trust window membership when LMP cannot be estimated within an acceptable error — very late or absent prenatal care, missing gestational-age fields, or reliance on a delivery code with no dating information can make window misclassification worse than an honest any-pregnancy analysis, and a fill near a trimester boundary will be assigned almost at random.
The design becomes actively dangerous in three situations: (a) differential pregnancy recognition or termination by exposure — women on a known teratogen may be diagnosed earlier, have earlier dating ultrasounds, or undergo elective termination, which depletes the affected fetuses from the live-birth denominator and biases the live-birth-restricted risk toward the null (a form of live-birth/survivor selection bias);
(b) immortal-time-style misalignment when exposure status in a later window is used to define a cohort whose person-time in an earlier window is then counted as "unexposed"; and (c) presenting a reassuring "no increased risk" from an any-pregnancy binary when the etiologically relevant window-specific analysis was never run or was hopelessly under-powered.
Data-source operational depth
- Claims (FFS vs MA vs commercial): LMP is almost always derived — delivery date minus gestational weeks from diagnosis/procedure codes, prenatal-ultrasound dating codes, or a published/validated algorithm. Drug exposure is the pharmacy claim (`ndc` + `fill_date` + `days_supply`); you must construct covered-day intervals and handle reversals, early refills, stockpiling, and 90-day mail-order supplies before computing window overlap. Require continuous medical + pharmacy enrollment across the entire periconceptional-through-delivery span so that "no fill in the window" is observed non-exposure, not missingness.
Specific failure modes: Medicare Advantage and capitated/bundled person-time drop fee-for-service claims, so a MA-only span fabricates apparent non-exposure — restrict to enrollees with both medical and pharmacy benefit and exclude MA-only person-time. Differential competing risks of fetal loss by exposure distort the live-birth denominator; report the proportion of pregnancies ending in an observed live birth by arm and analyze non-live-birth endpoints in the maternal cohort. Immortal time in procedure or infusion studies — e.g., requiring a second-trimester administration to be "exposed" makes all of the first trimester immortal — must be avoided by aligning time zero to the first qualifying exposure.
- EHR: Prenatal flow sheets, dating ultrasounds, and problem-list gestational age give a direct LMP/EDC and far sharper exposure timing via e-prescribing and medication administration records than fills alone. The cost is visit-driven, leaky capture: external pharmacies and care outside the system are missing, and a patient who leaves the network is differentially lost. Link to claims for complete dispensing and for infant outcomes rendered elsewhere.
- Registry: Product or disease pregnancy registries capture exact LMP, ultrasound dating, exposure dates, and adjudicated outcomes prospectively with high validity — but are small and selected (enrollment, recall, and healthy-volunteer effects). Their best use is to validate claims-based window/LMP algorithms or to triangulate effect sizes, not to estimate population risk alone.
- Linked claims-EHR-vital records: The reference substrate — claims for complete pharmacy + enrollment, EHR for clinical dating and infant exams, vital/birth records for confirmed live births and recorded gestational age. The catch is linkage selection (only the linkable subset) and date reconciliation across order, fill, service, and delivery dates, which must be resolved before any window is assigned.
Worked claims example (antiepileptic drug, first-trimester major-malformation risk)
Source: linked commercial + multi-state Medicaid claims, 2016-2023. Build the pregnancy cohort by identifying delivery claims, then back-date LMP with a validated gestational-age algorithm (delivery_date - estimated gestational weeks) or the earliest prenatal-dating ultrasound code when present.
Eligibility: continuous maternal medical + pharmacy enrollment (no MA-only spans) from LMP-90 days through 90 days post-delivery, and a linked infant continuously enrolled >=90 days. Define the first-trimester window as `[LMP, LMP+97 days]`. For each maternal fill, compute its covered interval `[fill_date, fill_date + days_supply - 1]` and flag `exp_t1 = 1` if that interval overlaps the first-trimester window by at least one day (primary, binary); secondary metrics are days-overlapping-window and average daily milligrams in window.
Outcome: a major-congenital- malformation algorithm with validated PPV > 0.80 applied to infant claims in days 0-90 plus the index inpatient stay. Restrict to first-trimester initiators of the index AED versus first-trimester initiators of an active-comparator AED (active-comparator, new-user logic ported into pregnancy), and balance maternal age, epilepsy-type and severity proxies, comorbidities, folic-acid use, and concomitant AEDs with a high-dimensional propensity score (matching or overlap weighting).
In this construction the adjusted risk ratio for first-trimester exposure to the teratogenic AED was 2.8 (95% CI 1.6-4.9), whereas the any-pregnancy ever-exposed RR was only 1.9 (1.1-3.2) — diluted by third-trimester-only users for whom organogenesis had passed. Pre-specified dating-sensitivity analyses (shift the LMP algorithm by +/-14 days; move the window end by +/-7 days; reassign straddling fills by majority-of-covered-days rather than any-overlap) moved the point estimate only between 2.4 and 3.1, and a negative-control outcome with no plausible teratogenic mechanism was null, supporting robustness against residual dating error and confounding.
Decision diagram
flowchart TD A[Delivery claim identified] --> B["Estimate LMP / pregnancy start<br/>delivery date - algorithm gestational weeks<br/>or earliest ultrasound dating code"] B --> C["Require continuous medical+pharmacy enrollment<br/>LMP-90 through post-delivery; exclude MA-only person-time"] C --> D["Define windows from LMP<br/>Periconceptional | T1 0-97d | T2 | T3 | Lactation"] D --> E["Build covered intervals from fill_date + days_supply<br/>apply straddling-fill rule"] E --> F["Per-window exposure: binary / days-in-window / dose-in-window"] F --> G["Link to infant; apply validated outcome algorithm<br/>require infant enrollment"] G --> H["Sensitivity: LMP +/-14d, window +/-7d,<br/>straddle rule, negative-control outcome"]
flowchart LR Cause[Maternal drug exposure] --> Recog[Earlier pregnancy recognition<br/>+ dating ultrasound in exposed] Recog --> Term[Differential elective termination<br/>or detected fetal loss] Term --> LB[Live-birth restriction] Cause --> Mal[Fetal malformation] Mal --> Term LB --> Est[Live-birth-restricted risk] Mal --> Est Term -. depletes affected fetuses .-> Est
Worked example
Scenario
Maria is a 28-year-old with epilepsy who filled a prescription for an antiepileptic drug several times during her pregnancy. Her delivery was on 2023-09-28, and a validated algorithm estimates her LMP as 2022-12-28, giving a gestational length of about 274 days. We want to know whether she had the drug on hand during the first trimester, specifically the organogenesis window (LMP through LMP+97 days, i.e., 2022-12-28 through 2023-04-04), because that is when major structural malformations are most plausible. We will look up her pharmacy fills in the claims table and compute whether any covered-day interval overlaps that first-trimester window.
Dataset
Maria's pharmacy claims rows (person_id 2001). Each row is one prescription fill.
| person_id | fill_date | drug | days_supply |
|---|---|---|---|
| 2001 | 2022-12-01 | levetiracetam 500 mg | 30 |
| 2022 | 2022-12-01 | levetiracetam 500 mg | 30 |
| 2001 | 2022-12-30 | levetiracetam 500 mg | 90 |
| 2001 | 2023-03-28 | levetiracetam 500 mg | 90 |
| 2001 | 2023-06-25 | levetiracetam 500 mg | 90 |
Steps
Result
Maria is classified as first-trimester exposed (binary = 1). Her covered days fully span the 98-day first-trimester window (Dec 28, 2022 through Apr 4, 2023), meaning the drug was theoretically on hand during the entire organogenesis period. This exposure flag is what gets carried into the birth-defect outcome analysis.
Trade-offs
Runnable example
Window assignment from claims-style inputs. Required inputs (already cleaned, de-duplicated, and enrollment-filtered): preg : one row per pregnancy -> person_id, lmp_derived (datetime), delivery_date (datetime) # lmp_derived comes from a validated back-dating algorithm or prenatal-dating code, NOT a constant 280...
import pandas as pd
import numpy as np
# Window edges as integer days relative to LMP (LMP = day 0). End is inclusive.
WINDOWS = {
"precon": (-90, -1), # periconceptional: 90 days before LMP
"t1": (0, 97), # first trimester (organogenesis-bearing)
"t2": (98, 195), # second trimester
"t3": (196, 300), # third trimester (capped; delivery may truncate)
}
def assign_windows(preg: pd.DataFrame, rx: pd.DataFrame) -> pd.DataFrame:
f = rx.merge(preg[["person_id", "lmp_derived", "delivery_date"]], on="person_id", how="inner")
# Covered interval of each fill, in days since LMP.
f["cov_start"] = (f["fill_date"] - f["lmp_derived"]).dt.days
f["cov_end"] = f["cov_start"] + f["days_supply"].astype(int) - 1
# Truncate third trimester at the observed delivery day so post-delivery supply isn't counted in utero.
deliv_day = (f["delivery_date"] - f["lmp_derived"]).dt.days
rows = []
for win, (w0, w1_const) in WINDOWS.items():
w1 = np.minimum(w1_const, deliv_day) if win == "t3" else pd.Series(w1_const, index=f.index)
ov_start = np.maximum(f["cov_start"], w0)
ov_end = np.minimum(f["cov_end"], w1)
days_overlap = (ov_end - ov_start + 1).clip(lower=0)
tmp = f.assign(window=win, days_in_window=days_overlap)
tmp["mg_in_window"] = tmp["days_in_window"] * tmp.get("daily_mg", np.nan)
rows.append(tmp[["person_id", "window", "days_in_window", "mg_in_window"]])
long = pd.concat(rows, ignore_index=True)
agg = (long.groupby(["person_id", "window"], as_index=False)
.agg(days_in_window=("days_in_window", "sum"),
mg_in_window=("mg_in_window", "sum")))
agg["exposed"] = (agg["days_in_window"] > 0).astype(int) # any-overlap binary; swap for majority-of-days rule
wide = agg.pivot(index="person_id", columns="window",
values=["exposed", "days_in_window", "mg_in_window"])
wide.columns = [f"{m}_{w}" for m, w in wide.columns]
return preg.merge(wide.reset_index(), on="person_id", how="left").fillna(
{c: 0 for c in wide.columns if c.startswith("exposed_")})data.table window assignment mirroring the Python version. Inputs (cleaned, enrollment-filtered): preg : person_id, lmp_derived (Date), delivery_date (Date) rx : person_id, ndc, fill_date (Date), days_supply (integer), daily_mg (numeric, optional) Produces per-pregnancy any-overlap binary, days-in-window, and...
library(data.table)
# Window edges in days relative to LMP (day 0); end inclusive.
win_edges <- list(precon = c(-90L, -1L), t1 = c(0L, 97L),
t2 = c(98L, 195L), t3 = c(196L, 300L))
assign_windows <- function(preg, rx) {
setDT(preg); setDT(rx)
f <- merge(rx, preg[, .(person_id, lmp_derived, delivery_date)], by = "person_id")
f[, cov_start := as.integer(fill_date - lmp_derived)]
f[, cov_end := cov_start + as.integer(days_supply) - 1L]
f[, deliv_day := as.integer(delivery_date - lmp_derived)]
if (!"daily_mg" %in% names(f)) f[, daily_mg := NA_real_]
out <- rbindlist(lapply(names(win_edges), function(win) {
w0 <- win_edges[[win]][1L]
w1 <- if (win == "t3") pmin(win_edges[[win]][2L], f$deliv_day) else win_edges[[win]][2L]
ov_start <- pmax(f$cov_start, w0)
ov_end <- pmin(f$cov_end, w1)
days_ov <- pmax(ov_end - ov_start + 1L, 0L)
data.table(person_id = f$person_id, window = win,
days_in_window = days_ov, mg_in_window = days_ov * f$daily_mg)
}))
agg <- out[, .(days_in_window = sum(days_in_window),
mg_in_window = sum(mg_in_window, na.rm = TRUE)),
by = .(person_id, window)]
agg[, exposed := as.integer(days_in_window > 0)] # any-overlap; swap for majority-of-days rule
wide <- dcast(agg, person_id ~ window,
value.var = c("exposed", "days_in_window", "mg_in_window"), fill = 0)
merge(preg, wide, by = "person_id", all.x = TRUE)
}Window assignment and a standardized exposed-vs-comparator risk step in SAS. Required inputs (post data-management, enrollment-filtered, dates as SAS date values): work.preg : person_id, lmp_derived, delivery_date work.rx : person_id, ndc, fill_date, days_supply, daily_mg (optional) PROC SQL computes day-overlap of...
/* 1. Covered interval of each fill in days since LMP, joined to the pregnancy anchor. */
proc sql;
create table fills as
select r.person_id, r.ndc, r.daily_mg,
(r.fill_date - p.lmp_derived) as cov_start,
(r.fill_date - p.lmp_derived) + r.days_supply - 1 as cov_end,
(p.delivery_date - p.lmp_derived) as deliv_day
from work.rx r
inner join work.preg p on r.person_id = p.person_id;
quit;
/* 2. Day-overlap with each window; t3 truncated at the observed delivery day. Any-overlap = exposed. */
proc sql;
create table exp_wide as
select person_id,
max( max(0, calculated o_precon) > 0 ) as exposed_precon,
max( max(0, calculated o_t1) > 0 ) as exposed_t1,
max( max(0, calculated o_t2) > 0 ) as exposed_t2,
max( max(0, calculated o_t3) > 0 ) as exposed_t3,
/* days-in-window for dose/intensity secondary analyses */
sum( max(0, calculated o_t1) ) as days_t1
from (
select person_id,
(min(cov_end, -1) - max(cov_start, -90) + 1) as o_precon,
(min(cov_end, 97) - max(cov_start, 0) + 1) as o_t1,
(min(cov_end, 195) - max(cov_start, 98) + 1) as o_t2,
(min(cov_end, min(300, deliv_day)) - max(cov_start, 196) + 1) as o_t3
from fills)
group by person_id;
quit;
/* 3. Adjusted first-trimester exposure vs active comparator on the linked infant malformation outcome.
work.analytic = exp_wide joined to maternal baseline covariates + infant outcome (mcm=0/1) + arm. */
proc genmod data=work.analytic descending;
class arm(ref='COMPARATOR') epilepsy_type / param=ref;
model mcm = exposed_t1 mat_age epilepsy_type folate concomitant_aed
/ dist=binomial link=log; /* log-binomial -> adjusted risk ratio */
estimate 'First-trimester exposure RR' exposed_t1 1 / exp;
run;Citations
- [1]Huybrechts KF, Bateman BT, Hernández-Díaz S. Use of real-world evidence from healthcare utilization data to evaluate drug safety during pregnancy. Pharmacoepidemiology and Drug Safety. 2019;28(7):906-922.
- [2]Margulis AV, Setoguchi S, Mittleman MA, Glynn RJ, Dormuth CR, Hernández-Díaz S. Algorithms to estimate the beginning of pregnancy in administrative databases. Pharmacoepidemiology and Drug Safety. 2013;22(1):16-24.