Skip to main content

Oracle // MMM demo

This is Oracle's MMM run on a synthetic DTC fashion panel.

Every number you see carries a credible interval. Oracle has never had a zero-variance claim pass review.

Run manifest

DTC fashion demo panel // 52 weeks // 5 channels

Ship gates passed
Date range
2025-01-01 → 2025-12-24
Maturity tier
enterprise
Data quality
0.92
Posterior source
Synthetic (seeded)
R-hat
1.002
ESS-tail
650
Divergences
0
Holdout MAPE
8.9%
Lift calibration
2 tests

Deterministic synthetic posteriors used. The Windows PyTensor toolchain on the build host does not have a C++ compiler available, so the real PyMC-Marketing NUTS fit was skipped. The synthetic path is schema-identical and seeded (random_seed=42) for reproducibility.

Channel contribution

Posterior share of KPI by channel. Each bar carries a ninety-per-cent credible interval in the table below.

Revenue Contribution Waterfall

Baseline + channel contributions = total revenue

Source: Acera Labs Bayesian MMM

ChannelShare mean80 pct CIAdstockHill alphaHill gamma
Email (Klaviyo)25.9%18.1% 33.7%geometric0.72$126
Paid social (Meta)21.1%14.8% 27.5%geometric0.46$3,013
Programmatic display19.8%13.9% 25.8%geometric0.24$1,786
Organic search19.0%13.3% 24.7%geometric0.38$1
Paid search14.1%9.9% 18.3%geometric0.44$1,043

Response curves

Hill saturation curves with the current weekly spend marked. Where a marker sits past the half-saturation line, further spend buys less.

Paid search

78% saturated

Paid social (Meta)

50% saturated

Email (Klaviyo)

50% saturated

Programmatic display

50% saturated

Organic search

50% saturated

Budget scenario

What if we shift ten per cent from one channel to another? Oracle traces the response curves and reports the uplift with a credible interval.

Shift 10 percent of organic_search weekly spend into paid_search. Weekly shift: $0.

Current weekly spend
Organic search$0
Paid search$12,502
Proposed weekly spend
Organic search$0
Paid search$12,502
Estimated uplift (normalised response units)
+0.0000
80 pct CI: 0.00000.0000

Uplift is in normalised Hill-response units. Multiply by the channel's beta coefficient to convert to AUD.

Send this run to your CFO

run_id: 36d925a3-9f97-49e9-b07d-9d09b76d9ef1

How this was done

Expand

Paid search, organic correction

Branded search captures demand that was already heading to the site. Before the Bayesian fit, Oracle regresses organic search traffic in as a control column (Kraft et al. paid-search correction), so the posterior for paid_search reflects incremental effect rather than demand that would have converted organically.

Adstock per channel type

Digital channels use geometric adstock with a Beta(2, 5) decay prior. Owned channels (email, organic) use geometric adstock with a shorter Beta(2, 10) decay. Offline channels use a Weibull PDF kernel so lagged-peak responses (TV brand response peaking two to three weeks after a flight) are captured instead of smeared across the same week.

Hill saturation

Each channel is transformed through a two-parameter Hill curve: Hill(x) = x^alpha / (x^alpha + gamma^alpha). Alpha controls the S-curve onset. Gamma is the half-saturation point: the spend level at which response equals half of maximum. Priors are Beta(3, 3) on alpha and a half-normal on gamma scaled to the channel's median spend.

Lift calibration

Where incrementality tests are available, Oracle adds them as likelihood terms (add_lift_test_measurements in PyMC-Marketing) so the posterior is pulled toward the measured lift. This run uses Binet and Field industry priors as a stand-in for geo-lift tests on paid_search and paid_social_meta. Any deviation larger than two standard errors flags a calibration conflict and blocks downstream optimiser output.

Holdout validation

The last eight weeks of the panel are withheld from the fit. After sampling, Oracle runs posterior-predictive checks against the holdout and reports MAPE, fifty-per-cent coverage, and ninety-per-cent coverage. Ship gates require R-hat below 1.01, tail ESS above 400, zero divergences, and holdout MAPE below fifteen per cent. A run that misses any gate is not shipped.

Posterior source

This demo uses deterministic synthetic posteriors (random_seed=42) because the Windows build host for the fixture does not have a C++ compiler available for PyTensor. The synthetic path is schema-identical to a real NUTS fit and is only ever used for seeded demos, not production runs.