*! version 1.0.0 05aug2026

Title

causalimpact interpretation -- How to read the tables, the report
and the figure

Reading the header

Everything above the first double rule tells you what was fitted, not what was
found. Read it first: most bad causal-impact analyses are visible here rather
than in the numbers.

Response the treated series.

Covariates the control series that build the synthetic control.
Truncated with "..." if long; the full list is in e(covariates). If this
says (none), the counterfactual is a pure extrapolation of the response's
own history and will be far less trustworthy.

State model which components are in the state: local level, and
optionally a seasonal block and a regression block.

Regression static spike-and-slab, dynamic, or
none.

Standardised whether columns were centred and scaled on pre-period
moments. Affects the metric of the coefficients, not the reported effects.

Pre-period / Post-period the training and evaluation windows, in
the units of the tsset time variable.

Obs (pre) the single most important number in the header. This is
how much data the model had to learn the relationship. Twenty pre-period points
cannot support a confident counterfactual over sixty post-period points.

MCMC draws / Burn-in / Retained the sampler's bookkeeping.
Retained = draws - burn-in. With niter(1000) you retain 900.

Note the asymmetry between Obs (pre) and Obs (post). Section 3 of the
paper shows estimation accuracy decaying steadily as the forecast horizon grows.
A post-period much longer than the pre-period is a warning sign, not a bonus.

Average versus Cumulative -- pick one before you look

The two columns answer different questions and only one is usually right for
your data.

Average is the mean over the post-period, time point by time point. "On a
typical day during the campaign, how much higher was the response?" This is
always interpretable.

Cumulative is the sum over the post-period. "How many extra units in total
did the intervention produce?" This is interpretable only for flow
quantities -- clicks, sales, sign-ups, visits, revenue -- things that accumulate.

For a stock quantity -- number of current subscribers, a price, a stock
level, a temperature, an unemployment rate -- summing across time is
meaningless. Adding today's subscriber count to yesterday's does not produce a
quantity that exists. In that case:

o Report the Average column and ignore the Cumulative one.

o Drop the third panel with metrics(original pointwise).

o If you want a cumulative-style summary, use the running average of
eq. (2.17), available as stub_avg_effect from generate(). It
stays interpretable for stocks and flows alike.

This distinction is from Sec. 2.4 of the paper and it is the single most common
misuse of the method in applied work.

Reading the main table

Four blocks, each with a point estimate, a posterior standard deviation, and a
credible interval.

Actual -- what was observed in the post-period. No uncertainty: it is data.

Prediction -- the counterfactual. What the model says would have happened
without the intervention. Its interval reflects genuine uncertainty about an
unobservable quantity, which is why it is usually wider than people expect.

Absolute effect -- Actual minus Prediction, in the units of the response.
This is the headline number.

Relative effect -- the same thing as a percentage of the counterfactual.

Three things about these numbers routinely confuse people.

1. The effect interval is not the difference of the two intervals above it.
It is computed from the posterior draws of the difference, which is
narrower than differencing the endpoints would suggest, because the observed
value carries no uncertainty. Do not try to reconcile them by hand.

2. The point prediction is not the midpoint of its own interval. The point
estimate is the mean of the noise-free state; the interval comes from quantiles
of draws that include observation noise. The gap is deliberate and matches the R
package.

3. Relative effect Average and Cumulative are identical by construction.
Both report the posterior of sum(y)/sum(counterfactual) - 1. This is not a bug
and not a display quirk; the R package does the same. There is only one relative
effect.

Also note that the relative effect is generally not the absolute effect
divided by the prediction. Posterior distributions of ratios are not symmetric,
so E[y/c] does not equal E[y]/E[c]. When the gap exceeds five percentage points
the verbal report says so explicitly.

The two probabilities, and why they can disagree

The table closes with

Posterior tail-area probability p the one-sided Bayesian tail-area
probability of the cumulative effect

Posterior probability of an effect 1 - p

p is computed by counting how many posterior draws of the counterfactual sum
are at least as extreme as the observed sum, taking the smaller tail, and
dividing by the number of draws plus one. It is a one-sided statement.

