SKAdNetwork analytics works on aggregated, delayed postbacks, not on users. What you learn about an install is a conversion value from 0 to 63; every CV update resets a 24-hour timer, iOS then adds a random 0-24 hour delay, and the postback reaches the ad network and the MMP 24-48 hours later, sometimes longer, with no user_id. So the MMP decodes the values and joins them to spend, and the join with Firebase events happens in BigQuery, not inside Firebase.

When iOS 14.5 shipped with the App Tracking Transparency (ATT) prompt, the usual IDFA-based attribution broke. Today, Apple's SKAdNetwork (SKAN) is the only way left to estimate iOS ad effectiveness at all. We all had to forget about tracking individual users and learn to work with aggregated cohorts and delayed data. If your team learns to properly link SKAN, MMP, and Firebase data together, you stop pouring budget into a void and can actually optimize CAC.

Context: what we are dealing with

Before ATT, everything was simple: the user clicked an ad, the ad network sent the device ID (IDFA) to the MMP, and after install the MMP joined the click and the conversion with 100% accuracy.

The new SKAN reality looks different:

  1. Aggregated data: we no longer see individual users. Data arrives in bulk batches.
  2. Delayed postbacks: conversion notifications are intentionally delayed by 24-48 hours (sometimes longer), so we cannot identify a user by install time.
  3. Event limits: we now have Conversion Values. It is simply a number from 0 to 63. And you have a very narrow window to encode the most important information into that number.

The natural question is: how do you optimize ad campaigns quickly when results arrive only a couple of days later and in such a stripped-down form?

Deep dive: how this works under the hood

To work with SKAN properly you need to understand the full data path from click to dashboard. It involves the device (iOS), Apple itself, the ad network, and your MMP.

SKAN timers: why the postback arrives late

Conversion value, two timers and a 24-48 hour delay

  1. First launch

    starts a 24h timer

    • CV 0-63
  2. In-app actions

    CV only goes up

    an update resets the timer

    • reset 24h
  3. Random timer

    another 0-24 hours

    protection against identification

    • lag 24-48h
  4. Postback

    to the network and the MMP

    aggregated batch

    • no user_id

Every CV update resets the timer: more data, a later postback.

Judge a cohort on day 3-4 - daily optimization does not work on SKAN.

SKAN timers: first launch starts a 24h timer, each CV update resets it, a random 0-24h timer follows, then a postback with no user_id

The logic of timers and Conversion Values (CV)

At the core of SKAN is the Conversion Values (CV) system. As soon as a user opens the app for the first time, a 24-hour timer starts. Any meaningful action (a registration or a purchase) can update the CV, but only upward.

One important nuance: every successful CV update resets the 24-hour timer. We collect more behavioral data but push the postback even further into the future.

Once the user stops doing the actions you care about and the timer expires, iOS starts a second, randomized timer (0 to 24 hours). The postback goes to the ad network and the MMP only after that timer runs out. That random timer is why ad-account numbers always lag.

The integration path (SKAN + MMP + Firebase)

Without proper infrastructure, SKAN data will stay as opaque numbers between 0 and 63. Our job is to decode them, tie them to ad spend, and store them inside the core analytics (Firebase, GA4, or BigQuery).

The role of the MMP (AppsFlyer, Adjust, Branch)

The MMP acts as the central hub:

  • CV mapping configuration: inside the MMP dashboard you define the rules. For example, CV 1 = "Registration", CV 2 = "Purchase < $10".
  • Postback collection: networks deliver SKAN postbacks to the MMP, which decodes them by your rules.
  • Data joining: the MMP joins this data with its own attributions and the spend from the ad accounts.

Integration with Firebase and BigQuery

Because SKAN postbacks contain no user_id or app_instance_id, we cannot just bind them to user sessions in Firebase. The right architecture goes through a warehouse:

SKAN + MMP + Firebase through BigQuery

We do not push SKAN events into Firebase - we join the raw data in the warehouse

  1. SKAN postbacks

    networks send them to the MMP

    CV with no user_id

    • aggregates
  2. MMP

    AppsFlyer, Adjust

    CV mapped to events

    ad account spend

    • Data Locker
    • Pull API
  3. BigQuery

    raw data from the MMP

    Firebase events

    • one model
  4. Reports

    Blended ROAS

    pLTV by cohort

    • 3-7 day windows

A SKAN postback has no user_id - joining is only possible at the aggregate level.

Raw MMP and Firebase data are joined in BigQuery into Blended ROAS.

SKAN postbacks go to the MMP for CV mapping, then MMP raw data and Firebase events meet in BigQuery for Blended ROAS and cohort pLTV

Instead of trying to push SKAN events directly into Firebase, we export the raw data from the MMP (via Data Locker or the Pull API) and the raw events from Firebase into a single store - BigQuery. And then, inside BigQuery, we build aggregated reports such as Blended ROAS.¹ Blended ROAS is calculated as the ratio of all generated revenue to total ad spend.

Optimizing campaigns in real time is a bad idea. Because of SKAN delays, you can only assess a cohort honestly on day 3-4 after install. Give campaigns time.

What to do next

For marketers:

  • Evaluate campaigns in 3-7 day windows and forget about daily optimization.
  • Focus on LTV prediction (pLTV). Find the in-app actions during the first 24 hours that predict future purchases best and tie them to Conversion Values.
  • Watch Blended ROAS (total revenue / total spend) to see the full picture.

For analysts:

  • Set up a Raw Data export from the MMP to Google BigQuery.
  • Build a single data model that ties ad-account spend, SKAN postbacks, and Firebase events together.

For developers:

  • Make sure the MMP SDK initializes immediately on app start. Otherwise you lose the beginning of the install window.
  • Show the ATT (App Tracking Transparency) prompt at the right moment in onboarding so that users are more likely to grant tracking consent.

The trick is to step beyond the old attribution metrics and build a BigQuery-based stack that keeps working even under strict privacy rules.

Sources

  1. Firebase & BigQuery Integration Guide

FAQ

How do the SKAdNetwork timers work?

The postback is held behind a timer, and every successful conversion value update resets the 24-hour window. You collect richer behavioural data and push the postback further into the future at the same time.

Can I optimize iOS campaigns daily on SKAN data?

Not honestly. Because of the delays, a cohort can only be assessed properly on day 3-4 after install. Daily changes are reactions to the fastest-arriving part of the cohort, not to the cohort.

What does an MMP add on top of SKAN?

SKAN postbacks arrive aggregated, delayed and with no user_id. The MMP (AppsFlyer, Adjust or Branch) holds your conversion value mapping, collects the postbacks from the networks, decodes them by your rules and joins them with its own attributions and ad-account spend. Its raw data then goes into BigQuery next to Firebase events, instead of being pushed into Firebase directly.

How do you measure ROAS for iOS campaigns under SKAN?

At cohort level, in a warehouse. Export the MMP's raw data via Data Locker or the Pull API and Firebase's raw events into BigQuery, tie them to ad-account spend, and build Blended ROAS there as total revenue divided by total spend. Read it in 3-7 day windows, because a cohort can only be assessed honestly on day 3-4 after install.

Seeing this in your own funnel?

Two weeks, fixed scope, read-only access. You get the findings and a 90-day roadmap whether or not we work together afterwards.