Migration Guide
Coming from Robyn, Google Meridian, or PyMC-Marketing? Your modeling instincts transfer — adstock, saturation, controls, and ROI all have direct homes here. This guide maps the concepts you know to this framework's config and API, and is honest about what differs.
The one mindset shift
In grid-search tools, a model's hyperparameters (adstock decay, saturation shape, coefficients) are numbers you search over and then fix. Here they are random variables with priors, and fitting returns their full posterior. So "what adstock decay did we pick?" becomes "what does the decay posterior look like?" — you get an interval, not a point, and that interval flows into every downstream ROI and reallocation. Two more differences worth knowing up front: the framework asks you to pre-register the model design before seeing results (limiting researcher degrees of freedom), and it treats experiment calibration as a first-class step, not an afterthought.
Concept map
| Concept | Robyn | Meridian | This framework |
|---|---|---|---|
| Carryover | geometric / Weibull adstock, theta/shape ranges |
geometric adstock, alpha prior |
AdstockConfig (geometric, delayed, Weibull); decay is a fitted RV |
| Saturation | Hill (alpha, gamma ranges) |
Hill saturation, priors on slope/half | SaturationConfig (Hill, logistic, …); shape params are fitted RVs |
| Effect size | ridge coefficient (regularized point) | coefficient / ROI prior (Bayesian) | coefficient or ROI-scale prior; media_prior_mode="roi" |
| Inference | Nevergrad search + ridge, Pareto front of models | NUTS (TF-Probability) | NUTS (NumPyro/PyMC); one model, full posterior |
| Uncertainty | spread across Pareto solutions | posterior credible intervals | posterior credible intervals throughout |
| Experiment calibration | calibration_input (lift studies) |
ROI priors from experiments | in-graph likelihood on lift/ROAS estimands; a full loop |
| Geo hierarchy | one model per geo, or national | hierarchical geo model | partial-pooled per-geo betas (vary_media_by_geo) |
| Controls / confounders | context variables | control variables | role-tagged controls with a causal DAG and refutation checks |
From Robyn
Robyn searches hyperparameter ranges and returns a Pareto front of candidate models.
The translation is mechanical: a range becomes a prior, and the Pareto spread
becomes a single model's posterior. Your theta adstock ranges map
to an AdstockConfig; your Hill alpha/gamma ranges map to
a SaturationConfig; your calibration_input lift studies map to the
framework's experiment calibration — with the added
honesty that you commit to the design before seeing which model "looks best."
from mmm_framework import (
MFFConfigBuilder, ModelConfigBuilder, TrendConfig, TrendType,
)
# Robyn theta/Hill ranges -> per-channel adstock windows + Bayesian inference
mff_config = (
MFFConfigBuilder()
.with_kpi_name("Sales")
.add_national_media("TV", adstock_lmax=8) # longer carryover, like a high-theta TV
.add_national_media("Search", adstock_lmax=2) # short carryover
.weekly()
.build()
)
model_config = ModelConfigBuilder().bayesian_numpyro().build()
trend_config = TrendConfig(type=TrendType.LINEAR)
Instead of hand-picking from a Pareto front, you fit once and read the posterior — and where Robyn asks for a business "budget allocation" objective, here that lives in the reallocation simulator on top of the fitted curves.
From Meridian
Meridian is already Bayesian, so the concepts line up closely — adstock, Hill saturation, geo hierarchy, and priors on ROI all have direct equivalents. If you set ROI priors in Meridian, use this framework's ROI-scale media priors so the prior lives on the decision quantity rather than an abstract coefficient:
# illustrative — ROI-scale priors and per-geo hierarchy in the model spec
spec = {
"kpi": "Sales",
"media_channels": [{"name": "TV"}, {"name": "Search"}, {"name": "Social"}],
"media_prior_mode": "roi", # priors on ROI, not raw coefficients
"priors": {"media": {"TV": {"roi": {"median": 2.0, "sigma": 0.5}}}},
"vary_media_by_geo": True, # partial-pooled per-geo effectiveness
}
Honest gap: if your Meridian model leans on reach & frequency inputs, note that first-class frequency-saturation modeling is on the roadmap rather than shipped — model those channels on impressions or spend for now, and calibrate with a frequency experiment. Geo hierarchy, ROI priors, and adstock/saturation all transfer directly.
From PyMC-Marketing
This is the smoothest migration, because both are PyMC 6 under the hood. A common
misconception: this framework does not subclass PyMC-Marketing — it is a
separate, standalone engine that can optionally interoperate with a PyMC-Marketing
model for reporting. PyMC-Marketing's MMM maps to BayesianMMM; its
adstock and saturation transformations map to AdstockConfig /
SaturationConfig; its model coordinates map to the MFF's declared dimensions.
What you gain by moving up is the layer around the model: declared causal roles and
refutation checks, the pre-registration and calibration loop, experiment design and
prioritization, and the report/agent surface. The
Model Garden is the place to bring a bespoke model class along.
Fastest way to compare
Fit the bundled example (load_example("national")) here and against your
current tool on the same data. The quickstart
even grades the result against a sealed answer key — a like-for-like recovery test you can
run in minutes.