Geo lift testing: how to design and read a GeoLift or matched market test

Turn the ads up in some regions, leave others alone, and compare. The arithmetic takes a minute; the design is where the test earns or loses its credibility.

Mike Taylor By Mike Taylor · Updated · 7 min read

A geo lift test measures the incremental effect of advertising by changing spend in some geographic regions and comparing them with regions where nothing changed, so the untouched regions tell you what would have happened without the campaign. GeoLift is Meta’s open-source R package for designing and analyzing these tests, and it’s become the default starting point for many marketers, although Google has published its own methods for the same problem going back to 2011. You’ll also hear the same idea called geo testing, geo experiments, a geo holdout or a matched market test, depending on how the regions were picked and who is selling it to you.

The reason geo tests matter so much now is that they don’t need to follow individual users. Having run a growth agency that spent over $10 million a year on Facebook ads, I’ve come to see platform-reported attribution as the platform marking its own homework, and user-level tracking has only got patchier since iOS privacy changes. A geo test sidesteps all of that: you only need to be able to target ads by region and to count the outcome (sales, sign-ups, store visits) by region. That makes it one of the few ways to test TV, radio, outdoor and other channels with no click to track, and one of the best ways to get ground truth for calibrating a marketing mix model. Most of what follows is about the design choices, because they decide whether anyone should believe the result.

How a geo lift test works

Every geo test has the same three ingredients: a set of regions (countries, states, Nielsen DMAs, postcodes, cities), a pre-period in which every region runs as normal, and a test period in which the treatment regions get a change (more spend, a new channel, or ads switched off entirely) while the comparison regions carry on as before. The effect of the campaign is the gap between what the treatment regions did and what they would have done without the campaign. That second number is never observed, so every method in this space is really a different way of estimating it, which is the counterfactual at the heart of all incrementality work.

The first big choice is how the regions get assigned. In a randomized geo experiment you have enough regions that you can let chance decide which are treated, which protects you against hidden differences you didn’t think to check. Jon Vaver and Jim Koehler at Google described this design in their 2011 paper, using the 210 US DMAs as an example set of geos, and they found that ranking regions by size and randomizing within size groups narrowed the confidence interval on return on ad spend by 10 percent or more. In a matched market test you have too few regions to randomize well (a UK brand testing in two TV regions, say), so you pick treatment and comparison markets that looked alike in the pre-period and rely on that similarity continuing. Matched markets are far more common in practice, and they’re also far easier to fool yourself with.

The second choice is how you build the counterfactual from the comparison regions, and there are three families you’ll meet:

MethodHow it builds “what would have happened”Where you’ll see it
Difference-in-differencesTreatment’s pre-period level plus the comparison group’s changeSpreadsheets, simple matched pairs, two-way fixed effects regression
Synthetic controlA weighted blend of untreated regions that tracks the treated region in the pre-periodGeoLift (augmented synthetic control), CausalImpact-style analyzes
Regression on the pre-periodTest-period outcome regressed on the pre-period outcome and the spend change, across geos (GBR) or over time (TBR)Google’s geo experiment papers and matched_markets library

Whichever estimator you use, the test period should run a little beyond the end of the spend change. Vaver and Koehler point out that offline sales in particular lag the advertising (people research, decide and then visit a store), so a test that stops counting the day the ads stop will miss some of the effect. That’s the same adstock carryover an MMM tries to estimate, showing up inside your experiment.

Pre-period4-5x the test length, no structural breaksTestspend changes in treatment onlyCool-downlagged salesLearn how regions move togetherTreatment vs counterfactualComparison regions: business as usual throughout (no new local campaigns, no national changes aimed at them)
The shape of a geo lift test: a long stable pre-period to learn how regions move together, a test window where only the treatment regions change, and a cool-down window that keeps counting delayed sales after spend returns to normal. Source: Vexpower.

Three answers from one geo test

The course’s invented geo dataset makes the core problem concrete. Twelve regions are split into six matched pairs; one region in each pair gets a campaign worth four (thousand) a week in extra spend for four weeks, and we know the true media effect is eight a week because the data was built that way. There’s a catch built in, which is exactly the kind of thing that happens in real tests: one treated region also ran a local promotion during the test window that nobody in marketing planned around.

Interactive
Three answers from one geo test

Twelve invented regions, six matched pairs, four weeks before and four after a campaign in the treatment regions. Exclude regions to see what moves, or load your own file with the same columns.

Treatment regions included (untick to exclude). The flagged region ran a local promotion during the test.
Before/after, treatment only
17.0
Difference-in-differences
9.0
Known media effect
8.0
iROAS (DiD ÷ spend)
2.25

