MMP Migration Playbook: Switching Providers Without a Gap

Here's the short version, the one you can hand your PM before sprint planning: an MMP migration is a time-bounded dual-SDK overlap. You run both attribution SDKs in parallel for roughly two weeks, reconcile the numbers, then cut over. Click and install attribution overlap cleanly during that window. But there's no true SKAdNetwork overlap, because SKAN postbacks route to exactly one MMP even with both SDKs live. Which means your SKAN data gap starts on the app's release day and can't be backfilled. So plan the release date first, and let everything else hang off it.

What "no data gap" actually means (and the one gap you can't close)

Let me be honest about the phrase "no data gap," because vendors use it loosely and it burns teams who take it literally.

Click and install attribution overlaps fine. Both SDKs sit in the same binary. Both fire their own install and event calls to their own endpoints, and both attribute against their own click data. During the overlap you get two parallel truths, and reconciling them is arithmetic. More on that below.

SKAN is a different animal. Here's the on-device picture. When a conversion value gets updated, the OS holds a timer, and after that timer expires it posts a single encrypted payload. The registration of which endpoint receives that payload is per-app, resolved through the ad network's own routing. Only one MMP's postback URL is in play. As Singular's help center puts it, "SKAN postbacks can only be sent to one MMP. Even if both SDKs are integrated, only one MMP receives SKAN conversions." No fan-out. The device picks one door.

And it picks it whenever it feels like it. The postback arrives on a randomized delay, anywhere from a few hours to well past two days after the conversion window closes. You'll reconfigure everything correctly on Tuesday and watch the confirming postbacks straggle in Thursday afternoon, unbothered by your deadline. Get used to this rhythm. It does not care about your migration plan.

MMP migration is the act of swapping your attribution SDK and vendor while preserving historical continuity and existing-user identity, bounded by a dual-SDK overlap window during which both SDKs collect data in parallel before you cut traffic over to the new one.

Before you touch code: the export nobody does first

Historical data does not move between MMPs. Full stop. An MMP only knows about events that fired after its integration went live, and postbacks are forward-looking, never retroactive. SplitMetrics states it plainly: "Historical data does not transfer – MMPs only send postbacks for events after an integration goes live, so the export is your only archive."

So the very first thing you do, before any code lands, is pull a raw export from the old MMP. Not a dashboard screenshot. Raw event and install rows, carrying device identifiers, timestamps, campaign metadata, and event names. That file is the only surviving record of everything the old system attributed, and once you sunset the old SDK it's gone for good, so treat it like the archive it is and store it somewhere your data team can actually query later rather than a folder on someone's laptop that gets wiped at the next hardware refresh.

Here's the diagram-in-words for why the new MMP starts blind. Picture the new SDK waking up on release day with an empty memory. It has no idea a user installed six months ago, no clue which campaign drove them, no record of their last purchase. Every user who existed before go-live is, from the new MMP's perspective, a stranger. The export preserves the past. The device-ID import, coming next, is how you stop the new system from mistaking your whole existing base for a flood of fresh installs.

The device-ID import that stops you double-counting your own users

This is the step teams skip and then spend a week explaining to finance.

Before you release, you import a list of historical device IDs into the new MMP. Kochava's migration writeup describes exactly why: "Before you go live, you'll import a list of historical device IDs so existing users aren't counted as new install conversions." Branch is blunter about the failure mode: "If you install the Branch SDK without completing this step first, all existing users will appear as new installs in your data."

Think about what that does to your numbers. Say you have two million existing users. Ship without the import, and on update day the new MMP logs a large chunk of them as organic installs. Your install count spikes, your "organic" bucket balloons, and any pipeline downstream that reacts to install volume gets poisoned.

Now the doc-ambiguity flag, because this bit isn't spelled out anywhere clean. The vendor docs tell you to import device IDs, but they're vague on the matching-window behavior for re-identified users, meaning how long after import a returning device is correctly recognized versus treated as new. The docs don't say precisely, and testing shows it varies by MMP and by how quickly the OS surfaces the identifier after the update lands. Run a small internal cohort through it before you trust the behavior at scale. If your consent posture affects which identifiers you can even collect, our mobile consent management guide covers what you're allowed to import in the first place.

Phase-by-phase runbook

This is the spine. Paste it into a ticket, assign owners, and keep the on-device note next to each phase so nobody forgets what actually fires.

Phase 0, export historical raw data. Pull the full raw export from the old MMP before anything else. On-device: nothing changes yet; you're archiving what the old system already recorded, because it won't survive the switch.

Phase 1, import historical device IDs. Load existing device IDs into the new MMP before the new SDK ships. On-device: still nothing changes on the phone. You're pre-loading the new backend so returning users don't register as new installs.

Phase 2, match config. Replicate attribution windows, reinstall policy, and event names on the new MMP so they line up with the old one. On-device: the new SDK will fire events under these names, and mismatched names mean your funnels silently diverge.

Phase 3, dual-SDK overlap, minimum ~2 weeks. Ship the build with both SDKs live. Branch recommends you "keep your existing MMP SDK active for a minimum of 2 weeks post-release to ensure continuous data collection from users who haven't yet updated." On-device: both SDKs fire independently. Expect double-counted events during this window (that's the point of Phase 7).

Phase 4, switch tracking links network-by-network, lowest-spend first. Move click URLs one network at a time, starting where the least money is. On-device: the click that opens the app now resolves through the new MMP's link, and the old one stops attributing that network. Lowest-spend-first limits the blast radius if routing breaks.

Phase 5, self-attributing networks, manual disconnect/reconnect per network. Detach each SAN from the old MMP and reconnect to the new one. On-device: nothing, because SAN data flows server-to-server via API, not through a click URL (see the dedicated section).

Phase 6, SKAN cutover on release date plus CV schema re-registration. The SKAN endpoint follows the new app version; re-register conversion-value schemas per network. On-device: the OS now routes the single SKAN postback to the new MMP. This is the unrecoverable boundary.

Phase 7, reconcile and sunset the old SDK. Compare overlap counts, de-dupe, then remove the old SDK in a later release. On-device: once removed, the old SDK stops firing entirely.

If your Android setup leans on install referrer, don't lose it in the shuffle. The Google Play install referrer is one signal that survives most of this intact and is worth reconfirming after cutover.

SKAN re-registration and the 72-hour trap

Conversion-value schemas are configured per network, not once globally, and this is where migrations stall at the worst possible moment.

Some ad networks lock schema edits when a campaign has run recently. Moloco's docs state the rule directly: "You can only edit the registered Conversion Value if there is no Campaign activated under that app within the past 72 hours." So if you try to re-register your schema while a campaign is live or was live yesterday, the edit gets refused, and you're stuck with whatever mapping was there before.

The fix is sequencing. Pause the campaign on the affected network, wait out the 72-hour clock, register the new schema, then resume. Do this per network, because the lock is per network. Slot the pause windows into the same calendar you're using for release-date planning so they don't collide with a spend peak.

Then, predictably, you finish the reconfiguration, confirm the schema is live in the dashboard, and the postback that proves it actually works shows up two days later, arriving on its own schedule as postbacks do. Your logic can be perfect and you'll still be refreshing the events view Thursday, waiting on Tuesday's conversions.

Self-attributing networks don't come along for the ride

A link swap does nothing for Meta, Google, Apple Search Ads, or TikTok, and this trips up teams who assume Phase 4 covers everything.

SAN data doesn't flow through a click URL you can repoint. It flows through an authenticated API integration between the network and your MMP, where the network posts attribution back server-side, keyed to an account connection you authorized. Airbridge spells out the consequence: "SAN integrations don't auto-switch. Meta, Google, Apple Search Ads, and TikTok each require manual disconnection from your old MMP and reconnection to Airbridge."

Practically, that means logging into each network's business account, revoking the old MMP's connection, and authorizing the new one. Four separate manual dances, each with its own auth flow and its own approval lag. Miss one and that network's spend quietly keeps reporting into the old MMP, or worse, into neither. Put each SAN reconnection on the checklist as its own line item with its own owner. If you're also running holdout tests, note that inflated install counts wreck incrementality reads too, so it's worth reviewing incrementality testing for mobile UA before you trust lift numbers during the window.

A worked reconciliation example

Here's the part that earns its keep. During the overlap window you'll have two dashboards both claiming to be right, and neither is until you reconcile them. Let me walk a tiny concrete case.

Say on a given day the old MMP reports 1,000 installs and the new MMP also reports 1,000 installs. Comforting symmetry, except it's a trap. Because both SDKs are live, some devices fire events into both systems. Suppose 180 of those devices are the same physical phones double-firing, meaning they exist in both the old export and the new import, matched on device ID.

The naive read is 2,000 installs across your stack. The real number is 1,820 unique devices: 1,000 plus 1,000 minus the 180 overlap. Feed the un-deduped 2,000 into a cost-per-install calculation and your CPI looks 10 percent cheaper than reality, and every conversion rate built on that inflated base looks better than it is. Spend the same money, "get" more installs, congratulate yourself on a fictional efficiency gain. That's how a clean migration produces dirty numbers.

The de-dupe uses the device IDs you imported in Phase 1. Match the new MMP's install roster against the imported historical IDs and the current overlap set, subtract the intersection, and you get the true unique count. Do the same for revenue events, because double-counted purchases inflate ROAS the same way double-counted installs inflate CPI.

My rule, earned the hard way: reconcile-then-trust. Don't believe either dashboard until the overlap counts converge within a tolerance you set in advance. I use plus-or-minus a few percent for a normal-volume app. If they don't converge, something's misconfigured, usually a mismatched attribution window from Phase 2 or a partial device-ID import, and you fix that before you cut over. Trusting a dashboard during overlap is how teams cut over onto bad math.

Choosing the destination MMP

There's no single right answer. The honest rubric is the same for everyone: SDK platform coverage, deep-link and deferred-deep-link support, SKAN conversion-value handling, and how mature the migration documentation actually is. That last column matters more than teams expect, because a vendor with a clear migration guide has already thought through the traps in this article.

On that front, Branch and Airbridge publish the clearest migration paths I've read. Branch's two-week dual-SDK guidance and Airbridge's release-date warning both came straight from their own docs, and that specificity is a good sign. AppsFlyer and Adjust are the incumbents most teams migrate from or to, with broad platform coverage and long-standing SAN integrations.

Kixo belongs on the list as one option worth a look, with an honest caveat. It's an AI-native product and marketing analytics platform carrying iOS, Android and web SDKs, and it does mobile attribution plus deferred deep links via kixo.cc short links. Its distinguishing angle is chat-first analytics, where you ask questions in plain language and get AI-generated charts with a visible reasoning trail, rather than building every dashboard by hand. What I can't do is point you at a published migration-guide track record the way I can with Branch and Airbridge, so treat that as an open question and pilot the overlap window before you commit real spend.

Vendor SDK platforms Deferred deep linking SKAN CV support Documented migration path Notable angle
AppsFlyer iOS, Android, web Yes Yes Yes Broad incumbent, wide SAN coverage
Adjust iOS, Android, web Yes Yes Yes Incumbent, strong fraud tooling
Branch iOS, Android, web Yes Yes Yes, 2-week dual-SDK guide Deep-linking heritage, clear migration docs
Kixo iOS, Android, web Yes (kixo.cc) Yes Unknown, no public track record to cite Chat-first AI analytics plus attribution

Release-date planning owns everything

Because the SKAN gap starts on release day and cannot be recovered, the release date is a business decision, not an engineering convenience. Airbridge says it as plainly as it can be said: "The SKAN data gap starts on your app release date and cannot be recovered retroactively. Plan your release date with this in mind."

So don't land your cutover in the middle of a peak campaign. If Q4 is your biggest UA push, migrating the week before means the SKAN blind spot lands exactly when you most need clean iOS numbers to steer spend. Pick a trough. Vendor-stated timelines run roughly 7 to 10 business days end to end, so work backward from a quiet week and give yourself slack for the SAN reconnections and the 72-hour schema pauses, which don't parallelize as neatly as you'd hope.

And then it happens: everything's cut over, the old SDK is scheduled for removal, both dashboards finally agree within tolerance, finance stops emailing you. Clean migration. Except you're still waiting on three stray postbacks from the old MMP that will wander in sometime next week, on their own time, as they always do.

Copy-paste migration checklist

  • Export raw event and install data from the old MMP first, since it's your only archive of history (SplitMetrics).
  • Import historical device IDs before releasing the new SDK, or existing users log as fresh installs (Kochava, Branch).
  • Match attribution windows, reinstall policy, and event names on the new MMP (Phase 2).
  • Ship with both SDKs live and run the overlap a minimum of two weeks (Branch).
  • Switch tracking links network-by-network, lowest-spend first, to cap double-counting damage.
  • Manually disconnect and reconnect each SAN across Meta, Google, Apple Search Ads and TikTok, API side, not via link swap (Airbridge).
  • Re-register SKAN conversion-value schemas per network, pausing campaigns to clear the 72-hour edit lock (Moloco).
  • Reconcile overlap counts with imported device IDs before trusting either dashboard, then de-dupe installs and revenue.
  • Set the release date around business peaks, because the SKAN gap starts on release day and can't be backfilled (Airbridge).
  • Sunset the old SDK only after reconciliation converges.

Before you ship the build, run the iOS privacy manifest checklist against both SDKs. A migration is the easiest time to introduce a required-reason API violation that gets you a rejection on the exact release date you spent a month planning.