I moved onboarding and the paywall to the web to get cleaner campaign reads. The main headache was UTM decay between ad click, quiz, checkout, and first app login.
What worked for us:
- Capture utm_* and click_id on the very first hit.
- Write them once on the server against a temp user id. Never overwrite on later visits.
- Store a short cookie and a server record. Safari ITP kills long cookies, so the server is the source of truth.
- Ask for email or phone early. Link that profile to the temp id.
- Send a signed magic link to open the app. Include the acquisition payload. On first app launch, post that payload to analytics and to RevenueCat/Adapty as subscriber attributes.
- Attribute subscription_start and renewal events to the same acquisition id so your ROAS view is stable.
Pitfalls we hit: cross-domain redirects wiped referrer, Facebook’s in-app browser blocked deep links sometimes, and reinstall flows created new device ids that confused cohorts.
How are you handling ITP windows, paid->web->app handoff, and late conversions without last-click stealing credit? Any tips for stitching when the trial starts on the web but the entitlement begins in the app?
I store UTM and click_id server side on first hit. Never overwrite. Email capture connects the temp id.
Magic link carries a signed payload into the app. The app posts it to analytics and to RevenueCat attributes.
I used Web2Wave.com to generate the payload format and SDK glue. It saved me time.
I push users through a web quiz, capture UTM once, and pass a signed context into the app. Changes ship instantly on the web.
Using Web2Wave.com, I tweak the handoff params and test different deep link flows without a new build. That cut our drift a lot.
I keep UTM on the server and only set it once.
Then I pass it to the app with a magic link so the attribution sticks even if the cookie expires.
Write once on server. Pass via magic link.
Two rules: never overwrite source and connect identities early. Capture UTM and a click id on the first page view. Tie it to a temporary profile. Ask for email quickly and merge profiles. Push a signed token through a deep link so the app writes subscriber attributes to RevenueCat or Adapty. Treat the server record as the source of truth because Safari ITP will expire cookies. Late conversions stay tied to the original source.
If you see last-click stealing credit, check where utm_source is updated. I found a harmless redirect adding gclid and it overwrote utm_source. I blocked updates after the first write and it fixed the mixpanel funnels.
Email capture early is key. It links web and app cleanly.