Your file needs columns region, arm (treatment/comparison), period (pre/post) and revenue_k (or revenue). Optional: week, pair, media_spend_k, known_media_lift_k, promotion_lift_k.

Data: geo-experiment-synthetic.csv, Vexpower synthetic teaching data (deterministic, no sampling noise). Means are simple averages of region-weeks. iROAS is the estimated weekly lift per treated region divided by the extra weekly spend per treated region. Your own file stays in your browser.

The treatment-only before/after comparison says 17, because it credits the campaign with the common upward trend that lifted every region by eight between the periods. Difference-in-differences says 9, because subtracting the comparison group’s change removes that shared trend. However, the known media effect is 8, and the extra one comes from the promotion: a six-unit shock in one of six treated regions adds one to the treatment average. Removing a shared trend doesn’t remove a local shock, which is the whole lesson in one line. If you untick the promotion region, DiD lands on 8 and the implied iROAS drops from 2.25 to 2.00, which is the difference between a channel that looks comfortably profitable and one that might only just clear your breakeven ROAS.

In a real test you won’t have the answer-key columns, so the pair-level chart is the part I’d pay most attention to. Five pairs agree and one doesn’t, and an outlying pair is a prompt to go and ask the regional team what happened there, not something to quietly average away. Dropping a region after you’ve seen the results is also a judgment call you should write down and defend, because it’s exactly the move a motivated analyst would make to get the answer they wanted.

csv
Geo experiment dataset (CSV)96 rows: 12 regions × 8 weeks, with pair, arm, period, revenue, extra spend and the answer-key columns.
Download
py
Geo test analysis script (Python)Prints the three answers with and without the promotion region, DiD by pair, and the same estimate from a two-way fixed effects regression.
Download

Meta’s GeoLift R package

GeoLift is an R package from Meta’s Marketing Science team, created by Arturo Esquerra with Nicolas Cruces, and it covers the whole workflow: reading and checking geo-level data, choosing test markets with a power analysis, and estimating the lift after the test. As of October 2026 the repository is MIT licensed, still marked active, and its DESCRIPTION file lists version 2.7.5; it isn’t on CRAN, so you install it from GitHub, and the code itself has changed little recently (the last substantive change I could find was in January 2026, with most activity since then being dependency updates to the documentation site). That’s fine for a statistical tool that does one job, but it’s worth knowing before you build a production pipeline on it.

Under the hood GeoLift uses the augmented synthetic control method of Eli Ben-Michael, Avi Feller and Jesse Rothstein (2021), via their augsynth package. In plain terms, it builds a weighted blend of untreated markets that tracks the test markets in the pre-period, then corrects for whatever part of the pre-period it couldn’t fit using a ridge regression outcome model. I explain the idea step by step, with a widget that fits the weights live, on the synthetic control method page.

install.packages("remotes")
remotes::install_github("ebenmichael/augsynth")
remotes::install_github("facebookincubator/GeoLift")

library(GeoLift)
geo <- GeoDataRead(data = sales_by_city, date_id = "date",
                   location_id = "location", Y_id = "Y", format = "yyyy-mm-dd")

# Power analysis: which markets, how many, how long, at what budget?
markets <- GeoLiftMarketSelection(data = geo, treatment_periods = c(14, 21),
                                  N = c(2, 3, 4, 5), effect_size = seq(0, 0.25, 0.05),
                                  cpic = 7.5, budget = 100000)

# After the test: estimate the lift for the chosen test markets
result <- GeoLift(Y_id = "Y", data = geo, locations = c("city_a", "city_b"),
                  treatment_start_time = 91, treatment_end_time = 105)
summary(result)

The function names and arguments above follow GeoLift’s own walkthrough; the data frame and city names are placeholders. The market selection step is the most useful part of the package in my view, because it forces the conversation about power before anyone spends money. It simulates lifts across your history for different combinations of markets and test lengths, and it uses cpic (cost per incremental conversion) to estimate the budget each design needs to detect a given effect. If the answer is “you need to spend more than you have for longer than you’re willing to wait”, that’s valuable to know in week zero rather than week six.

GeoLift’s best practice notes are also more specific than most vendor guidance. They recommend daily data rather than weekly, the finest geography you can target, a pre-period four to five times the length of the test with no structural breaks, at least 25 pre-treatment periods and 20 or more geographic units, no missing values, and a test of at least 15 days on daily data (four to six weeks on weekly data) that covers a full purchase cycle. Meta’s own documentation also says plainly that people-based experiments like Conversion Lift have more statistical power where they’re feasible, which is a refreshingly honest thing for a geo tool to say about itself. I cover those user-level tests on the conversion lift studies page.

