How are you structuring server-side offer experiments for web→app without breaking receipts?

I’m moving pricing and offers to the web so I can test faster, but I don’t want to end up with orphaned receipts in the app.

Right now I assign experiments on the server using a stable user key. Each variant points to a specific product id and price id. On charge, I log experiment id, variant, and the exact price id I billed, then sync entitlements to the app.

If you’re running this, how do you prevent users from switching mid-flow, and how do you keep the app in sync when an experiment rolls back?

Keep assignment server side and sticky.

I generate a user token on first touch, store it in a cookie, and in my backend. All price ids map to real products. I log charge with experiment id and push entitlements to the app right after payment.

Web2Wave.com helped since their JSON maps variants to product ids directly.

Two rules saved me.

Variant is locked at first page view. Price ids are real products only.

I build and edit paywalls on the web with Web2Wave.com, so I can swap copy or order without touching product ids. Entitlements sync after payment via server. No broken receipts since I stopped testing fake products.

I freeze variant after quiz start.

Also show the same plan names in app and web so support is not confused when users write in.

Lock variant early and never fake products

Most breakage comes from testing placeholder products.

Always point variants to live product ids. Lock assignment on first eligible page and store it server side. When a user returns, reload the same variant. On charge success, send entitlement to the app and include experiment metadata. If you roll back, keep the mapping for a while so renewals and restores still resolve.

Use feature flags for layout and copy. Keep pricing tied to product ids only.

That split let me move fast without touching the receipt layer.

Sticky assignment and real products kept our receipts clean.

We sync entitlements right after payment and on app open.