Checking whether the credible interval excludes zero is a two-sided test.
So in borderline cases the star next to p and the interval can disagree. That is
expected, not an inconsistency. The significance stars in this table follow p;
the single star * marks the case where the interval excludes zero but p is
above 0.05.

One hard limit worth knowing: p can never be smaller than 1/(retained draws + 1).
With niter(1000) the floor is 1/901 = 0.00111. If you see exactly that
value, it means "as small as this sampler can report", not "0.00111 precisely".
Raise niter() if you need finer resolution in the tail.

The inclusion table

When controls are present, a second table reports the spike-and-slab posterior
for each of them.

P(incl) posterior probability that the covariate is in the model.
Above ~0.5 the model is relying on it; near 0 it has been discarded.

Post. mean model-averaged posterior mean of the coefficient. Draws
that exclude the covariate contribute exactly zero, so a covariate with
P(incl) = 0.02 will have a mean shrunk almost to zero regardless of how large
its coefficient is when it does enter.

Post. s.d. model-averaged posterior standard deviation, on the same
mixed scale.

P(b>0) probability the coefficient is positive given that it is
in the model. Conditional, not marginal. For a covariate that is almost never
included this is computed from a handful of draws and is close to noise --
values like 0.000, 0.500 or 1.000 on a covariate with P(incl) = 0.003 mean
nothing.

Read P(incl) first and only then look at the other three columns. A coefficient
summary is meaningful only for covariates the model actually uses.

Two structural points. First, coefficients are in the metric the model is fitted
in -- standardised unless nostandardize was used -- exactly as in the R
package, which likewise never converts them back. Second, _cons is
redundant with the local level and should not be read as a structural intercept.

A special case that surprises people: with few candidate controls, the prior
inclusion probability is min(1, modelsize()/J). With one covariate plus an
intercept and the default modelsize(3), that is min(1, 3/2) = 1, so
everything is forced into the model and every P(incl) prints as 1.000.
That is the prior speaking, not evidence. Variable selection only does visible
work when you have more candidates than modelsize().

Reading the figure

Panel A, original. Observed series in solid black, counterfactual as a
dashed dark blue line, credible band shaded. Look at the pre-period first.
The counterfactual should track the observed series closely there -- that stretch
is the model's audition. If it fits badly before the intervention, nothing after
it is trustworthy. In Figure 5 of the paper the fit is good enough to reproduce
a spike two weeks before the campaign.

Panel B, pointwise. The gap between observation and counterfactual, period
by period, with its band. This is where you see the shape of the effect:
when it started, whether it peaked, whether it decayed. A band that includes zero
at a given time point means no detectable effect at that point, even if the
overall effect is significant.

Panel C, cumulative. The running total of panel B. It should be a flat zero
line through the whole pre-period -- that is guaranteed by construction, and if it
is not, something is wrong. A steadily rising line with a band clear of zero is
a sustained effect. A line that flattens means the effect has worn off; the band
crossing back over zero means the cumulative effect is no longer significant,
which is exactly what Figure 1(c) of the paper illustrates.

The dashed vertical lines mark the end of the pre-period and the end of the
post-period. The band widens as you move right in every panel. That is not a
defect -- predicting further into the counterfactual future is genuinely more
uncertain, and a model whose band did not widen would be lying to you.

The verbal report

causalimpact, report prints a written interpretation, a faithful port of
summary(impact, "report") in R. It is meant as a starting draft for a
results section, not as a finished paragraph.

It has a fixed structure:

Paragraph 1 -- the average effect, with the counterfactual and its interval.

Paragraph 2 -- the cumulative effect, prefaced by the standing caveat that
sums "can only sometimes be meaningfully interpreted" (see
Average versus Cumulative).

Paragraph 3 -- the relative effect as a percentage.

Paragraph 4, printed only when needed -- a warning that the expected relative
effect is not the expected absolute effect over the expected prediction.

Paragraph 5 -- the significance verdict. The wording branches four ways on
(significant or not) x (positive or negative). When significant and positive it
adds the warning that statistical significance is not substantive significance,
and asks you to compare the effect against the goal of the intervention. When
not significant it lists the usual reasons: post-period too long, too short, or
controls too weak.

