Why Your MMP and the Stores Never Agree on Installs

The three consoles never agree because each one counts a different event at a different layer of the stack. Apple's App Store Connect counts first-time downloads per Apple Account. Google Play counts users who don't currently own the app. Your MMP timestamps the first SDK launch inside the app. None of them are wrong. Most app install discrepancies aren't bugs — they're the system working as designed, three tools answering three separate questions.

I've spent enough late nights diffing these numbers to tell you the reconciliation you're chasing often doesn't exist. So let's follow the plumbing instead of the spreadsheet.

Four moments, three clocks

Slow the on-device sequence down. A user taps Get or Install, the OS pulls the binary, the app lands on the home screen, the user taps the icon, the process spins up, and only then does your SDK's init code run. Three distinct moments live inside that flow: the download completing, the first open, and the SDK's first-launch callback firing. Each console picks a different one to call "the install."

The stores anchor near the front. Apple's App Units register the download against the Apple Account. Google's counting is messier, though its device-level install still fires close to download time. Your MMP sits at the very back of the line. It can see nothing until your code executes, which only happens when a human actually opens the app.

Per AppsFlyer's own attribution model documentation, "the timestamp of an app install is the first launch," while ad networks use engagement time and app stores use download time. One human action, three different clocks. A download at 11:58pm that gets opened at 12:04am is a Tuesday install in App Store Connect and a Wednesday install in your MMP. Nobody made a mistake. The calendars just disagree.

A definition table worth pinning up

Here's the disambiguation I wish someone had handed me on day one. Read each cell as "what this console counts for this event."

Event App Store Connect (App Units) Google Play MMP (AppsFlyer / Adjust)
First download Counted, once per Apple Account Counted at device level Counted only after first open fires the SDK
App update Not counted Not counted as new install Not counted
First open Not the trigger (download is) Not the trigger This is the trigger — no open, no install
Redownload / reinstall (same user) Not counted Suppressed at user level Suppressed inside the re-attribution window
Family Sharing Included for free apps, excluded for paid apps N/A Counts if it produces a first open

The Family Sharing detail comes straight from Apple's developer forums, where the guidance reads: "App updates, downloads from the same Apple ID onto other devices, and redownloads to the same device are not counted. Family Sharing downloads are included for free apps, but not for paid apps." Adjust's attribution overview is equally blunt on the open requirement: "if a user downloads an app and never opens it, Adjust will not count an install."

When someone in a standup asks why the numbers are off by a few percent, half the time the answer is already sitting in a cell above.

Apple disagrees with itself first

Before an MMP ever enters the conversation, Apple hands you two install-ish numbers that don't match. App Units are unconstrained first-time downloads per Apple Account. The separate Installations metric is opt-in device-level analytics, reported only for users who agreed to share their data with you.

Apple states this directly in its App Store Connect analytics reference: "Usage data is based on users who have opted in to share their analytics with you." A developer-forum answer puts the mismatch even plainer: "Installations metrics depend on the number of users who agreed to share data with you, whereas the first time downloads has no such constraints." Installations will therefore sit structurally below App Units, and the size of that gap measures your opt-in rate, not your install volume. Two Apple dashboards, one Apple, no agreement.

Play's back-dating and the "users, not installs" trap

Google splits its counting across user, device, and event levels, and your MMP lines up closest to the device level. The confusion usually starts with the acquisition reports, which measure something subtly different. Per Google's Play Console help, those reports track "how well your store listing acquires users, rather than installs," calculated on "users who do not currently have your app installed on any of their devices."

Then there's back-dating. Play attributes late activity back to the original date, so, as Google documents here, "your install statistics can be higher on your app's Acquisition reports page compared to its Statistics page for the same date range." Diff acquisition against your MMP and you're comparing a back-dated user count to a forward-stamped device event. They drift. Both are behaving correctly.

Where redownload noise and missing inits hide

The re-attribution window breeds most of the "phantom" discrepancies I get pinged about. A user deletes your app and reinstalls; the store may log a fresh download, but your MMP deliberately withholds a new organic install if the reinstall falls inside that window.

AppsFlyer's re-attribution window docs set the default at 90 days: "During the re-attribution window app reinstalls aren't recorded as new installs" unless a retargeting campaign is involved. Adjust takes a shorter stance — seven days of inactivity plus a seven-day reattribution window by default. The exact same reinstall gets swallowed for three months on one MMP and re-counted after two weeks on another.

