How to add subscriptions to a Bolt-generated Expo app

Want to add in-app subscriptions to your Bolt app? This guide shows how to build a working paywall UI using prompts only, then integrate RevenueCat to handle real purchases and entitlements on Android using EAS Build.

Perttu Lähteenlahti
Published

Key summary: Bolt-generated apps previewed in Expo Go cannot support RevenueCat subscriptions due to missing native modules. To enable in-app purchases, developers must export the project, configure EAS Build, and install the RevenueCat SDK locally. Subscription products should be created in Google Play Console, linked to RevenueCat, and assigned to offerings. Subscriptions are then managed via entitlement checks, which control gated content access. Building with EAS enables full subscription functionality for production Android apps.

In this guide we are going to look at how to add in-app purchases, meaning simple monthly and yearly subscription, into the Expo React Native app we have created with Bolt. We are also going to add a paywall to block users from accessing part of the content in the app, and implement a logic for checking that the user is eligible for accessing content. 

We are first going to create our project with Bolt, from which you can then start making your own changes to the apps. In this guide we are going to build only the Android version of the app, but this setup will also work with building an iOS version and adding in-app purchases into it.

Step 1: Creating your Bolt app with prompts

As the first step let’s open open bolt.new and give the following prompt to get things started:

1I'm building a mobile app for browsing cat pictures. The app should have two tabs: Feed and Profile.
2
3In the Feed tab:
4	- Display a vertical scrollable list of 15 cat images.
5	- Only the first 2 images should be fully visible. The remaining 13 images must have a semi-transparent overlay with the text:
6"Subscribe to unlock" centered over the image.
7	- Tapping on a locked image should present a paywall screen, built using components that would integrate with the react-native-purchases package.
8	- Do not install or import react-native-purchases. Instead, insert a comment like:
9// place react-native-purchases integration here
10wherever subscription logic or hooks would be placed.
11
12In the Profile tab:
13	- Show a simple text indicator of the user's subscription status (e.g., "You are subscribed" / "Not subscribed").
14	- Assume subscription state is available from react-native-purchases, but again, do not install or implement the package—just include comments where the integration would go.
15
16Additional Constraints
17	- Do not include installation instructions or unrelated boilerplate.
18	- Avoid backend integration or data persistence; fake/mock data is acceptable.
19	- Prioritize clean layout and separation of concerns. Use well-named components for Feed, Profile, Paywall, and OverlayedImage.
20	- Make the app previewable in Expo Go—only use packages that are compatible with Expo Go.
21	- For the paywall screen, include UI elements like product name, price, a "Subscribe" button, and a dismiss button.
22	- Ensure app state reflects the locked/unlocked state of content based on a boolean variable like isSubscribed.

Why not just add subscriptions as part of the prompt?

This prompt should provide you with a working app that has all the UI parts for having subscriptions. If you navigate around the application, you should see that everything works but when you try to press the subscribe button, nothing happens. This is by design as we don’t yet want to call actual subscription methods.

You might have noticed that the prompt we used explicitly tells Bolt not to add a package called react-native-purchases. This is RevenueCat’s React Native SDK which is needed for in-app purchases. The reason why we can’t just add this package through Bolt, is because for displaying the preview of our app Bolt uses an app called Expo Go. The Expo Go preview app that displays our app comes bundled with native modules that allow for extensive but finite interactions with native code. This means that you can for example build complex views or interact with native device features like the camera. However, it lacks the native modules that are needed for in-app purchases. Because of this, when we install a new dependency like react-native-purchases from RevenueCat that has native code changes, we might run into problems when using Bolt. However, we can solve these problems by deploying our app with Expo Application Services.

You now have a working app which you have created with Bolt. When you open the preview of the app everything all functionalities except subscriptions should work at this point. You can continue using Bolt to add more features to your app, but do not yet touch any of the subscriptions parts of the code produced by Bolt. Once you are happy with the app you have created, continue to the next section to learn about deploying your app using Expo Application Services (EAS).

Step 2: Switch from Expo Go to EAS Build

