1 Β· Why it matters: where A/B tests fail

Causal inference is a set of methods that estimate a cause-and-effect from data collected without randomisation.

A randomised test does one job: it makes groups comparable, so any difference can be pinned on the change. But in many situations randomisation is impossible, unethical, or already too late:

SituationWhy an A/B test won't work
A price changeYou can't legally or reputationally show random customers different prices
Feature already shipped to everyoneNo control group left β€” the test wasn't set up in advance
Offline / city-level launchUnits are cities or stores; there are few of them, random split doesn't work
An external shockRegulation, a competitor, a pandemic β€” life already ran the "experiment"
Marketplace / social networkGroups affect each other β€” randomising by user distorts the result

The gist: an A/B test answers "will it work if we launch." Causal inference answers "did the thing that already happened work" and "what happens if we roll it out to everyone." It's not a replacement for testing β€” it's the tool for when a test isn't available.

2 Β· The core idea: the counterfactual

The whole field rests on one question: what would have happened to these same users if the change had not occurred? That "parallel world" is the counterfactual, and you can never observe it directly β€” the same customer either got the feature or didn't.

So every causal method is really a different way to build a believable counterfactual: find a group or period that honestly shows "what would have happened anyway." A good analysis = a good counterfactual. A bad counterfactual = a beautiful but false number.

A check for any analysis: "What exactly am I comparing the result against β€” and is that really an honest answer to 'what would have happened otherwise?'" If there's no answer, don't trust the number.

3 Β· The main trap: correlation β‰  causation

Everyone knows the phrase, yet it catches people constantly. Three mechanisms that make an observed association lie:

Confounder

Something drives both the "treatment" and the outcome at once. A product-analytics classic: "users of feature X retain better β†’ the feature boosts retention." But feature X is chosen by the most engaged users β€” they'd have retained anyway. Engagement is the confounder, and it inflates the effect.

Selection bias

Groups differ from the start because of how they entered the analysis. Buyers of an extended warranty return items less often β€” not because the warranty protects them, but because more careful shoppers buy it.

Reverse causation

A doesn't cause B; it's the other way round. "Customers who contact support often churn more β†’ support drives churn." Actually, churning customers contact support more because they already have problems.

Practical takeaway: before building a complex model, ask β€” who ended up in each group, and why? Most false "insights" are born here, not in the maths.

4 Β· Five methods people actually use

For each: when it works, what it needs, and where it breaks. No formula derivations β€” what matters is when a method is honest and when it deceives.

Difference-in-Differences (DiD)

Idea: compare the change in the affected group with the change in a similar untouched group over the same period. The common trend cancels out.

When: a change hit one group/region, a similar untouched one exists, and before the change both moved in parallel.

Limit: rests on the "parallel trends" assumption β€” without the intervention the groups would have moved identically. Checked on pre-period history. If trends diverged, it lies.

Regression Discontinuity (RDD)

Idea: if "treatment" switches on at a sharp threshold (discount above 5,000; status above N points), customers just above and just below the cutoff are almost identical. The jump in the outcome at the boundary is the effect.

When: there's a clear threshold rule. Very convincing, close to an experiment.

Limit: measures the effect only for those near the threshold β€” it may differ for everyone else. Needs lots of data around the boundary.

Instrumental Variables (IV)

Idea: find an "instrument" β€” something that randomly nudges people toward treatment but doesn't affect the outcome directly. Through it, isolate the causal part.

When: there are hidden confounders and you can find a plausibly random nudge (e.g. an arbitrary delay in feature rollout).

Limit: a good instrument is hard to find, and its validity can't be fully proven β€” it's a matter of argument, not proof. The most fragile of the methods.

Propensity Score Matching (PSM)

Idea: for each "treated" user find a statistically similar "untreated" one and compare pairs, balancing observed differences.

When: lots of user data and confidence that the key differences are measured.

Limit β€” critical: it balances only what you observe. A hidden factor (motivation, intent) remains and spoils the result. Often creates a false sense of rigour.

Synthetic Control

Idea: when one large unit is affected (a city, a country), build a "synthetic copy" from a weighted blend of untouched units that reproduces its pre-period history. The gap afterwards is the effect.

When: one big treated unit, many donor candidates, a long history.

Limit: needs a long, stable pre-history; sensitive to external shocks that also hit the donors.

MethodKey conditionWhere it breaks
DiDParallel trends beforeTrends diverged
RDDA sharp thresholdEffect only near the boundary
IVA valid instrumentInstrument hard to justify
PSMKey factors measuredHidden factors remain
Synthetic ControlStable pre-historyExternal shocks on donors
5 Β· Difference-in-Differences: maths & code

The most used method in practice β€” and simple enough to show in full. Here's the idea as a formula, then runnable Python.

The 2Γ—2 formula

Four mean values of the metric β€” by group (treated / control) and period (before / after):

DiD = (Θ²T,after βˆ’ Θ²T,before) βˆ’ (Θ²C,after βˆ’ Θ²C,before) change in the affected group minus the background change (control)