Now for the honest caveat. The docs give you the default window, not the full suppression logic. What actually gets re-counted versus swallowed depends on organic-versus-paid source, whether a retargeting link was involved, and how the device identifier resolved on that reinstall. Don't treat the doc number as gospel. Instrument a test device, delete and reinstall on your own schedule, and watch which events land.

The quieter leak is downloads that never become opens. Each one inflates the store count relative to your MMP, and there's no postback to chase because the SDK never ran.

Reading the bands: definitional versus broken

No published benchmark tells you what "normal" looks like, so what follows is my engineering judgment, labeled as opinion. It's derived from the counting differences above, not measured across a fleet of apps. Treat these as bands to reason with, not numbers to quote back at me in six months.

On Android, where Play's device-level install and your MMP's first-launch install sit one on-device step apart, I'd expect a definitional delta in the low single digits, roughly 2–6%, driven mostly by downloads that never open and reinstall suppression. On iOS, the split between App Units (per Apple Account, download-timed) and MMP installs (per device, open-timed) runs wider, so 8–15% can be entirely definitional before anything breaks.

Push those bands higher the second SKAdNetwork enters the picture. Aggregation, crowd-anonymity thresholds that withhold data for low-volume campaigns, randomized postback delays — all of it widens the plausible gap on paid iOS traffic. A low-volume campaign can show a large percentage gap that's permanent by design, not a fault.

Postback timing earns its own eye-roll. SKAdNetwork postbacks arrive after a randomized delay measured in days, not seconds. When your Monday numbers don't reconcile on Monday, the honest answer is often that the postbacks are still in transit. Anything outside these bands, after the windows close, is worth escalating. Inside them, breathe.

Triage: which gap is which

Run any discrepancy through four questions, in order.

  1. Has the data-completeness window closed? If postbacks and back-dated activity are still landing, wait. It's lag, not loss.
  2. Is the console far above the MMP? Suspect missing SDK inits or downloads that were never opened.
  3. Is the MMP above the console, or are reinstalls spiking? That's redownload noise inside the re-attribution window.
  4. Does the gap persist after every window closes? Now escalate to your MMP.

Walk a small dataset with me for one campaign week: 10,000 App Units in App Store Connect for the iOS build, 9,200 device-level installs in Play's equivalent view for Android, and 8,600 installs in the MMP.

The App Units-to-MMP gap is 14%, right at the top of my iOS band. Question one: the SKAN window hasn't fully closed, so some of that gap is postbacks in flight. Question two: a slice is downloads that never opened. Nothing here screams bug, and it reconciles as normal.

Flip it, though. If the MMP reported 11,500 installs against 10,000 App Units after every window closed, that's the MMP claiming more installs than Apple recorded downloads. Not definitional. That's re-attribution double-counting or fraud, and it goes to your MMP with the raw-log request attached. Our install-fraud reading guide covers what to ask for.

Building the reconciliation view

Teams that stay sane stop chasing the decimal. They build one view that aligns on a single event definition and a single completeness window before comparing anything. Pick your anchor event — usually SDK first-open, since that's the layer you fully control — and hold every source to the same cutoff.

You can assemble this from BI warehouse exports, a shared spreadsheet, or a product-analytics platform that captures first-open at the SDK layer such as Kixo. Whichever you choose, the discipline outweighs the tool: same event, same window, then diff. If you're still deciding whether to run this off raw SKAN plus a warehouse or a full MMP, our MMP-versus-warehouse breakdown lays out the tradeoffs.

What you genuinely cannot reconcile anymore

Some gaps are gone for good. SKAdNetwork aggregation collapses user-level detail into campaign-level counts. Crowd-anonymity thresholds withhold or coarsen data for low-volume campaigns. And the randomized postback timing means a given install's report may never arrive in the window you're staring at. For a small paid iOS campaign, you might simply never get a number precise enough to line up against a store console. If that reality is new to you, the Apple Search Ads three-dashboard piece walks the same problem from the ad side.

So set the expectation with your stakeholders now: reconcile to the band, not to the decimal. Match your definitions, wait for the windows to close, and accept that a chunk of iOS variance is structural. As for the postbacks, they'll show up eventually, on their own schedule, long after you've stopped waiting.