Google’s approaches to geo experiments

Google has published a steady line of research on geo experiments, and it’s worth knowing because most commercial tools borrow from it. Vaver and Koehler (2011) set out the randomized design and a geo-based regression (GBR): each geo’s test-period outcome is regressed on its pre-period outcome and on the change in ad spend, weighted to account for geos of very different sizes, and the coefficient on the spend change is the return on ad spend. Their design section also shows how to estimate the confidence interval in advance by replaying the analysis on historical “pseudo” test periods, which is the same idea GeoLift’s market selection uses.

GBR needs a reasonably large number of geos, so Jouni Kerman, Peng Wang and Jon Vaver (2017) proposed time-based regression (TBR) for tests with only a few regions, such as matched market tests. TBR works on the aggregated treatment and control time series instead, learning the relationship between them in the pre-period and projecting it forward. Google’s open-source matched_markets Python library implements TBR for analysis and a “TBR matched markets” search for design that picks treatment and control groups subject to budget and other constraints. For randomized paired designs, Aiyou Chen and Tim Au developed trimmed match (published in the Annals of Applied Statistics in 2022), which trims the worst-matched pairs so a few outliers can’t dominate the estimate, and Chen, Longfils and Remy (2021) extended it to the design stage; that’s implemented in the trimmed_match library. Both repositories describe themselves as research code rather than officially supported Google products, so treat them like you would any careful academic implementation.

How to design a geo test that people will believe

The arithmetic of a geo test is easier than the design, which is the line I lean on most in the course’s lesson on designing a geo test. The calculation is only useful if the comparison regions give a credible picture of how the treatment regions would have moved without the campaign, and regions looking similar before a test is helpful context, not a guarantee about what happens afterwards. These are the decisions that matter, roughly in the order you’ll make them.

Start from the decision and the effect size you care about

Write down the budget decision the test will inform and the smallest lift that would change it, before you look at any markets. If a lift below 3 percent wouldn’t change your plan, you don’t need a test that can detect 1 percent, and if your design can only detect 20 percent you should know that up front. The statistical power for marketing tests page has a geo calculator that turns region-level noise, the number of regions and the test length into a minimum detectable effect.

Choose markets on the outcome, not on demographics

Match or select markets on the metric you’re going to measure (sales, sign-ups) over a long pre-period, plus anything category-specific that drives it, because two cities with the same age profile can still have very different sales seasonality. Avoid your biggest market as a treatment region if you can (it’s hard to build a counterfactual for something with no peers), and avoid tiny regions where a single store opening swamps the signal. If you can randomize, randomize within size strata, as Vaver and Koehler recommend.

Set the test length, spend level and holdout share together

Test length, spend intensity and the share of the country in treatment trade off against each other. A bigger spend change in fewer regions produces a larger, easier-to-detect lift but tells you about a saturation point you might never run nationally; a smaller change spread more widely is more representative but harder to see. As a rule I’d rather run a heavier test for long enough to cover a purchase cycle plus a cool-down than a light one that ends inconclusively, because a null result needs a precision story and a vague one doesn’t have one. For a “go dark” holdout, keep the holdout share as small as power allows, since every holdout region is revenue you’re choosing to forgo.

Protect against spillover and local shocks

Spillover happens when the treatment leaks into comparison regions: people commuting across a DMA border, national TV or social campaigns that don’t respect your regions, delivery zones that cut across them, or a sales team that hears about the test and pushes harder in the “losing” regions. GeoLift has a vignette on using commuting zones for exactly this reason. Local shocks (a store refit, a competitor closing, a regional promotion like the one in the dataset above) are the other half of the problem, and the only real defense is a log of everything else happening in each region during the test, agreed with the people who run those regions.

Make sure the outcome data exists at the right grain

The outcome has to be countable by the same geography you target ads by, which sounds obvious until you discover that ecommerce orders are recorded by billing address, store sales by store, and the ad platform’s regions by IP address. Decide the mapping before the test, check there are no gaps for any region-day, and if store or retail sales arrive with a lag, schedule the analysis for when the data is complete rather than when the campaign ends. The MMM data requirements page covers the same plumbing from the modeling side.

Reading the result and feeding it into your MMM