Paragraph 6 -- the tail-area probability, and whether the effect can be
called causal if the model assumptions are satisfied. That conditional is
load-bearing.

The prose also switches on significance in a subtle way that is easy to miss:
"By contrast, in the absence of an intervention..." when the effect is
significant, versus a plain "In the absence of an intervention..." when it
is not. Numbers in the report are abbreviated (3.51K, 1.2M) using the same
rounding rules as R, so they will look coarser than the table. Use
digits() to change the rounding, and e(summary) when you need full
precision.

A worked reading

From the R-vignette design, where the truth is a lift of exactly 10 units per
period over 30 periods:

Actual 117 3511
Prediction 106.5 3196
95% CI [ 105.8, 107.2] [ 3175, 3216]
Absolute effect 10.51 315.4
95% CI [ 9.834, 11.23] [ 295, 336.9]
Relative effect (%) 9.872 9.872
95% CI [ 9.173, 10.612] [ 9.173, 10.612]
Posterior tail-area probability p 0.00111 ***

Read it as: on a typical post-period day the response was about 117, whereas
without the intervention we would have expected about 106.5. The daily effect is
therefore about 10.5 units, and we are 95% sure it lies between 9.8 and 11.2.
Over the whole 30-period window that accumulates to about 315 extra units, with
a 95% interval of [295, 337]. In relative terms the response is about 9.9%
higher than it would have been, interval [9.2%, 10.6%]. The probability of
seeing this by chance is at the resolution floor of the sampler, so the effect is
clearly significant.

Now the honest part. The truth is 10 per period and 300 cumulative; the estimate
is 10.5 and 315, about 5% high, and the 95% interval for the cumulative effect
does not contain 300. That is not a failure of the command -- R returns
essentially the same answer on the same data. It happens because the single
covariate is an AR(0.999), effectively a unit root, so the counterfactual level
is genuinely uncertain and the model has drifted slightly. It is a good
illustration of the real lesson: the interval covers the model's uncertainty,
not the model's wrongness. Weak or near-integrated controls shift the whole
counterfactual, and no credible interval will warn you about that.

Ten ways to misread this output

1. Reading the Cumulative column for a stock quantity. Summing subscribers
across days produces a number, not a quantity.

2. Treating a wide band as a defect. It is the model reporting honest
uncertainty about an unobservable.

3. Assuming a significant overall effect means every period was affected.
Check panel B; individual periods may straddle zero.

4. Assuming a non-significant overall effect means nothing happened. A short
burst can be swamped by a long quiet post-period.

5. Reading a coefficient whose P(incl) is near zero. It has been shrunk to
almost nothing by model averaging.

6. Reading P(b>0) for a rarely-included covariate. It is computed from a
handful of draws.

7. Reading _cons as a structural intercept. It is confounded with the
local level.

8. Reporting p = 0.00111 as a precise number. It is the sampler's floor at
niter(1000).

9. Extending the post-period to "get more data". It dilutes a decaying
effect and widens the band; it does not strengthen the finding.

10. Calling the result causal without checking that the controls were
themselves untouched by the intervention. That assumption does all the work, and
no diagnostic in this output tests it.

Checklist before you believe a result

n Were the controls plausibly unaffected by the intervention? Argue it
explicitly; no statistic here can check it.

n Does the counterfactual track the observed series over the pre-period in
panel A?

n Does a placebo run on a date where nothing happened correctly return
nothing? This is the most informative single check you can run:

. causalimpact y x1, pre(1 40) post(41 70) report

n Is the response a flow, if you are quoting the cumulative effect?

n Is the post-period short enough that the relationship is still plausibly
stable?

n Do the inclusion probabilities pick out controls that make substantive
sense?

n Is the result stable across seeds, and across priorlevelsd(0.01)
versus priorlevelsd(0.1)? If the conclusion flips with the prior, report
that.

n Did you state the priors and the assumptions when writing it up?

Author

Dr Merwan Roudane

merwanroudane920@gmail.com

https://github.com/merwanroudane

Also see

Help: causalimpact,
causalimpact methods,
causalimpact rcheck,
causalimpact postestimation