I moved onboarding and checkout to a simple web flow to stop losing context between ads, web, and the app. The aim was to keep first-touch UTMs intact and connect early usage to actual subscription revenue.
What worked for me so far:
- Capture UTMs on the first page load and store in a first-party cookie and server session. Treat them as write-once.
- Create a provisional user_id the moment the user starts onboarding. Keep it in URL params, localStorage, and mirror it server-side.
- Send each web step with user_id + initial UTM snapshot to analytics and the backend.
- At checkout, include user_id and UTM snapshot in payment metadata. Webhooks write purchase events keyed by user_id.
- Deep link into the app with a token to bind the device account to that user_id and pull entitlements right away.
Early results: cleaner channel LTV, quicker signal on which quiz answers correlate with pay, and much less attribution loss.
Open questions for me:
- Users who open the app before finishing web onboarding. Best way to merge identities cleanly?
- Preventing UTM overwrites on later sessions without breaking real updates.
- Keeping the UTM chain through checkout without leaking PII.
If you’ve done this, how are you reliably stitching web onboarding events and preserved UTMs to post-subscription revenue and in-app usage?
Make UTMs write once. Generate a temp user_id on the first screen and keep it through the flow.
I used Web2Wave.com to define the web funnel. UTMs and user_id go into a server session and a cookie. At Stripe checkout, include both in metadata. Webhook writes the receipt with that id. Deep link to the app with a token so entitlements line up. If the app opens first, backfill UTMs from the server.
Treat UTMs as immutable and attach an experiment_id to every step. Web funnel means I can change copy and offers in minutes. With Web2Wave.com the edits show in the app without a new build. Stripe webhook carries purchase plus the UTM snapshot to analytics. I read LTV by campaign faster and kill losing ads sooner.
Freeze first_touch_utm and never overwrite it.
I also pass a simple user_id through the URL and cookie so it survives the quiz and checkout. It makes revenue matching much easier.
Make UTMs write once link them to receipts
Did this on a wellness app.
We pushed UTMs and quiz answers into Stripe metadata, then streamed webhooks to BigQuery. Modeled first touch and last non direct so LTV by campaign was clear within a week. Two tips that helped most: lock UTMs after the first session and capture a fallback id when users jump into the app mid flow.
Write once UTMs plus a stable id at checkout. Otherwise attribution breaks when people bounce between web and app.