Android's Attribution Reporting API: A Practical Primer

Here's the awkward part I have to lead with: the attribution reporting api android engineers spent 2024 and 2025 integrating is, as of October 2025, deprecated. Google announced on October 17, 2025 that it was retiring the remaining Privacy Sandbox APIs, this one included. So why write a primer on plumbing nobody has to lay anymore?

Because the design is the clearest public blueprint we have for privacy-preserving mobile attribution, and the ideas in it aren't going away just because this particular implementation did. I've shipped attribution SDKs into apps with tens of millions of installs, and I've watched the industry re-derive these same primitives three times now. If you understand how this API split conversions into two report types, you understand the shape of whatever comes next. Let's walk through what actually happened on the device.

What the Attribution Reporting API was, in one paragraph

The Attribution Reporting API let an ad tech register an ad click or view as an attribution source, register a later conversion as a trigger, and have Android match the two on-device before sending measurement off-device. Per Google's own documentation, it produced two flavors of output: event-level reports carrying low-fidelity conversion data, and aggregatable reports carrying higher-fidelity data. Nobody got a raw user-level join table. The device did the matching, added noise, and mailed you a redacted summary.

If you came from SKAdNetwork on iOS, that last sentence should feel familiar and also slightly better. More on that below.

The two registrations: source and trigger

Every attribution system, no matter how private, needs two moments recorded: the ad interaction and the conversion. This API named them plainly.

A source registration happens when someone clicks or views an ad. The ad tech calls registerSource() (or hands off a URI the platform fetches), and Android stores a source record on the device. That record carries source-side metadata the ad tech chose in advance, plus expiry windows and priority values.

A trigger registration happens later, when the user does the thing you care about, an install completing, a purchase, a level-up. The app calls registerTrigger(), and Android looks back through the stored sources on that device for a match.

Here's the step-by-step that matters, because it's where people's mental models break. The match is on-device and last-touch by default. Both the source and the trigger have to have been seen on the same physical device. There is no server-side identity graph doing the join. If the click landed on a phone and the install landed on a tablet, the API has nothing to connect. That's not a bug you can file. That's the privacy model working as designed.

One more thing the docs are quiet about: timing of delivery. Google's developer guide says reports go out on scheduled delivery times ranging from a couple of hours to several days. In testing you can fast-forward the device clock to force them out. In production you cannot, and I'll be honest, that reporting cadence gave me the same low-grade dread SKAN postbacks always have. They arrive whenever they feel like it, and you build your dashboards around that fact or you lie to yourself.

Event-level vs aggregatable reports

This is the split worth tattooing on the inside of your eyelids, because it's the whole design tension in one table. Two report types, two very different privacy-utility trade-offs, and you almost always wanted both.

Event-level report Aggregatable report
Fidelity of conversion data Low (a few bits of trigger data) Higher (histogram contributions)
Ties back to the specific ad click Yes, coarsely No, it's aggregated across sources
Typical use Optimization signals, model training Campaign totals, revenue, value buckets
Privacy protection Heavy noise, tiny data payload Aggregated + noised via a server
Delivery timing Delayed, scheduled Delayed, scheduled

Event-level reports gave you a small amount of high-trust-ish data about which source a conversion tied to, but almost nothing about the conversion itself. Think of it as "this click eventually converted, and here are three bits of context." Good for feeding an optimization model, useless for reporting exact purchase amounts.

Aggregatable reports flipped it. You lost the one-to-one link back to the individual click, but you could pack much richer values, purchase amounts, product categories, value tiers, into histogram buckets that got summed across many users in an aggregation service before you ever saw them. That's how you answered "how much revenue did this campaign drive" without ever learning what any single person bought.

The reason both existed is that no single report can be both granular per-user and privacy-safe. You pick your poison per question. Optimization questions took event-level. Reporting questions took aggregate. If a vendor ever told you one report type replaced the other, they were selling something.

Noise, and why your numbers never quite reconciled

Privacy here isn't a policy sticker, it's math baked into the output. The WICG explainer describes the system randomly sending noisy null reports for some fraction of trigger registrations, specifically so the true count of conversions is obscured and no single source can be pinned to an individual.

What that means on the ground: if you ran a small campaign and expected 40 conversions, the reported number could wobble. At tiny volumes the noise dominates and your data is basically unusable. At large volumes it washes out and the aggregate is trustworthy. The intuition is simple. Add a fixed amount of random jitter to every count, then run 50 conversions through it and the jitter is a rounding error you'd never notice. Run 5 conversions through the same jitter and it can double or halve your number. Same mechanism, wildly different reliability, and the only lever you control is how much real volume you push through a single source. This is the same lesson SKAN taught the hard way, low-volume campaigns are where privacy-preserving measurement goes to die. If you were planning a hundred micro-campaigns to A/B fifty creatives, this API was going to disappoint you, and it was designed to.

