A web dashboard built in Dash for Bayesian Media Mix Modeling (MMM). It fits a Bayesian MMM on one sample territory (from the Google Meridian simulated dataset), then explores channel effects, budget trade-offs and optimisation in a clean UI with interactive elements.
![]() |
![]() |
| Overview dashboard | Budget optimiser view |
The app uses PyMC-Marketing to estimate a multidimensional MMM with geometric adstock and logistic saturation on paid media spend, plus controls & seasonality. Inference is NUTS (isn't it always?) and posteriors are summarised with ArviZ.
Data: On first run it downloads Google Meridian’s simulated geo_all_channels.csv and caches it under data/. This is synthetic multi-geo weekly data; the app automatically selects the largest territory by revenue (Geo36 in the bundled file) and models that one territory only.
Caching: Fitted inference data is written to data/mmm_idata.nc (& a fingerprint file) so later launches reload the posterior instead of resampling unless you refit or invalidate the cache, to save on (re)loading time.
| Route | Purpose |
|---|---|
| Overview | In-sample KPIs, recent-window diagnostics, revenue vs. baseline/media decomp over time |
| Contributions | Channel contribution to revenue (posterior uncertainty) |
| Response curves | Marginal response / saturation curves by channel |
| Optimiser | Steady-state budget scenarios with optional channel min/max constraints |
The header Options panel lets you adjust sampler settings like draws, tuning steps and target accept (with more to be added in the future) and trigger a refit. Successful runs persist settings to data/mmm_sampler_config.json.
- Adding more user options to adjust MMM/sampler settings
- UI: Dash 4.x, Dash Mantine Components, Plotly figures
- Model:
pymc-marketing, PyMC, optional nutpie + JAX for sampling throughput - Python: 3.10+ recommended (match your
pymc-marketingwheel availability) - Package manager: uv (used for dependency management)
uv sync
uv run python app.pyOpen http://127.0.0.1:8050. The first model fit can take around a minute or two while NUTS runs. Subsequent starts should be faster.
PyMC/PyTensor may need a working C++ toolchain or fall back to pure NumPy modes. The project sets a local PyTensor compile dir and, on Apple systems, can disable the C++ compiler unless PYTENSOR_CXX points to a working compiler. If sampling fails, check PyMC/PyTensor docs for your OS version. I'll likely add a fix in the future if it doesn't get fixed.
This repository is a demo built on simulated data. Don't treat its outputs as business decisions without validating on your own data, priors and governance!

