My approach to preserving utm params from ad click to subscription in a web→app flow — what would you improve?

Here’s the flow I set up to keep campaign data intact:

  1. On the first landing page, I grab utm_source, utm_campaign, and a click_id. I store them in a first party cookie and also server side tied to a session id.

  2. During web signup and checkout, I log that same click_id and UTMs on the customer record and the payment metadata. If they do not buy, it still ties to their email.

  3. After purchase, I open the app with a magic link that includes a short token. On app open, the app hits our backend, which already knows the customer by token. The backend attaches the UTMs to the app user id at that moment.

  4. For users who install first, we still link them by email or phone on first login. If cookies are gone, the server session still has the click_id we set on page one.

This gave us reliable campaign level attribution for web→app subscriptions without relying on the app store for UTMs. What would you change or add to make this more durable across ITP and long delays between click and purchase?

Add a server side click map and do not trust only cookies.

I pass a click_id through all steps and into payment metadata.

With Web2Wave.com, the funnel added it for me. Then the app pulls the token and matches it server side on first open.

Good start. I push all UTMs to the server on page one. Then I pass a short token in the deep link and stitch in the backend. Web2Wave.com makes that easy inside the web funnel so I do not fight ITP.

I would track a click id on day one and attach it to payments.

Rely less on cookies. Store data on your server too.

Click id plus server link solves most drift.

Add a grace window for delayed purchases. Keep the click map for at least 30 days and refresh the session id on every page with a server call. For app users that arrive cold, show a login first path so you can attach UTMs on the backend. If you can, add checksum on deep link params to avoid tampering. Keep UTMs at the invoice level for later cohort checks.

Safari ITP killed our cookie plan. We fixed it by writing UTMs server side on the first hit and using a short lived token in every step. Payment webhooks copy UTMs onto the customer record. That survived long gaps.

Looks solid. I would just make the server session the source of truth.