When the test is done, report the estimated lift, its interval, the iROAS that implies, and the design caveats, in that order. A point estimate above your hurdle isn’t enough if the interval still includes values below it, and a “not significant” result from an underpowered test isn’t evidence that the channel doesn’t work. It’s also worth being precise about what you measured: a test of extra spend on top of a non-zero baseline tells you about the marginal return on that increment, not the average return on all spend, and a short test can miss later effects.

The most valuable thing to do with a good geo result is to use it as a prior or calibration target for your marketing mix model, so the model’s always-on estimates are anchored to something experimental. Record the treatment, comparison regions, dates, geography, spend change and outcome in a test log, because a library of past tests is worth much more than any single one. The full process from question to design is in the incrementality testing guide, and if you want to compare commercial options, the incrementality testing tools page covers vendors that run geo tests for you. The Vexpower MMM course has a lesson on exactly this design problem, using the invented Northstar brand, where the interactive starts with a competitor closure in the campaign region so you can see what a comparison can and can’t remove.

Downloads

csv
Geo experiment dataset (CSV)12 invented regions, six matched pairs, four weeks pre and four post, with answer-key columns for the media effect and a local promotion.
Download
py
Geo test analysis script (Python)Reproduces the before/after, difference-in-differences and known-effect answers, the pair-level check and a fixed-effects regression. pandas and numpy only.
Download

Frequently asked questions

What is GeoLift?

GeoLift is an open-source R package from Meta's Marketing Science team for designing and analyzing geo experiments. It picks test markets with a power analysis, builds a synthetic control from the untreated markets using the augmented synthetic control method, and reports the lift with confidence intervals. It is MIT licensed and installed from GitHub rather than CRAN.

What is a matched market test?

A matched market test changes advertising in a small number of regions and compares them with regions chosen because their sales looked similar before the test. It is used when there are too few regions to randomize well. The comparison is only as good as the match, so the pre-period fit and a plausible story for why the regions would have kept moving together both matter.

How long should a geo test run?

Long enough to cover at least one purchase cycle and to reach the precision you planned for, plus a cool-down window for delayed effects. GeoLift's documentation suggests a minimum of about 15 days with daily data or four to six weeks with weekly data, with a pre-period several times longer than the test.

How many regions do I need for a geo test?

More is better, because the noise between regions sets the smallest lift you can detect. GeoLift's guidance is at least 20 geographic units with 25 or more pre-treatment periods. With only a handful of regions you are running a matched market test, and you should expect wide intervals unless the effect is large.

Is a geo test better than a conversion lift study?

Not always. A user-level lift study on a platform usually has more statistical power, and Meta itself recommends people-based tests where they are feasible. Geo tests earn their place when user-level randomization is impossible, when the outcome is offline sales, or when the channel is TV, radio, outdoor or another medium with no user-level holdout.

References

  1. GeoLift (facebookincubator/GeoLift on GitHub) MIT licence, R 4.0+, version 2.7.5 in the DESCRIPTION file; install via augsynth and GitHub. Last code change January 2026.
  2. GeoLift documentation: walkthrough and best practices Daily data, 4-5x pre-period, 20+ geos, 25+ pre periods, 15 days / 4-6 weeks minimum test length.
  3. Vaver & Koehler (2011), Measuring Ad Effectiveness Using Geo Experiments Randomised geo experiments, the geo-based regression model, stratifying by size, test period extended for delayed effects.
  4. Kerman, Wang & Vaver (2017), Estimating Ad Effectiveness using Geo Experiments in a Time-Based Regression Framework TBR for tests with few geos, such as matched market tests.
  5. Chen & Au (2022), Robust causal inference for incremental return on ad spend with randomized paired geo experiments Trimmed match; Annals of Applied Statistics.
  6. Chen, Longfils & Remy (2021), Trimmed Match Design for Randomized Paired Geo Experiments
  7. google/matched_markets and google/trimmed_match on GitHub Python libraries for TBR and TBR matched markets design, and for trimmed match; both described as research code, not officially supported Google products.
  8. Ben-Michael, Feller & Rothstein (2021), The Augmented Synthetic Control Method Journal of the American Statistical Association; the method behind GeoLift's estimator.
Mike Taylor
Mike Taylor

I've built marketing mix models for Monzo Bank, Booking.com, Time Out, The AA and others, advised Google, Appsflyer and Recast on MMM, and teach marketing mix modeling on LinkedIn Learning. Before that I co-founded a 50-person growth marketing agency. I write the Vexpower MMM course.

Keep reading

Learn MMM by doing itThe Vexpower course walks through thirty lessons on one invented brand, with simulators, Python labs and a decision case you can defend.
See the course