Recurring revenue lives or dies on subscription friction. In 2025, both Apple and Google tightened policy around pricing transparency, cancellation, and account deletion. The engineering work is half payments, half lifecycle hygiene. Here’s a compact, production-ready playbook.
1) Product Model and Entitlements
Structure products cleanly:
- Tiers: free, plus, pro. Keep SKU naming deterministic (
pro_monthly,pro_yearly_intro). - Benefits → entitlements: represent access in your backend (e.g.,
entitlements: ["pro_features"]). The client renders UI based on entitlements, not raw SKU names. - Intro/Promo: isolate introductory offers and win-back promos as separate SKUs with limited eligibility tracking server-side.
2) Purchase Flow (Client)
- iOS (StoreKit 2): Use
Product.products(for:)to fetch,purchase()to transact, andTransaction.updatesto listen for changes. Validate locally, then forward receipts to your backend for authoritative validation. - Android (Billing Library 7.x): Query products with
queryProductDetailsAsync, launch withBillingFlowParams, and handlePurchasesUpdatedListener. Acknowledge purchases within 3 days; setpendingstates for cash-based regions.
UX rules: Single, clear paywall; show monthly vs yearly with transparent effective price; disclose renewal date and trial length. Always provide a restore purchases button.
3) Server Validation and State Machine
Treat the server as the source of truth:
- Validation: Forward iOS signed transactions and Android purchase tokens to platform endpoints. Cache results with TTL.
- State machine:
inactive → trialing → active → grace → on_hold → canceled. Persistrenewal_intent,period_end,is_in_intro. - Webhooks/RTDN: Subscribe to App Store Server Notifications v2 and Google Real-Time Developer Notifications. Drive entitlement changes from events, not cron jobs.
4) Cross-Device Consistency
- User identity: Require sign-in for premium features; map platform account to your user ID.
- Restore: On new device, call restore/queries, match receipts/tokens to user, and reissue entitlements.
- Offline: Cache current entitlements locally with short TTL; degrade gracefully if the server is unreachable.
5) Pricing, Trials, and Compliance
- Price transparency: Show full recurring price, billing period, trial length, and cancellation timing near the CTA. No dark patterns.
- Local currency: Render from platform price objects; avoid hard-coded numerics.
- Regions & taxes: Rely on store collections; don’t duplicate tax logic.
- Account deletion: Provide in-app account deletion that also erases billing identifiers you store (keep a minimal audit token if legally required).
- Cancellation route: Surface the platform’s manage-subscription link from settings.
6) Churn Prevention and Win-Backs
- Grace & on-hold: Respect store grace periods; keep read-only access or limited features while payment issues resolve.
- Dunning (store-compliant): Nudge inside the app (no external payment steering). Explain what pauses on expiry.
- Win-back offers: Trigger after 14–30 days of churn with compliant promos (intro pricing eligibility varies by platform).
7) Observability and Fraud Controls
- Metrics: trial start→convert rate, churn by cohort, grace → recovered, refund rate, revenue by country, LTV by channel.
- Attribution: Store the last non-PII acquisition channel; analyze paywall conversion per campaign.
- Fraud: Rate-limit restore attempts, verify signed transactions, and fingerprint anomalous device patterns (without storing PII). Flag unusually high refund ratios.
8) Testing and Release Safety
- Sandboxes: Use StoreKit testing in Xcode and Play Console license testers; simulate renewals, grace, price changes, and refunds.
- Feature gates: Wrap new paywalls/price tests behind remote flags.
- Rollback: If validation or webhook processing breaks, default to no new entitlements but never silently revoke current active users. Fix forward; communicate in-app.
9) Paywall Craft
- Clear value bullets tied to entitlements, social proof, and a single prominent CTA.
- Monthly vs yearly toggle with honest savings math.
- Accessibility: large tap targets, readable contrast, and VoiceOver/TalkBack labels.
Bottom line: Model entitlements on the server, drive state from real-time platform notifications, and keep the client focused on a clean, compliant UX. Respect grace periods, make cancellation transparent, and use data—not guesswork—to refine the paywall and reduce churn.




