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

ConceptRobynMeridianThis 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.