I want retention cohorts that reflect actual subscription states, not just web clicks. We sync web funnel events to the app’s subscription provider, then use those states to build cohorts. What worked and what bit me:
- Map web events to subscription milestones: trial_started, converted, renewed, refunded, canceled. Keep names identical across systems.
- Use idempotency on the webhook consumers. Duplicate webhooks happen.
- Align timezones. My first cohort chart was off because one system logged UTC and another local.
- Handle upgrades and downgrades. The revenue curve changes even if “active” stays true.
- Keep a single user_id across web and app. Email-only keys broke when users changed emails.
I also added a daily reconciliation job that compares processor reports to RevenueCat/Adapty states and fixes mismatches. That caught refunds and chargebacks that did not fire webhooks.
For anyone who has done this: what schema and event mapping kept your cohorts clean, and how did you handle late refunds without corrupting historical metrics?