Now that our app has the basic UI for subscriptions in place, we can integrate the actual subscription logic using the react-native-purchases SDK from RevenueCat. Since the SDK includes native code, and our app uses Expo, we need to configure it to work with EAS Build, Expo’s custom build service.

To get started download the project you have created with Bolt to your computer and open it in your IDE of your choice (e.g., VS Code, Cursor). You will also need the command line so open that as well.

Preparing Expo for native modules

To enable native code in an Expo project, we need to switch from Expo Go to EAS Build. This is required for react-native-purchases and any other library that depends on native modules.

Follow the official Bolt Expo integration guide to configure your app. The key steps are:

1. Install eas-cli if you haven’t already:  

1npm install -g eas-cli

2. Log in and configure the project:

1eas login
2eas build:configure

3. Once configured, use eas build instead of expo start to build your project for iOS or Android:

1eas build -platform android

This will create a production build of your application that you can then submit to the Play Store console. If you run into any errors or need additional support, check out Expo’s guide for creating production builds for Android

We have now a working production version of our app for Android that we can start adding subscriptions into. Before we do that we need to first set up Google Play Console and RevenueCat, connect these two, and add products for our users to purchase.

Step 3: Set Up Products in Google Play and RevenueCat

Before we work on enabling subscriptions for our app, let’s set up RevenueCat and configure our products. In this tutorial we are only going to configure products for the Play Store so that we can have working Android apps at the end of these tutorials.

Start by creating a new RevenueCat account at revenuecat.com. Getting started with RevenueCat is free. 

You should now have your RevenueCat account set up and ready to go. If you’re interested in serving iOS users, a part that this guide does not cover, be sure to check out our iOS subscriptions guide for linking App Store Connect and RevenueCat together. Otherwise, jump ahead to the next section to work on Google Play integration.

First we need to connect our Google Play account to the RevenueCat dashboard, which will allow RevenueCat’s servers to communicate with Google Play Store on your behalf. To do this we need to provide RevenueCat with a set of service credentials. The process for configuring all of these is a bit complex, but this is all done to give RevenueCat with only the absolutely necessary access; allowing us to keep security level high.

To get access to the Google Play console, where all your distributed apps will live, you need to sign up for a Google Play developer account, which currently costs a one time fee of 25$. Learn more about setting up a Play Console developer account from Google’s official documentation.

Once you’ve set up your Play Console account, follow RevenueCat’s detailed guide to doing the setup between Google Play console and RevenueCat. 

You should now have a Google Play Console developer account, which is configured to work with RevenuCat. We are not ready to add products into Google Play Console.

Configuring Google Play with our Products

With our RevenueCat account connected to the Google Play Store, we’re now ready to configure in-app subscriptions for our app.

1. Add Subscriptions in Google Play Console

First, log into the Google Play Console, select your application, and navigate to Monetize > Products > Subscriptions in the sidebar.

Click the Create subscription button and configure your pricing and billing periods (e.g., monthly and yearly). Be sure to take note of the Product ID for each subscription—you’ll need this when connecting your app to RevenueCat.

For more detailed information follow our Google Play product setup guide.

2. Import Products into RevenueCat

Now that your subscription products are live in the Google Play Console, head back to the RevenueCat dashboard.

Navigate to your project’s Products tab and click + New > Import Products. RevenueCat will automatically fetch your available subscriptions from Google Play. Select the ones you want to import and click Import. Your subscriptions will now appear in your RevenueCat project, ready to use.

3. Create an Offering

Offerings in RevenueCat are how you define which products to show in your app. This makes it easy to test pricing, paywalls, and product combinations—all without needing to update your app.

Go to the Offerings tab and click + New to create your first offering. You’ll assign the products (like your monthly and yearly subscriptions) to this offering, which your app will reference when displaying a paywall.

Follow the steps in RevenueCat’s Offering documentation to complete setup.

You should now have all the RevenueCat and Google Play Console configured with subscriptions. Before continuing with the guide, navigate to the API keys section of RevenueCat dashboard and copy the Android SDK key. We will need this in the next step to connect our app to RevenueCat.

