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.tsis 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.priceStringfromusePro().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
allPurchasedProductIdentifiersornonSubscriptionTransactions. They are append-only and do not shrink on refund.entitlements.activeis the only truth. onProStatusChangekeeps 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 forPLACEHOLDER_UIDandlocal:ids inpro-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