I’m trying to close the gap between the ad click and the moment the user actually gets an entitlement in the app, without forcing account creation on the web. Here’s what I’ve been doing so far, and where it still feels fragile.
On the web:
- Capture UTMs on first load, set a server cookie (SameSite=Lax) and mirror to localStorage as a backup. Append UTMs to every internal link and include them in the checkout payload.
- Generate a short-lived claim_token at checkout start. On successful payment, fire a server event with UTMs + claim_token + email if collected + price/offer variant.
- Redirect to a “continue in app” screen with a deep link that includes the claim_token. Also email a magic link with the same token for users who switch devices later.
In the app:
- Use deferred deep linking so first open resolves the claim_token. If it arrives, my backend exchanges the token for the web customer_id, UTMs, and purchase details.
- Set identity early. I pass the stable customer_id to Adapty/RevenueCat as app_user_id, then confirm entitlement. Analytics (Mixpanel/Amplitude) gets an identify call with the same ID and UTM properties so cohorts stay consistent.
What’s working:
- Channel attribution sticks to the actual subscription, not just the install.
- We can see cohorts by utm_source/creative through trial and into renewal.
Edge cases and pitfalls:
- Safari ITP shortens cookie life. Server-set cookies last longer than client-only storage, but I still see some lost UTMs after 7 days.
- If the user ignores the deep link and opens the app from the store, the claim_token never arrives. The email magic link helps, but not everyone clicks it.
- Cross-domain hops can strip query params if the redirect chain isn’t clean. I had to standardize a single canonical domain.
Questions:
- If you don’t require sign-up on the web, how are you reliably claiming the right user in the app? Are you using Branch/AppsFlyer links plus a server token, or something simpler?
- Any clean patterns for recovering the journey when deferred deep link fails to deliver the token on cold start?
- Bonus: if you have a diagram or code snippet for the claim_token exchange and identity sync with Adapty/RevenueCat, I’d love to see it.