Step 4: Install and Configure RevenueCat

To install the RevenueCat SDK, run:

1npx expo install react-native-purchases

Initializing the RevenueCat SDK

You can now initialize RevenueCat in your app. This is typically done once when your app starts. Creating our app with Bolt should have created a commented section where to place the following code parts in our app. Most likely it is in a file called _layout.tsx

1// place these at the top of the file in _layout.tsx or similar
2import Purchases from 'react-native-purchases';
3import { useEffect } from 'react';
4
5//... paste these inside the export default function Layout or similar, after // the '{' bracket but before the 'return (' part
6
7useEffect(() => {
8  Purchases.configure({
9    apiKey: PLACE_YOUR_API_KEY_HERE
10  });
11}, []);
12

Paste the API key you copied in the previous section of this guide into the apiKey part, to enable your app to interact with RevenueCat’s servers.

Step 5: Add purchase logic to the UI

To check if the user has an active subscription, query getCustomerInfo() and look for an active entitlement:

1const [isSubscribed, setIsSubscribed] = useState(false);
2
3useEffect(() => {
4  const checkSubscription = async () => {
5    try {
6      const customerInfo = await Purchases.getCustomerInfo();
7      const activeEntitlement = customerInfo.entitlements.active['pro'];
8      setIsSubscribed(!!activeEntitlement);
9    } catch (e) {
10      console.warn('Failed to fetch subscription status:', e);
11    }
12  };
13
14  checkSubscription();
15}, []);

Use this in both the Feed and Profile tabs to reflect the user’s subscription status.

Implementing the paywall logic

Now we can update the paywall screen to show available offerings and handle purchases:

1import Purchases from 'react-native-purchases';
2
3const [offering, setOffering] = useState(null);
4
5useEffect(() => {
6  const loadOfferings = async () => {
7    try {
8      const offerings = await Purchases.getOfferings();
9      if (offerings.current) {
10        setOffering(offerings.current);
11      }
12    } catch (e) {
13      console.warn('Failed to fetch offerings:', e);
14    }
15  };
16
17  loadOfferings();
18}, []);
19
20const handlePurchase = async () => {
21  try {
22    if (!offering || offering.availablePackages.length === 0) return;
23
24    const { customerInfo } = await Purchases.purchasePackage(offering.availablePackages[0]);
25    const activeEntitlement = customerInfo.entitlements.active['pro'];
26
27    if (activeEntitlement) {
28      navigation.goBack();
29    }
30  } catch (e) {
31    if (!e.userCancelled) {
32      console.warn('Purchase failed:', e);
33    }
34  }
35};
36

This fetches the product offerings from RevenueCat and initiates a purchase flow. After a successful purchase, the entitlement is checked and the paywall is dismissed if the subscription is active.

Updating the feed to reflect entitlements

Finally, use the isSubscribed flag in your Feed screen to lock or unlock content:

1<OverlayedImage
2  source={item.uri}
3  locked={!isSubscribed && index >= 2}
4  onPress={() => navigation.navigate('Paywall')}
5/>
6

This ensures that only subscribed users can access the full list of cat pictures.

Conclusion

With the RevenueCat and Google Play Console set up, the RevenueCat SDK integrated, and the necessary code changes made to our Bolt created app our app is now ready to accept and react to users subscribing. Create a new EAS build of your application with the same command we used before to create the first build of our app. Once the build finishes processing, test your app and the subscriptions. If you run into any problems, check that you have placed the code provided in the correct places. These guides can also possibly help you:

As the next step you might want to build an iOS version of your app and enable subscriptions for it as well. For that you only need an Apple Developer account and RevenueCat’s App Store Connect setup guide. Since Expo apps are multi-platform by default, you do not need to make any changes to the code we added in this guide.

You might also like

Share this post

Want to see how RevenueCat can help?

RevenueCat enables us to have one single source of truth for subscriptions and revenue data.

Olivier Lemarié, PhotoroomOlivier Lemarié, Photoroom
Read Case Study