The first bracket is how the affected group changed. The second is how the background would have changed even without the intervention (the control estimates it). Their difference is the clean effect.

The same estimate via regression

In practice DiD is run as a regression β€” it gives the standard error, p-value and confidence interval directly:

Y = Ξ²0 + Ξ²1Β·Treated + Ξ²2Β·After + Ξ²3Β·(Treated Γ— After) + Ξ΅ the interaction coefficient β₃ is the DiD effect

Here Treated = 1 for the affected group, After = 1 for the post period. The Treated Γ— After term only "switches on" in the bottom-right cell β€” so its coefficient β₃ captures exactly the extra change that can't be blamed on the common trend or on the initial gap between groups.

Key assumption (parallel trends): without the intervention, both groups would have moved the same way. Check it on pre-intervention history β€” if the curves ran parallel, the estimate is trustworthy.

Python: run it yourself

Self-contained β€” needs only numpy. Data is generated inside (a true effect of +2.5 pp) so you can run it as-is and watch the method recover it. Swap the generated arrays for your own.

What the result shows: the naive "after βˆ’ before" in treated would give +3.54 pp β€” inflated, because part of the rise is just the background (+1.41). DiD subtracts the background and gives an honest +2.13 pp, close to the true +2.5. Both methods agree to two decimals.

6 Β· Business cases
Difference-in-Differences
Launching a feature in one region

Situation: the product shipped a new onboarding only in Russia, keeping the old one in Kazakhstan. You want the effect on day-30 retention.

Naive approach: "retention rose 4 pp in RU β†’ onboarding works." The trap: retention may have risen everywhere due to seasonality.

Done right: take the change in RU (treated) and in KZ (control) over the same period. If RU is +4 pp and KZ +1.5 pp, the onboarding effect β‰ˆ 2.5 pp, not 4.

Check: look at 3–6 months before launch β€” did the retention curves run parallel? If yes, the estimate is trustworthy.

Lesson: "rose after launch" β‰  "launch raised it." Subtract the background.
Regression Discontinuity
The effect of a loyalty tier

Situation: "Silver" status is granted at 10,000 points and unlocks free delivery. Does the status itself affect purchase frequency?

Naive approach: compare "Silver" vs "no status." The trap: Silver members are simply active buyers β€” they already bought more.

Done right: compare customers with 9,800–9,999 points (just missed) and 10,000–10,200 (just got it). They're nearly identical; the behaviour gap is the status effect.

Lesson: a threshold in your product is a near-ready natural experiment. Look for your own: limits, ranks, cutoffs.
Synthetic Control
Impact of entering a new market

Situation: you opened a large offline store in one city. How did it affect the brand's total revenue in that city, accounting for online cannibalisation?

Problem: there's only one city, so there's no honest control group.

Done right: build a "synthetic city" from a weighted blend of similar cities without a store, matching the target's revenue history before opening. The gap after opening is the clean effect.

Lesson: even for a single city you can build a control β€” out of a combination of others.
Propensity Matching Β· with a caveat
Does premium support pay off?

Situation: customers on premium support renew more often. Should you offer it to everyone?

Naive approach: "renewal +15 pp β†’ roll out to all." The trap: premium is chosen by the most engaged β€” they'd renew anyway.

Done right (and its limit): match on the observed β€” company size, tenure, usage. Already fairer. But: "intent to stay" isn't measured, and it drives both buying support and renewing. So even careful PSM here probably overstates the effect.

Lesson: matching balances only the measured. If the decision is expensive, confirm it with a real experiment on a subset.
7 Β· Which method to choose
If you have…Look at
A change in one group + a similar untouched oneDifference-in-Differences
A clear threshold rule (points, amount, rank)Regression Discontinuity
One large unit (a city, a country)Synthetic Control
Many observed features, all key ones measuredPropensity Matching (carefully)
A plausibly random "nudge" toward treatmentInstrumental Variables
The ability to hold back part of the audienceAn A/B test after all β€” it's more honest

Default rule: if you can run a real experiment, run it. Causal inference is more expensive to justify and always leans on assumptions that can't be fully verified.

8 Β· Honest limitations β€” so you don't fool yourself

Causal inference is powerful, and that's exactly why it's dangerous: it returns a confident-looking number even when the assumptions don't hold. Keep in mind:

LimitationWhat to do
Every method leans on unverifiable assumptionsState the assumption explicitly and check what you can (pre-trends, group balance)
Hidden factors can't be balanced awayAsk: "what could enter both sides and stay unaccounted for?"
The effect may be local (only near the threshold / compliers)Don't extrapolate the estimate to the whole base automatically
Temptation to try methods until one looks "nice"Fix the method and assumptions before the analysis
The section's main point: an analyst's value isn't computing the effect β€” it's honestly saying how much to trust it. A good causal analysis always names its own weak spot.
← Back to the A/B Testing Calculator Home