ExpertIndependently reviewed, not yet spot-checked by a human

Self-controlled designs

Let every person serve as their own control and every characteristic that does not change over time cancels out at once — including the ones you never measured and do not know exist. What separates SCCS from case-crossover, when each of the three assumptions breaks, and why "does the event change what happens to the exposure afterwards?" is the question that decides whether this design works at all.

What this page answers

The instrumental variables page tackles the same predicament — unmeasured confounding — at a high price: two of three assumptions cannot be verified, and the confidence interval widens several-fold.

Self-controlled designs take an entirely different route, and the idea behind them is almost brutally simple:

If the two sides of the comparison are two stretches of time in the same person, then everything about that person that does not change over time disappears from the comparison.

Genes, constitution, sex, ancestry, childhood environment, socioeconomic position, the baseline burden of chronic disease, health-seeking habits — it makes no difference whether you measured any of them, because within one person they take the same value in both stretches of time and cancel out. This is not statistical adjustment; it is elimination by design.

The cost moves elsewhere. The design answers “why now?” and never “why me?”; it suits transient exposures paired with acute events with a definite date; and it carries three assumptions, at least one of which is routinely broken in pharmacoepidemiology.

Two kinds of anchor: SCCS and case-crossover

Every self-controlled design is defined by three things: an anchor (a fixed point on the timeline), a focal window (the stretch during which risk is hypothesised to be raised), and one or more referent windows (used to estimate how often things happen ordinarily). The analysis is always stratified by person — conditional Poisson or conditional logistic regression — and that step is where the time-invariant characteristics actually get eliminated.

The two families differ in where the anchor is pinned:

Case-crossover (CCO)Self-controlled case series (SCCS)
AnchorThe outcome eventThe exposure
What is comparedFrequency of exposure in focal vs referent windowsEvent rate in focal vs referent windows
The question“Given that the event happened now, how likely is it that exposure preceded it?”“Given that exposure happened, how likely is an event shortly afterwards?”
Where the referent window sitsOne or more time points before the eventAll of the observation period outside the focal window
DirectionOne-directional (unless deliberately made bidirectional)Bidirectional — observation does not end because an event occurred
ModelConditional logistic regression or Mantel-Haenszel, giving an ORConditional Poisson regression, giving an IRR
With long-term medicationKnown upward bias (persistent user bias)Less affected, but more exposed to time-varying confounding
If the event changes later exposureInsensitive (the referent window precedes the event)Sensitive — it is one of the core assumptions
If the event changes the length of observationInsensitiveSensitive (fatal outcomes break it outright)

Those last two rows usually decide which design to use: when the outcome is often fatal, or when clinicians stop the drug after an event, case-crossover is the safer choice; when use of the exposure is changing quickly over calendar time — a vaccine rollout, for instance — SCCS is safer.

The simulation on this page

The setup matches the most typical pharmacoepidemiological question: a fourteen-day course of treatment and an acute event — admission for an arrhythmia, say — with a true incidence rate ratio of 3.0. Two things were built into it deliberately:

  • Baseline event rates differ a great deal between people (the frailty term has a standard deviation of 1.0, so the highest- and lowest-risk people differ several-fold), and that frailty is never measured.
  • Sicker people are more likely to be prescribed the drug — in the simulated data, exposed and unexposed people differ by 0.83 standard deviations of frailty.

The simulation follows 4000 people for 365 days each; 1614 of them used the drug at some point, and 4084 events occurred in total.

Timelines for eight simulated patients, one row each. The grey line is a 365-day observation period, the yellow block is the 14-day risk window, red dots are events falling inside that window and blue dots are events outside it. The first four patients have an event inside the risk window; the last four do not.
Eight simulated patients. The yellow block is the fourteen-day risk window (the focal window) and the rest of the observation period is referent. The only comparison this design ever makes is between yellow and non-yellow within a single row — no two rows are ever compared with each other.Plotting script figures/scripts/B6-05-self-controlled.R

The SCCS conditional likelihood, written out

At the heart of SCCS is one line of algebra you can write by hand. Take a patient with nin_i events during observation, of which ni,riskn_{i,\text{risk}} fall inside the risk window, who spent rir_i days in the risk window and cic_i days in the referent window. Conditional on the total number of events that patient had, the probability of them landing in the risk window gives:

Li(β)=(eβ)ni,risk(ci+eβri)niL_i(\beta) = \frac{\left(e^{\beta}\right)^{n_{i,\text{risk}}}}{\left(c_i + e^{\beta} r_i\right)^{n_i}}

eβe^\beta is the incidence rate ratio (IRR). The patient’s baseline risk does not appear in the expression — conditioning on how many events they had cancelled it out. That single line is the entire content of “every time-invariant characteristic is eliminated”.

It also explains two further facts: only people with both an event and an exposure contribute to the estimate (everyone else contributes a constant, which differentiates away), and this design cannot estimate absolute risk — the denominator was conditioned out, leaving only a ratio.

library(survival)
set.seed(20260822)

OBS <- 365L; RISK <- 14L; IRR <- 3.0; BASE <- 0.0016

# -- Simulation: frailty is unmeasured and drives both whether the drug is
#    prescribed and the event rate --------------------------------------
simulate_people <- function(n) {
  frailty <- rnorm(n)
  exposed <- rbinom(n, 1, plogis(-0.5 + 1.0 * frailty))   # confounding by indication
  start   <- ifelse(exposed == 1, sample(OBS - RISK, n, TRUE), NA)
  rate    <- BASE * exp(frailty)
  lapply(seq_len(n), function(i) {
    inrisk <- rep(FALSE, OBS)
    if (exposed[i] == 1) inrisk[start[i]:(start[i] + RISK - 1L)] <- TRUE
    days <- which(rbinom(OBS, 1, pmin(rate[i] * ifelse(inrisk, IRR, 1), 1)) == 1)
    list(exposed = exposed[i], inrisk = inrisk, eventDays = days,
         riskDays = sum(inrisk), controlDays = OBS - sum(inrisk),
         events = length(days),
         eventsInRisk = if (length(days)) sum(inrisk[days]) else 0L)
  })
}
rows <- simulate_people(4000)

# -- SCCS: optimise the conditional likelihood directly ------------------
# Only people with an event AND an exposure enter; the rest are a constant
use   <- Filter(function(r) r$events > 0 && r$exposed == 1, rows)
r_day <- sapply(use, `[[`, "riskDays")
c_day <- sapply(use, `[[`, "controlDays")
n_rsk <- sapply(use, `[[`, "eventsInRisk")
n_all <- sapply(use, `[[`, "events")

nll <- function(b) -sum(n_rsk * b - n_all * log(c_day + exp(b) * r_day))
o   <- optim(0, nll, method = "BFGS", hessian = TRUE)
se  <- sqrt(1 / o$hessian[1, 1])
exp(c(IRR = o$par, lcl = o$par - 1.96 * se, ucl = o$par + 1.96 * se))

# -- Case-crossover: one stratum per event, conditional logistic ---------
lags <- c(30, 60, 90)                     # three referent points, all pre-event
recs <- list()
for (k in seq_along(rows)) {
  r <- rows[[k]]
  for (ev in r$eventDays) {
    wins <- c(ev, ev - lags)
    if (any(wins < 1)) next
    recs[[length(recs) + 1]] <- data.frame(
      sid = paste0(k, "_", ev), case = c(1L, rep(0L, length(lags))),
      exposed = as.integer(r$inrisk[wins]))
  }
}
dd <- do.call(rbind, recs)
summary(clogit(case ~ exposed + strata(sid), data = dd))$conf.int

