💰In-App Purchases
Sell digital subscriptions and one-time products inside your app using Google's and Apple's native purchase systems.
What are In-App Purchases?
Natively provides built-in support for RevenueCat to handle in-app purchases and subscriptions across iOS and Android. RevenueCat manages purchase validation, receipt handling, and subscription status for you, so you don't have to build and maintain this infrastructure yourself.
Apple and Google require apps to use their native in-app purchase systems - not external payment processors like Stripe - for digital goods, content, and subscriptions sold within the app. Physical goods and real-world services are the main exception. See How to use for more information.
Prerequisites
This feature requires the Unlimited or Lifetime plan. See all plans
A RevenueCat account.
iOS:
An Apple Developer account.
Your iOS app is already published in the Natively Dashboard.
Android:
A Google Play Developer account.
Your Android app is already published in the Natively Dashboard.
App Stores Product Configuration
Before RevenueCat can validate purchases, your subscription or one-time-purchase products must exist in Google Play Console (for Android) and/or App Store Connect (for iOS).
Your Google Play Console account must have a Google Merchant account configured before you can sell in-app products or subscriptions. If you haven't set this up yet, Google Play will prompt you to configure it when you first try to create a product.
If you don't see an option to create subscriptions or in-app products yet, upload a build first - create a release in a Closed testing track and upload Android .AAB file from Natively Dashboard.
Open your app in Google Play Console and go to Monetize with Play > Products.
Follow RevenueCat's Android Product Setup guide to create your subscription or in-app products.
Confirm your subscription products show as Active in Google Play Console.
Your Paid Applications Agreement must be signed before you can set up or test any in-app purchases. In App Store Connect, go to the Business module and sign the latest version of the agreement. You'll also need to complete the Tax and Banking tabs, with a linked bank account showing a Clear status - in-app purchases won't work in sandbox or production until all of this is complete.
Open App Store Connect and navigate to your app.
Follow RevenueCat's iOS Product Setup guide to create your subscription or one-time purchase products.
Confirm each product's state shows Ready to Submit before it can be used - even for sandbox testing.
RevenueCat Configuration
With your store products created, connect RevenueCat to each store so it can manage the full purchase lifecycle on your behalf.
Create your RevenueCat project
Sign up or log in at RevenueCat.
Click New Project, give it a name - typically your app's name - and confirm.
Each RevenueCat project can hold one or more apps (e.g., your iOS and Android apps), and is where all your Products, Entitlements, Offerings, and API Keys will live.
Add and connect your app(s)
In your RevenueCat project, go to Apps & providers in the left sidebar.
Click New app configuration.
Select Google Play Store for Android, and App Store for iOS.
Configure the platforms:
Enter the Android app Package Name (Bundle ID) configured in your Natively Dashboard.
Upload your Service Account Credentials JSON. Follow RevenueCat's Google Play Store service credentials guide for the full walkthrough.
Click Save changes.
Enter the iOS app Bundle ID configured in your Natively Dashboard.
Upload your In-app Purchase Key. Follow RevenueCat's In-App Purchase Key guide for the full walkthrough.
Add your App Store Connect API key. Follow RevenueCat's App Store Connect API Key guide for the full walkthrough.
Click Save changes.
The App Store Connect API key you already created for publishing your iOS app in the Natively Dashboard can be reused here - no need to generate a new one.
Set up your Product Catalog
Once your app is connected to each store, bring your products into RevenueCat and organize them.
You must have at least one Entitlement and at least one Offering to use RevenueCat with Natively.
Import your product(s)
In RevenueCat, go to Product Catalog in the left sidebar, then click Products.
Find your connected store (App Store or Play Store) and click + New.
Click Import Products and select the products you created earlier in App Store Connect and/or Google Play Console.
Click Import.
Repeat for each platform you support - iOS and Android products need to be imported separately, even if they represent the same offer.
Check RevenueCat's Import Products guide for the full walkthrough.
Create Entitlement(s)
Entitlements represent the access level a purchase unlocks in your app - for example premium, pro, or gold. Most apps need only one entitlement; create more only if you offer distinct tiers.
Go to Product Catalog > Entitlements and click + New Entitlement.
Give it an identifier (e.g.
premium) and the display name, then click Add.Open the entitlement you just created. In the Associated products section, click Attach and select the products that should unlock it, including the equivalent product from each platform.
Check RevenueCat's Entitlements guide for the full walkthrough.
Avoid spaces in the identifier - use something like premium or pro_tier instead of Premium Access. The identifier is what your app's code checks against, so keeping it simple and consistent avoids issues later.
Create Offering(s)
Offerings control what your app actually displays to users, and let you change pricing, packaging, or messaging remotely - without shipping an app update.
Go to Product Catalog > Offerings.
RevenueCat automatically creates a default offering for you - you can use it, or click + New to create an additional one if you need multiple offerings (e.g., for different user segments).
Open the offering and click Edit to add/change the Packages - these group equivalent products across platforms (e.g., a monthly subscription available on both iOS and Android) under a single identifier your app's code can use.
Check RevenueCat's Offerings guide for the full walkthrough.
RevenueCat provides predefined package identifiers for common cases (e.g. $rc_monthly, $rc_annual), or you can create your own custom identifier if none of the predefined ones fit.
Package identifiers must be distinct across your offerings - reusing the same identifier in more than one offering can cause unpredictable behavior.
Natively Dashboard Setup
Before proceeding, make sure you have completed the RevenueCat Configuration steps above.
Open your Natively app dashboard and navigate to Features > In-App Purchases.
Toggle the feature to Enabled.
Paste the Public API Keys you copied from RevenueCat into the respective fields:
iOS API Key - starts with
appl_.Android API Key - starts with
goog_.
Click Save.
Rebuild your app(s).
Make sure you're using your App Store (appl_...) or Play Store (goog_...) key - not RevenueCat's Test Store key. The Test Store is a separate sandbox environment inside RevenueCat and won't work with purchases in your app.
You must rebuild your app for these changes to take effect.
Implementation
Choose your integration method below: Bubble.io Plugin (No-Code), JavaScript SDK (Code), or AI Agents (for AI-powered editors like Lovable, Base44, and Replit).
Initialization
Check Plugin
Before starting, verify if the Natively plugin is already installed in your Bubble project.
Open your Bubble editor and navigate to the Plugins tab in the left sidebar.
Check Installed Plugins: Look through your list of installed plugins for "Natively iOS & Android app builder".
If it IS installed: Check the version number. If an update is available (e.g., you see a button saying "Update"), click it to ensure you have the latest features and bug fixes.

