Growth × Engineering · iOS attribution

Our trials were
invisible to Meta.
Here's why —
and the fix.

We were getting trials from Instagram ads. RevenueCat proved it. But Meta Ads Manager reported zero. The culprit isn't the ads — it's how Apple privacy (ATT) and SKAN carry the signal. This page explains it in five minutes.

No jargon required ~5 min read Fix already shipped
01 — The symptom

Two dashboards. Two completely different stories.

Same users, same month. RevenueCat — our source of truth for subscriptions — counted hundreds of trial starts. Meta, which we pay to drive them, saw none of them.

RevenueCat · new trials (30 days)
0
Real trials, really happening. App Store + Play Store.
SOURCE OF TRUTH
Meta Ads · "In-app start trial"
0
The exact event the campaign optimises for — stuck at zero.
53 installs · 0 trials reported

The ads worked. The measurement didn't. Meta literally couldn't see the conversions it was paying for — so it couldn't optimise, and we couldn't trust the numbers.

02 — The root cause

Apple cut the wire: App Tracking Transparency.

Since iOS 14.5, every app must ask permission before it can track you across apps. That permission unlocks the IDFA — the device ad ID Meta historically used to match a trial back to the exact ad click.

🔒

Allow "OnCourse" to track your activity?

Your data will be used to deliver personalised ads.

Ask App Not to Track
Allow
Device ad ID (IDFA) A1B4-9F2E-77C3-0D5A-E831
  • Tap “Ask App Not to Track” and the IDFA collapses to all-zeros. No shared identifier exists.
  • Without it, Meta cannot deterministically match a trial to the click that drove it.
  • AppsFlyer then files those users as “organic” — so the paid channel looks empty, even though it isn't.
On iOS, roughly 9 in 10 users opt out.

That's the trap: the old, identifier-based way of counting trials is dead on arrival for almost everyone we acquire.

03 — The privacy-safe path

SKAN: how Apple lets you measure without tracking.

SKAdNetwork (SKAN) is Apple's own attribution system. It needs no IDFA and no ATT permission — that's the entire point. Instead of identifying a person, the app sends Apple a tiny anonymous code, and Apple passes an aggregated result to Meta.

👆

Ad tap

User taps your Instagram ad. Meta cryptographically signs the click.

📲

Install + trial

App opens and sets a conversion value — a small code for what happened.

cv = trial started
🍎

Apple holds it

Apple waits a randomised 24–48h, strips all identity, then sends a postback.

anonymous · delayed
📊

Meta decodes

Meta reads the conversion value via your schema and reports the trial.

No user ID ✓ Works without ATT ✓ Aggregated & delayed ✓ Campaign-level only

The whole system hinges on that conversion value — and that's exactly where our problem lived.

04 — The bug, made visible

Apple sends one tiny code. We never told it what “trial” meant.

The conversion value is decoded with a schema you configure in AppsFlyer. Ours only encoded “app installed.” So every postback Meta received said “install” — and nothing about trials. Flip the switch below to see what changed.

SKAN schema · Window 1 (days 0–2)
appsflyer · skan-conversion-studio · id6504909373
SKAN postback to Meta ───▶ 53 installs · 0 trials

Same ads, same spend, same users. The only change is that the trial and direct subscription events now occupy a slot in the code — so Apple's postback can finally carry them, and Meta can finally count them.

05 — What we shipped

Three changes. The wire is reconnected.

01

Encoded trials into SKAN

Rebuilt the AppsFlyer conversion-value schema so a trial start and a direct subscription each map to a value Meta can read.

Live in production
02

Kept the opt-out crowd

Turned on “Support anonymized users” so SKAN postbacks from the ~90% who decline ATT are retained instead of dropped.

Live in production
03

Fed RevenueCat the source

The app now forwards media source & campaign into RevenueCat, so paid installs stop showing as “No Attribution.”

PR open → main
06 — What to expect

SKAN is slow by design. Read it with patience.

Because Apple anonymises and delays everything, conversions surface gradually — and only for installs that happen from now on. It will not backfill.

2–4 days
First trickle of trial conversions appears in Ads Manager for the earliest new installs.
~1 week
A clearer signal once several days of fresh installs have cycled through the windows.
2–4 weeks
Enough volume to actually judge performance — Apple's privacy thresholds gate low-volume data.
Keep in mind: SKAN numbers are aggregated, delayed, and modelled — they will always read lower and later than reality on iOS. RevenueCat stays the source of truth for true trial volume and for the weekly/monthly/annual plan split. Meta's number is the signal we feed its optimiser, not the scoreboard.

TL;DR for the team

iOS users opt out of tracking, so the old way of counting trials is dead. SKAN is the privacy-safe replacement — but it only works if the trial event is written into its conversion-value code. Ours wasn't; now it is. Expect Meta's trial numbers to start climbing within a week, stay lower than RevenueCat, and get more reliable as volume grows.