Verified with R 4.6.0 and survival 3.8.6 (the SCCS likelihood is optimised directly with base R's optim)

Five analyses, one true value

A forest plot of five estimates with 95% confidence intervals, against a dashed line at the true incidence rate ratio of 3. The between-person comparison sits clearly above the truth; SCCS and the case-crossover that uses every event both cover it; the first-event-only case-crossover and the SCCS with observation truncated at the event both sit above it.
Five analyses of the same simulated data. The dashed line is the true incidence rate ratio. The between-person comparison is inflated by confounding by indication; the two correctly executed within-person analyses cover the truth; the last two rows each break one assumption.Plotting script figures/scripts/B6-05-self-controlled.R
AnalysisEstimate95% CIAgainst the truth
True incidence rate ratio (the simulation’s setting)3.00
Exposed person-time vs everyone else’s person-time (between-person)4.574.05–5.17Inflated by confounding by indication
SCCS (within-person)3.012.66–3.41Covers the truth
Case-crossover, every event used2.832.35–3.41Covers the truth
Case-crossover, first event only4.623.24–6.60Overestimates in this simulation
SCCS, but the event ends observation3.873.05–4.91Third assumption broken

The first row is the point of the page: pool everyone’s exposed person-time, compare it with everyone’s unexposed person-time, and the estimate is 4.57 against a true value of 3.00. The bias is not an arithmetic error. It is that all 22596 exposed person-days came from the frailer part of the cohort — and a between-person comparison has no way to repair that, because frailty is not in the data.

SCCS, on the same data, gives 3.01 (2.66–3.41). It uses only the 1017 patients who had both an event and an exposure, 2555 events in total, of which 274 fell inside a risk window. No covariate was adjusted for, and no unexposed control group was used at all.

The three SCCS assumptions

What this design buys is substantial, so it is not cheap. Taking the assumptions one at a time:

Assumption one: events are independently recurrent, or rare enough

If one event changes the probability of later ones — after a first stroke, the probability of a second is permanently different — the derivation of the conditional likelihood no longer holds. The conventional response is to analyse only each person’s first event, and that is safe only when events are rare enough (an incidence below 10% over the study period). The simulation on this page uses an independent Poisson process, so every recurrence can be used.

Assumption two: the event must not change the probability of later exposure (event-independent exposure)

This is the one most often broken in pharmacoepidemiology. After a patient has an event, the clinician frequently stops prescribing the drug — so exposure in the period after the event is artificially suppressed, the referent window looks cleaner than it really is, and the IRR is overestimated.

The historical fix is to carve out a pre-exposure window before the exposure and drop it. Recent work shows that this repair is not dependable: how much bias remains depends not only on the length of the delay but on the length of the observation period and on where in that period exposure tends to occur. If you are worried about this assumption, the right response is a sensitivity analysis using an SCCS extension built for event-dependent exposure — not a pre-exposure window and a clear conscience.

Assumption three: the event must not change the length of the observation period (event-independent observation period)

SCCS is bidirectional precisely because observation does not end when an event occurs. When the outcome is death, that assumption fails outright — the patient dies and the rest of the observation period does not exist.

The last row of the simulation demonstrates it: change the data so that follow-up stops at the first event and leave everything else alone, and SCCS returns 3.87 (3.05–4.91), nearly thirty per cent above the true value of 3.00, with a confidence interval that does not cover the truth at all.

The core case-crossover assumption

CCO rests on a single sentence, but that sentence covers a lot of ground: under the null hypothesis that exposure has no effect, the probability of exposure in the referent window must represent the probability of exposure in the focal window.

Two consequences follow directly.

First, use of the exposure must not have a marked time trend. If prescriptions of this drug have been rising year on year, a patient is more likely to be on the drug “on the day of the event” than “thirty days earlier” — for reasons having nothing to do with the drug’s effects and everything to do with the calendar. The estimate is pushed up systematically. There are two responses: a bidirectional CCO, with referent windows on both sides of the event (which requires the extra assumption that the event does not change later exposure), or a case-time-control, which uses a group of people without events to estimate the odds ratio attributable to the time trend and divides it out.

Second, chronic medication produces an upward bias. Only people whose exposure status differs between windows carry any information in a CCO. If the drug is taken daily, the only people who can be “exposed on the day of the event, unexposed thirty days earlier” are those who had an event shortly after starting it. The reverse combination — unexposed at the event, exposed thirty days earlier — is almost nonexistent, because people who do not have events do not stop the drug. This is persistent user bias, a systematic problem for CCO with chronic medication; SCCS, being bidirectional, is much less affected.

The claim that only discordant people contribute can be counted directly in this simulation. The third row of the table above (every event used) has 3052 matched sets — one per event — of which only 445 (14.6%) are genuinely discordant between focal and referent windows and therefore enter the conditional likelihood. The fourth row (first event only) has 127 of 1168 (10.9%). In both rows, fewer than a sixth of the apparent matched sets are carrying the estimate — and a reader looking only at the table cannot see it. That is the entry in the misuse table below about not reporting how many people actually contributed information.

What this design does not eliminate

Self-controlled designs eliminate what does not change over time. So none of the following is touched:

  • Time-varying confounders — age, season (influenza, temperature), the natural course of the disease itself. The longer the observation period, the worse this gets. The standard remedy is to cut age and calendar time into intervals and include them in the conditional model.
  • Imprecise timing of exposure or outcome — focal and referent windows get drawn in the wrong place and events are assigned to the wrong period. This is why the design requires events whose date is unambiguous (acute events, precisely dated). Conditions with an insidious onset (endometriosis) and as-needed medication (an analgesic for migraine) do not fit.
  • Selection bias — if events inside the focal window are more likely to be recorded than events outside it (post-vaccination symptoms are reported more readily), the association is overestimated.
  • Absolute risk — this design cannot produce it. Converting to an attributable fraction or to cases per ten thousand people requires external denominator information, and requires great care.

When to reach for a self-controlled design

When all four of these hold, it is often the best available choice:

  1. The exposure is transient (or the exposure is permanent but its effect on the outcome is transient — vaccines work this way).
  2. The outcome is acute, with a clear date.
  3. Unmeasured, time-invariant confounding is the main threat — exactly the grey nodes on a DAG.
  4. No suitable comparison group exists, or the exposure spread through the whole population quickly (a vaccination campaign).

Conversely, when the exposure is chronic, the outcome’s onset is vague, or the dominant threat is time-varying confounding, a cohort study with weighting is the more practical route.

Why this page recommends no videos

Videos are listed on this site only after they have been verified. On this topic there is no teaching-level video in any language — nothing at all in Chinese, traditional or simplified, and in English only three recordings of seminars or lectures (view counts in the hundreds, thirty to sixty minutes long, mostly someone advancing slides).

Rather than pad the list, here is the situation as it stands. If you would rather hear it explained, the three closest are the Leicester RSS Hub’s Self-controlled case series methodology (32 minutes, methodological), Self controlled Design (60 minutes) given by Malcolm Maclure, who originated the case-crossover design, and OHDSI’s Vaccine safety evaluation using SCCS (58 minutes, applied). All three are pitched at people who already know the method, not at beginners.

The more efficient path is to read this page and then go straight to the CC BY review listed at the foot of it — it has a full glossary and an annotated bibliography.

Common misuses

MisuseWhy it is wrong
Using SCCS when the outcome is deathThe event ends the observation period; the third assumption fails outright
Using standard SCCS where clinicians stop the drug after an eventThe event changed later exposure, so the IRR is overestimated
Using CCO for a drug taken every dayPersistent user bias: only people who had an event soon after starting contribute
Using a one-directional CCO when prescribing has a clear time trendThe referent window no longer represents ordinary time, and the estimate is pushed up
Using a self-controlled design for a condition with vague onsetFocal and referent windows get drawn wrongly and events land in the wrong period
Observing for years without adjusting for age and seasonThis design eliminates only what does not change over time
Reporting “cases per ten thousand people” from a self-controlled analysisThe denominator was conditioned out; the design cannot estimate absolute risk
Not stating how many people actually contributed informationOnly those with both an event and an exposure enter the likelihood
Describing the IRR as a between-person risk ratioIt compares periods within one person, and answers “why now?”
Claiming a self-controlled analysis alone has removed all confoundingTime-varying confounding is untouched
Writing a non-significant result as “the drug does not cause this event”It means this analysis did not detect an increase in risk

Reproducing every number on this page

/opt/homebrew/bin/Rscript figures/scripts/B6-05-self-controlled.R

Read the figure

The answer comes from the same statistical output that produced this page's figures, not from a number typed in beside them.

In the same simulated data, pooling everyone's exposed person-time against everyone's unexposed person-time gives an incidence rate ratio of 4.57, while the simulated truth is 3. What is the excess?

Show the answer and why

Correct answer: The treated and untreated differ by 0.83 standard deviations on an unmeasured frailty, and the between-person comparison books that gap as drug effect

The denominator of the between-person comparison is the person-time of people who never took the drug, and those people carry lower baseline risk: treated and untreated differ by 0.83 standard deviations on a frailty nobody measured, and that entire gap lands on the drug. This is systematic bias, not sampling noise. Enlarge the sample and 4.57 is estimated more precisely, not closer to the truth. 1.00 is the standard deviation of the frailty itself, which is the raw material of the bias rather than its size. No between-person analysis can repair this, because frailty is not in the data at all - which is exactly why a self-controlled design moves the comparison inside one person.

The simulation has 4000 people and 4084 events in total. SCCS estimates 3.01. How much of that data does the estimate use?

Show the answer and why

Correct answer: Only the 2555 events belonging to the 1017 patients who have both an event and an exposure; everyone else contributes a constant

The conditional likelihood only feeds on people who have both an event and an exposure. People with no event, and people with no exposure, contribute a term with no parameter in it, which differentiates away. So of 4084 events, only 2555 come from those 1017 patients. The figure 274 is the subset of those 2555 that fall inside the risk window - the numerator side, not the whole dataset. Throw away the events outside the window and nothing is left to estimate the ordinary rate against, so there is no ratio to compute. This is also why an SCCS report must state how many people actually contributed: of 4000 people, 1017 carry the estimate.

The case-crossover row has 3052 matched sets, one per event. How many of them does the conditional logistic regression actually use?

Show the answer and why

Correct answer: Only 445 - the sets whose exposure status differs between the focal and referent windows; the rest are constants in the conditional likelihood

Conditional logistic regression compares only within a stratum, so a set whose exposure status is identical on the event day and at all three referent times contributes nothing to the likelihood. Of 3052 sets, only 445 are discordant - under a seventh. The figure 1168 is the number of sets in the first-events-only version, which answers a different question and has even fewer informative sets. None of this is visible in the estimate table: thousands of sets on the surface, a few hundred carrying the estimate, and the width of the interval is set by the latter. That is why a case-crossover report should state the number of informative sets.

Changing the case-crossover from every event to first events only, with nothing else altered, moves the estimate from 2.83 to 4.62. What does that jump say?

Show the answer and why

Correct answer: 2.83 is the more credible one: events selected for being first have referent windows that are systematically less likely to be exposed, so first-events-only pushes the estimate up

A first event is not a randomly drawn event. If somebody's referent time happens to fall inside a treatment episode, his event rate over that stretch is three times the usual, so he probably had his first event right there - and then that one is the first, and this one is never selected. The events that do get selected therefore have referent windows less likely than usual to be exposed, the denominator shrinks, and the estimate rises from 2.83 to 4.62. The value 2.89 is the single-referent version that still uses every event, and it sits almost on top of 2.83 - so the inflation comes from the sample restriction, not from the number of referent windows. The lesson is that whether the referent window represents ordinary time is the one thing this design has to protect, and any apparently harmless sample restriction can break it.

Change the data so that follow-up ends the moment an event occurs, with nothing else altered, and SCCS estimates 3.87 with a 95% CI of 3.05 to 4.91. What does that mean?

Show the answer and why

Correct answer: A lower limit of 3.05 already sits above the truth: the third assumption, that events must not affect the length of the observation period, has been broken and the whole estimate is inflated

SCCS is bidirectional precisely because the observation period does not end when an event happens. Once an event truncates follow-up, the referent time after that event disappears entirely, the referent window is systematically shortened, and the ratio is pushed up: 3.87 is close to a third above the truth, and the lower limit of 3.05 does not cover it at all. That is not conservative, it is biased. The value 3.41 is the upper limit of the full-data version, and the two intervals barely overlap, so the difference is bias rather than precision. In practice: do not reach for standard SCCS when the outcome is death or highly fatal. Use a case-crossover instead, or an SCCS extension built for event-dependent observation, or move the start of follow-up to the moment of first exposure.

There are 274 events inside the risk window. The between-person comparison turns them into 4.57 and SCCS turns the same events into 3.01. Why do identical events give different answers?

Show the answer and why

Correct answer: Because the between-person denominator is all 3810 events outside the risk window, including those of people who never took the drug at all, whose baseline risk is lower to begin with

The numerator is the same 274 events; the denominator is not. The between-person comparison sets them against all 3810 events outside the risk window, and most of those come from people who never took the drug. Their baseline risk is lower, the denominator is diluted, and the ratio rises. SCCS uses only the same person's own time outside the window as the denominator, so frailty cancels in the subtraction. The third option is half right: the conditional likelihood does use only the people who have both an event and an exposure, so some of the 1945 people with events never enter it. But headcount is not the mechanism behind this gap - the numerator is the same events either way - and the direction of the gap is predictable in advance, since confounding by indication pushes the between-person comparison upwards, whereas different samples giving different numbers says nothing about direction.

Sources and licences

Report a content problem

The statistics on this site are written by AI and reviewed by AI; a human only spot-checks. What you can see may be what we cannot.

The more specific, the more fixable — e.g. which sentence disagrees with which textbook or paper.

Needed only if you want a reply; reports without it are still read.

Sent along with your report

These are attached automatically. You can drop any of them.