If it is NOT installed: Click the + Add plugins button, search for "Natively", and click Install.

Check SDK
Before writing any logic, ensure the Natively SDK is correctly installed and up-to-date in your codebase.
Open your project's main HTML file (or header settings) and look for the Natively script tag inside the
<head>section.Install/Update: If missing or outdated, add the following code. You can specify the SDK version in the URL (e.g.,
@2.26.0).
To ensure you are using the most up-to-date version, check the Natively GitHub releases page for the latest version number.
Initialize the SDK
AI-powered editors like Lovable, Base44, and Replit use the JavaScript SDK to implement Natively features. Before implementing any feature, the Natively SDK must be initialized in your project.
Copy the line below and paste it into your AI agent to check and set up the Natively SDK in your project.
Setup Logic
[Element] Natively - Purchases
Events:
Set Customer Success - fires when Set Customer ID completes successfully.
Set Customer Failed - fires when Set Customer ID fails.
Customer ID Received - fires when Get Customer ID returns a result.
Get Price Success - fires when Get Package Price completes successfully.
Get Price Failed - fires when Get Package Price fails.
Purchase Success - fires when a purchase completes successfully.
Purchase Failed - fires when a purchase fails due to an error.
Purchase Cancelled - fires when the user backs out of the purchase flow. Handle this separately from Purchase Failed - it isn't an error.
Restore Purchase Success [iOS] - fires when Restore Purchase successfully finds and restores prior purchases.
Restore Purchase Failed [iOS] - fires when Restore Purchase fails.
Paywall - purchase success - fires when the user completes a purchase through the paywall.
Paywall - cancelled - fires when the paywall is shown, and the user closes it without taking action.
Paywall - error - fires when the paywall was shown and an error occurred during an operation.
Paywall - was not presented - fires when the paywall doesn't display at all.
Paywall - Entitlement ID missing - fires only when using Show Paywall if needed without providing an Entitlement ID.
Paywall - Offering ID was not found - fires only when the provided Offering ID is invalid.
Paywall - restore purchase success [iOS] - fires when the user restores a purchase from within the paywall.
States:
Latest Transaction Id - the transaction ID after Purchase Package.
Latest Customer Id - the customer ID after Set Customer ID or Purchase Package.
Latest Error - empty if no error occurred.
Latest GetPrice price - the raw numeric price, e.g.
9.99.Latest GetPrice price (Localized) - the localized price string, e.g.
"$9.99"or"9.99 USD".Latest GetPrice currency - the currency code, e.g.
"USD","UAH".Latest PurchasePackage packageId - the package ID from the most recent purchase attempt.
Actions:
Purchase Package - initiates the purchase of a product or subscription:
Package ID - the package to purchase.
Old Product ID (Android) - required only when upgrading or downgrading an active Android subscription. This must be the real store Product ID, not a package ID - retrieve it via RevenueCat - Verify Subscription below.
Proration (Android) - controls exactly when the user is charged and how their billing cycle adjusts during an upgrade or downgrade. See RevenueCat's Proration documentation for a full breakdown.
Set Customer ID - links your user's ID to a RevenueCat customer:
Customer Identifier - recommended to use your Current User's unique ID, so purchases are tied to the same account across devices.
Reset Customer ID - unlinks the current Customer ID from this device.
Get Package Price - retrieves the price for a specific package.
Get Customer ID - retrieves the current customer ID.
Show Paywall - displays a RevenueCat paywall:
Offering ID - optional; shows this specific offering instead of the default.
Show Paywall if needed - displays a paywall only if the user doesn't already have the specified entitlement:
Offering ID - optional; shows this specific offering instead of the default.
Entitlement ID - required.
Restore Purchase [iOS] - restores previous purchases tied to the user's App Store account. RevenueCat handles the underlying restore logic automatically.
RevenueCat - Verify Subscription
Unlike the actions above, this checks entitlement status directly against RevenueCat's servers rather than through the Natively SDK - useful for confirming a user's real subscription state, or for retrieving the store Product ID needed for Android upgrades/downgrades.
This action requires your RevenueCat Secret API Key - a different key from the Public API Keys used in Natively Dashboard Setup. Add it as revenuecat_apiKey in the Bubble plugin settings. Find it under RevenueCat App > API keys > Secret API keys, and confirm you're using an API Key V1 - other versions won't work.
Customer ID - the RevenueCat user ID used during Set Customer ID. If no customer exists with this ID, RevenueCat creates a new one.
Entitlements ID - the entitlement identifier to check.
Returns:
Product ID - the store product ID tied to the active entitlement.
Purchase Date
Grace Period Expires Date
Expiration Date
Is Active - Yes/No. Yes - when Expiration Date is after the current date.
Error - empty text if no error occurred.
AI-powered editors like Lovable, Base44, and Replit use the JavaScript SDK to implement Natively features.
Copy the line below and paste it into your AI agent.
Before using this prompt, gather your own project-specific values from RevenueCat: your Package IDs (e.g. $rc_monthly), Entitlement ID (e.g. premium), and Offering ID if you're not using the default. Include these in your feature description so the AI agent uses your actual values instead of placeholders.
Replace the placeholder at the beginning with a description of what you want to build - for example: "Add a paywall that shows monthly and annual subscription options, links to the user's account on login, and lets them restore purchases".
How to use
Know when Stripe is and isn't allowed
Apple and Google require digital goods, content, and subscriptions consumed within the app to go through their native purchase systems (IAP) - using Stripe or another processor for these will get your app rejected. The main exception is physical goods and real-world services (e.g. a taxi ride, a hotel booking, a physical product) - these can use Stripe or any other payment processor, even inside the app.
Only show IAP UI inside the Natively app
Use Browser Info to detect isNativeApp, and only show purchase/paywall UI when true. In a regular browser, use your web checkout flow instead (e.g., Stripe).
Log in before purchasing, restoring, or fetching offerings
Call login with a stable internal user ID as soon as the user is authenticated in your app - ideally the same ID you'd use across web and mobile. This ties purchases to the right customer in RevenueCat from the start, rather than to an anonymous ID that's harder to reconcile later.
Never trust the client alone for entitlement access
A SUCCESS purchase or restore callback confirms the purchase flow completed - it doesn't guarantee your backend has verified the entitlement yet. Always re-check subscription status server-side (via RevenueCat's REST API, or your own backend synced with RevenueCat) before unlocking premium features.
Handle CANCELLED differently from FAILED
A cancelled purchase means the user backed out - this isn't an error and usually shouldn't show error messaging. Reserve error UI for genuine FAILED results.
Always offer Restore Purchases, especially on iOS
Users reinstalling the app or switching devices need a way to recover purchases tied to their App Store / Google Play account without paying again.
Don't confuse Package ID with Store Product ID
packageId (e.g. $rc_monthly) is what you pass to purchasePackage for a normal purchase. But oldProductId, required for Android upgrades/downgrades, must be the real store product ID (e.g. com.company.app.premium:monthly) - retrieve it from platformProductId in getOfferings()'s response, not from a package ID.
Don't hardcode prices or product info
Use getOfferings() or packagePrice() to display live, localized pricing - prices vary by region and can change without a client update.
How to verify a user's subscription
Never rely on a purchase callback alone as proof of entitlement - always confirm with RevenueCat's own record of the customer's subscription state.
Use the RevenueCat - Verify Subscription action (documented in Setup Logic), which checks a customer's entitlement directly using your RevenueCat Secret API Key.
Setup example:
On each user login or first signup, set the RevenueCat Customer ID to your own user's unique ID using the Set Customer ID action.
Purchase a subscription (package) using the Purchase Package action.
Verify the user's subscription whenever you need to check their entitlement status, using the RevenueCat - Verify Subscription action.
If purchases aren't working, check the Latest Error state on the Natively - Purchases element for details.
You can also use the RevenueCat API directly for other purposes, such as independent validation of purchases.





