iOS broke attribution, so I stopped attributing
For years, mobile UA ran on a comfortable assumption: when someone installs your game, you know which ad they came from. A device identifier tied the tap on a Meta ad to the install that followed, deterministically, per user. Whole optimization stacks were built on that link. Then Apple’s App Tracking Transparency arrived, most users declined to be tracked, the identifier went dark, and that link quietly became fiction on iOS — replaced by SKAdNetwork, which hands back delayed, aggregated, deliberately privacy-fuzzed install counts instead of clean per-user trails.
The first instinct — mine included — was to treat this as a signal-quality problem and patch it. Model the missing conversions, reconstruct the probable attribution, stitch SKAdNetwork postbacks back into something resembling the old per-user view. A lot of very smart engineering went into this across the industry, and it always felt like what it was: building an ever-more-elaborate prosthesis for a limb that wasn’t coming back. You were estimating the per-user link, then building your decisions on the estimate as if it were the measurement, compounding one layer of uncertainty on top of another.
What actually helped was to stop asking “how do I recover attribution” and start asking “what was attribution ever for.” It was for deciding where the budget goes. And the marketing mix model I’d already built for organic lift answered that question without ever needing a per-user link — because MMM never looked at individual users in the first place. It works at the aggregate level: total spend per channel per day, total installs per day, the relationship between the two over time. It was, almost by accident, already privacy-proof. The thing ATT broke was a thing MMM never depended on.
That changed the posture completely. Instead of a degraded attribution signal propped up by modeling, I had a method whose required inputs — aggregate spend, aggregate installs — Apple’s changes didn’t touch at all. The privacy wall that demolished per-user attribution is no obstacle to a model that only ever read the totals.
But it forced one real change, and it’s the part worth writing down. On iOS, installs per channel are now the unreliable, privacy-fuzzed quantity — that’s exactly what SKAdNetwork degraded. So on iOS I stopped feeding the model paid installs and fed it the one number Apple can’t obscure: spend. You always know what you spent. Your own billing is ground truth, immune to anyone’s privacy policy. Android, where attribution still largely works, keeps using installs as the input. The platforms diverge on purpose:
# the input variable depends on what each platform can still measure honestly
if platform == "ios":
media = paid_spend # SKAdNetwork fogged installs; billing is ground truth
else: # android
media = paid_installs # per-install attribution still reliable hereThat looks like a small config branch, but the rule behind it matters: feed the model the most reliable observable, and let that differ by platform. On iOS the trustworthy observable is what left your bank account; on Android it’s still the install count. Rather than force both platforms through one pipeline and pretend iOS installs are as solid as Android’s — quietly poisoning the model with a number you know is fogged — you let each platform contribute the signal it can actually stand behind. The model on iOS answers “how do organic installs respond to spend,” the Android model answers “how do organic installs respond to paid installs,” and both are honest about their own inputs instead of one of them laundering a broken number.
There’s a real cost here. Spend and installs aren’t interchangeable inputs — spend folds in price (CPI moves with auction dynamics and seasonality, so a spend-based model partly measures cost fluctuation, not just volume), and the two platforms’ results no longer sit on the same axis, which makes a clean cross-platform total something you assemble carefully rather than read off. I accepted that. A coherent measurement built on a number that’s actually true beats an apples-to-apples comparison built on a number I know is fiction on one side.
The wider point: when a measurement breaks, your best move is often not to repair the measurement but to find a decision-making method that never required it. Reconstructing the old per-user signal was the locally obvious move and a strategic dead end — pouring effort into restoring a capability the platform had deliberately removed and would keep removing. Switching to a method that operates on data the privacy changes don’t touch was the move that aged well, because it stopped fighting the direction the whole ecosystem was visibly heading. The future of measurement in a privacy-first world looks a lot more like aggregate modeling and a lot less like following individual users around, and ATT was just the early, loud announcement of it.1
From work on a marketing-analytics system for a mobile-gaming portfolio. Platform specifics, channels, and numbers are abstracted; the reasoning is as built. Code is illustrative.
Footnotes
This isn’t “attribution is dead, only model.” Deterministic attribution is still genuinely useful where it works (Android, web, logged-in surfaces), and incrementality tests remain the causal gold standard. The argument is narrower: don’t build your core budget decisions on a per-user signal the platform is actively dismantling. Use attribution where it’s honest, and make sure the decisions that really matter rest on something privacy changes can’t take away.↩︎