ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-06-19Advanced

I Started the Ad SDK Before Asking for ATT — the Init-Order Bug That Quietly Lowered First-Session eCPM

When I rolled AdMob mediation out to four iOS apps, only the very first session showed weaker ad revenue. The cause was the order between the ATT prompt and MobileAds initialization. Here is why the order matters, plus how I had Antigravity audit the init sequence across all four apps.

antigravity375ios29admob13att2monetization28

Premium Article

Right after rolling mediation out to four iOS apps, I noticed an odd step in the Firebase dashboard. Daily eCPM was steady, yet the first impression of each session had a noticeably lower fill rate. No crashes, ads were showing — but the first slot or two right after a fresh install were filled with clearly lower-priced demand.

It took a few days to trace. The short version: I was initializing the ad SDK before the ATT (App Tracking Transparency) prompt had resolved. The code compiled, no warnings — which is exactly why this class of bug is easy to miss.

This is a record of the ordering pitfall I actually hit across the wallpaper and healing apps I run as an indie developer, why it matters, and how I had Antigravity audit the initialization sequence alongside the fix.

The tell: revenue dips on the first session only

In a mediation setup, each ad network reads device signals to bid. On iOS the signal that matters most is the IDFA (the advertising identifier). On devices where ATT returns "allow," the IDFA is available; where it does not, you get a zeroed value.

What matters is when the IDFA becomes final. If an ad request fires before the ATT result is in, the IDFA is not yet available at that moment. The SDK treats the device as non-trackable and builds its bid accordingly. The first request leans on non-targeted inventory, and the price drops. That was the "first session only" weakness I was seeing.

From the second session onward the ATT outcome is already stored by the OS, so the IDFA returns immediately and the step disappears. That is why the daily average hid it — you only see this degradation once you split the segment into "first session" versus "later sessions."

Why the order matters this much

Here are the four players, lined up by their dependency direction.

ComponentRolePosition in init order
ATTrackingManagerRequests tracking consent; decides IDFA availabilityFirst
IDFAThe ad identifier, finalized after consentDepends on ATT
GMA SDK (MobileAds)Reads the consent result, then builds bids and deliveryAfter ATT
SKAdNetworkAttribution path that does not depend on consentHandled by the SDK

The dependency runs one way. ATTrackingManager produces a result → the IDFA is finalized → MobileAds bids against that state. Break the order and MobileAds starts running while "nothing has been decided yet."

The official docs say to request ATT "before you load ads," but the trap in practice is the difference between "right after you call the request" and "after consent has returned." requestTrackingAuthorization is asynchronous and returns its result in a callback, so the moment right after you call it, nothing is settled. Unless you start MobileAds inside the consent callback, you lose the race even though you thought you respected the order. My first version did exactly the wrong thing — it started MobileAds immediately after the call.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Pin down why fill rate and eCPM dip on the first session only, narrowed to the single issue of ATT / IDFA / MobileAds initialization order
Copy a complete, race-free Swift snippet for the correct ATTrackingManager and MobileAds.start ordering straight into your own app
Hand the order check across scattered init calls to an Antigravity agent while you keep the delivery-policy decisions in human hands
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-05-24
Running iOS Push Notification A/B Tests Weekly With Antigravity Agent — A Self-Improving Loop For Copy, Timing, And Segments
Drawing on 12 years of indie iOS app development across wallpaper and wellness apps with over 50 million cumulative downloads, this article walks through a weekly Push Notification A/B testing loop powered by Antigravity Agent. It covers the FCM bridge, BigQuery measurement, segment design, and a real D7 retention recovery story.
App Dev2026-05-06
How I Tripled Wallpaper App Revenue Using Antigravity — AdMob Optimization to ASO (2026)
A case study on using Antigravity to overhaul a wallpaper app — improving AdMob revenue, App Store ratings, and organic downloads. Only the changes that actually moved the numbers, with real results.
App Dev2026-03-27
Antigravity × AdMob Revenue Optimization Guide — Streamline Mobile Ad Implementation with AI Agents
Learn how to leverage Antigravity's AI agents to streamline Google AdMob implementation and maximize mobile ad revenue. Covers ad format selection, waterfall optimization, and A/B testing strategies.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →