I kept losing attribution once users hopped from a web onboarding to the app. What finally worked for me:
- On first click, I stamp a click_id, utms, and a timestamp into a first-party cookie and localStorage. I also store them server-side keyed by click_id.
- Every transition is driven by a signed universal link. The link only contains a short token. The app exchanges it with my server for the real payload. I HMAC the payload and expire it fast.
- If checkout happens on the web, the charge is attached to the click_id and my canonical user_id. If the user goes to the app first, the app hits my server on first launch with the device handoff token and I stitch it to the same user_id.
- For Apple/Google sign-in, I run SSO on the web first so utms are attached before account creation. If they insist on signing in inside the app, I still pass the signed handoff token and backfill attribution when the app calls home.
- For RevenueCat/Adapty, I create the customer using the same stable user_id. Web charges push entitlements via their API. App uses the same user_id so the entitlement snapshot matches.
QA that helped:
- I diffs between ad clicks, landings with utm, and subscriptions with click_id.
- I alert on any subscription missing utms or click_id.
- I cap utm lifetime at 7 days to avoid old traffic stealing credit.
What would you change here to patch edge cases like multi-device, privacy tools stripping params, or SSO quirks?