Fetch the customer from RevenueCat's REST API using your Secret API Key and check whether the relevant entitlement is active.
This action requires your RevenueCat Secret API Key - a different key from the Public API Keys used in Natively Dashboard Setup. Find it under RevenueCat App > API keys > Secret API keys, and confirm you're using an API Key V1 - other versions won't work.
This call must always happen server-side. Never expose your Secret API Key in frontend code - anyone with it could query or manipulate subscriber data for your entire project.
The response includes a subscriber.entitlements object, keyed by entitlement identifier. Check whether the entitlement you care about is present, and its expires_date is null or in the future:
For a more real-time, scalable setup, RevenueCat also supports webhooks that notify your backend the moment a subscription's state changes - useful if you want to keep your own database in sync rather than checking RevenueCat on every request. See RevenueCat's webhook documentation if you want to build this.
Testing
Never use real payment methods to test purchases - always use sandbox/test accounts.
Test on Android - follow RevenueCat's Testing purchases in Play Store Sandbox guide for a full walkthrough.
Test on iOS - follow RevenueCat's Testing purchases in App Store Sandbox guide for a full walkthrough.
Troubleshooting
Purchases fail, or the paywall doesn't open
Go through this checklist:
Check the Debug Console. Open the Debug Console to inspect the actual error.
Confirm you're using the correct Public API Key. Use your App Store (
appl_...) or Play Store (goog_...) key in the Natively Dashboard - not the RevenueCat Test Store key.Confirm iOS payment setup is fully complete. Sandbox purchases fail if your Tax and Banking forms in App Store Connect aren't Clear, even with a signed Paid Applications Agreement.
Confirm Play Service Credentials have propagated. New Google Play Service Account credentials can show "Invalid Play Store credentials" for up to 36 hours after being generated.
Restore Purchases returns success, but the website doesn't reflect the access
A successful restore only confirms that RevenueCat recognized prior purchases; your app must still call your backend to re-verify entitlement status and update the UI accordingly. Don't unlock features directly from the restore callback alone.
Android upgrade/downgrade fails, or Google Play shows a duplicate subscription instead of a plan change
Confirm oldProductId is the real store Product ID (e.g. com.company.app.premium:monthly), not a package ID like $rc_monthly. Retrieve the correct value from platformProductId in getOfferings()'s response or from the RevenueCat Products section.
Last updated