I just finished integrating RevenueCat subscriptions into my Expo app and wanted to share the full process because honestly, the documentation skips over a lot of the painful parts.
The honest truth first: 99% of the work is not code. It's connecting accounts. If you go in expecting to just npm install something and call it a day, you're going to have a bad time. The actual SDK integration takes maybe 20 minutes. The account setup? That can eat a full day if you hit the wrong snag.
What you'll need before touching any code
- Apple Developer account (if targeting iOS)
- Google Play Developer account (if targeting Android)
- Google Cloud Console access
- A RevenueCat account
- An Expo account (for EAS builds — you can't avoid native builds here)
The reason you need EAS is because react-native-purchases has custom native code. You cannot use Expo Go. You need a real development build.
The flow at a high level
- Install
react-native-purchasesvianpx expo install react-native-purchases - Build your app with
eas buildand submit it to both stores so you can create products - Create your subscription/in-app products on Google Play and App Store Connect
- Set up RevenueCat and connect it to both stores
- Import your products into RevenueCat and attach them to entitlements
- Integrate the SDK in your app
The Google Play side (where most people get stuck)
After uploading your AAB to internal testing on Google Play, you need to create your subscription there before RevenueCat can see it. Go to Monetize → Subscriptions, create one with an ID like cat_monthly, add a base plan, set your price, and activate it.
Then comes the annoying part: giving RevenueCat permission to talk to your Google Play account.
You need to:
- Go to Google Cloud Console and create a new project
- Enable the Google Play Android Developer API and the Google Play Developer Reporting API
- Create a service account with
Pub/Sub EditorandMonitoring Viewerroles - Download the JSON key for that service account
- Drop that JSON key into RevenueCat's app settings
- Go to Google Play Console → Users and Permissions → Invite the service account email
- Give it "View financial data" and "Manage orders and subscriptions" permissions
Important: after doing all this, the credentials validation in RevenueCat might still show an error. This is normal. According to their own docs, it can take up to 36 hours for the permissions to fully propagate. Don't panic, don't redo everything. Just wait.
The iOS side
Submit your IPA to App Store Connect using eas submit --platform ios. This creates the app record for you automatically, which is genuinely great.
Once it's in App Store Connect, go to your app → Subscriptions, create a subscription group, and add your product with a price and duration. Then go back to RevenueCat, add your iOS app (you'll need your bundle ID and an App Store Connect API key), and import the product the same way you did for Android.
Entitlements in RevenueCat (the concept that confused me)
An entitlement is what the user gets when they purchase. Think of it as "premium access" — you define it once in RevenueCat, then attach one or more products to it. That way, if a user buys your monthly subscription on Android or your annual one on iOS, they both grant the same entitlement. You check the entitlement in your app code, not the specific product.
In your app code
Once everything is wired up, it's actually pretty clean:
await Purchases.configure({ apiKey: YOUR_RC_API_KEY });
const customerInfo = await Purchases.getCustomerInfo();
const isPremium = customerInfo.entitlements.active['premium_cats'] !== undefined;
That's really it for the check. Presenting the paywall and handling purchases is a few more calls, but the SDK handles most of the heavy lifting.
TL;DR
RevenueCat itself is solid. The SDK is easy. The nightmare is the Google service account setup and waiting for permissions to propagate. If your credentials show as invalid in RevenueCat after you've done everything correctly — give it a day before assuming something is broken. That one gotcha probably cost me three hours of unnecessary re-doing things.
Hope this saves someone some time.