I want to flag an ambiguity the docs never fully resolved: the exact noise parameters shifted across preview releases, so any hard "expect X% variance" number you read from 2024 was probably stale by mid-2025. Testing on real volume was the only honest way to calibrate. Assume the same about anything you read today, including this.

Where it genuinely beat SKAdNetwork

I lived through the SKAdNetwork migrations and still have the scars, so I don't say this lightly: on paper, this API was the better instrument. A 2026 SolarEngine breakdown of SKAN lays out SKAN's ceilings plainly, data that's aggregated, delayed roughly 24 to 72 hours, capped at campaign-level granularity, with no web-to-app measurement at all.

The Android API cleared several of those bars. Per Google's docs it supported app-to-app, app-to-web, web-to-app, and web-to-web paths on a single device, with browsers able to delegate their source and trigger registration down to Android so a click in Chrome could attribute an app install. SKAN couldn't touch the web-to-app case. AdExchanger's coverage made the same point, this was not simply SKAdNetwork with a different logo.

Here's the short version of what advertisers gained and lost against SKAN parity:

  • Gained: cross app-and-web attribution, two report types instead of one crude postback, richer aggregate values, and a formal aggregation service instead of SKAN's opaque conversion-value cramming.
  • Lost: nothing you were still keeping under GAID-era device IDs, because the whole point was that those IDs were going away.
  • Kept the same pain: delayed reports, noise at low volume, and no user-level joins across devices.

So the instrument was better. The problem was never the instrument.

Why Google shelved it anyway

Adoption. That's the whole story, and it's worth sitting with. Google's own retirement post and the Search Engine Land report on the shutdown both point at the same cause, low levels of adoption and ecosystem feedback that the expected value didn't justify the integration cost. Anthony Chavez, who ran Privacy Sandbox, said as much publicly.

Read between those lines and you get the real lesson. A technically superior measurement API still failed, because privacy-preserving attribution asks every ad tech, MMP, and advertiser to rebuild their pipeline for less data than they had, on a timeline they didn't control, against an outcome (GAID deprecation) that Google kept softening. When the forcing function got weaker, the reason to do the painful integration evaporated. The engineering was sound. The incentives weren't there.

I don't think that means the design was wasted. The source/trigger split, the two-report model, on-device matching with a separate aggregation service, these are now the standard vocabulary for how you'd build private attribution. When the next mandate arrives, and on mobile there's always a next mandate, whoever builds it will start from roughly this shape.

What to actually do with this in 2026

If you're building or buying mobile measurement right now, the practical takeaways survive the deprecation:

Design your reporting to tolerate delay and noise as a permanent condition, not a temporary Sandbox quirk. The moment any platform reintroduces privacy-preserving attribution, you'll be back in couple-of-hours-to-several-days territory, and dashboards that assume real-time truth will keep lying to your growth team.

Keep the two-question discipline. Separate your optimization signals from your reporting numbers, and don't expect one data source to serve both well. That was true under SKAN, it was true here, it'll be true next time.

And stop treating any single OS API as your measurement strategy. Two platform-native attribution frameworks have now either capped hard (SKAN) or been retired outright (this one) inside three years. The teams that weathered both are the ones who understood the underlying model well enough to adapt, rather than the ones who memorized a specific integration guide.

If you want the deeper on-device sequence for how a modern SDK stitches clicks to conversions without leaning on a retired API, the privacy-first attribution reference architecture covers the pattern in full.

A few questions I still get asked

Is the Attribution Reporting API on Android dead for good? The implementation is retired as of the October 2025 announcement. Whether the design returns in another form is a different question, and I'd bet on yes eventually, because the underlying privacy pressures haven't gone anywhere.

Did GAID actually get deprecated? No. The original 2026-onward GAID phase-out that justified this whole migration was walked back along with the rest of Privacy Sandbox. The advertising ID is still there. That reprieve is exactly why adoption stalled.

Should I have integrated it? If you did the beta work, you learned the model, which is worth something. If you held off waiting for a stable spec, your instincts were right this time. Both camps should keep the mental model and drop the code.

What's the one thing to remember? Event-level for optimization, aggregatable for reporting, noise at low volume, delivery whenever the system feels like it. That sentence outlives the API.