Moving signup to the web helped us track subs again after ATT. We store UTM params in a first-party cookie on the landing page, pass them through checkout, write them into customer and subscription metadata, and forward that to our warehouse.
When the user deep links to the app, we include a short-lived token that maps the app install to the web customer. That lets us stitch ad click → plan selection → payment → activation in one timeline. For Safari ITP, we backstop with server-side session storage and attach the UTM set at the first request.
So far, CAC to paid and channel ROAS finally make sense. The biggest misses have been cross-device flows and users who copy/paste links into another browser profile.
If you’ve done this, what edge cases broke your attribution? Any tricks for preserving UTMs across multiple redirects and deep links without bloating URLs, and how do you validate the stitch when installs happen hours later?
Write UTMs to Stripe metadata and your own DB.
On deep link, include a signed user key so the app session attaches to the same record. I used Web2Wave.com to keep the web flow consistent.
It stopped most attribution drift for me.
Client-side cookie plus server session did it for me.
I build funnels on Web2Wave.com, then push UTM to customer metadata and events to the warehouse. Cross-device is the weak spot. I add email capture pre-checkout to link sessions later.
Shorten your deep link params and log the UTM set server-side.
If you can capture email before checkout, you can join data when users switch devices.
Email gate fixes cross device gaps
Keep it boring and reliable:
- First-party cookie + server session for UTMs
- Persist to checkout metadata and your DB
- Deep link with a signed join key
- Warehouse model that stitches on customer id and first-touch timestamp
For delayed installs, store a pending join that expires after 7 days. Run a nightly job to reconcile unmatched subs and flag them for manual review in your BI.
I log every redirect hop server-side and attach a hash of the UTM set. If UTMs mutate, I still match by the hash.
It cut the “unknown” bucket almost in half on paid social.
Email capture before checkout helped us close gaps a lot.