Skip to content

Work / Aakalan / Wiki / Concepts

revenuecat-rules

Conceptverified 2026-10-30

revenuecat-rules

src/services/purchases.ts wraps the SDK: one pro entitlement, monthly and annual packages off the default offering. <ProProvider> in src/components/pro-provider.tsx is mounted in _layout.tsx; usePro() is in src/hooks/use-pro.ts.

  • Every function in purchases.ts is safe to call unconditionally. In Expo Go, on web or without keys they no-op and report "not pro". Add no platform guards at call sites.
  • Never hardcode a price. Render plan.priceString from usePro().plans.
  • Never promise a free trial unconditionally. Check trialEligible: a returning subscriber has used theirs and would be charged at once. The Play offer's eligibility is "never had ANY subscription in this app", so a monthly trialist gets no free year.
  • Never read allPurchasedProductIdentifiers or nonSubscriptionTransactions. They are append-only and do not shrink on refund. entitlements.active is the only truth.
  • onProStatusChange keeps state correct across renewals, expiry and refunds, not only purchases made this session.
  • The paywall must expose Restore purchases without scrolling. App Store review rejects without it.
  • identifyUser(uid) ties the entitlement to the account, not the device. It is skipped for PLACEHOLDER_UID and local: ids in pro-provider.tsx. Phone auth is live, so the placeholder guard can go.
  • RevenueCat needs a dev build: the native module is absent in Expo Go.
  • Do not put an empty string for a RevenueCat key in eas.json: it overrides the secret.
  • Anything designed but unreachable from a screen is marked "Soon" in the UI, not rendered as a working control. Nothing currently is.

Related: pricing, pro-never-gates-the-core-loop, plans