Best React Native in-app subscription libraries
Tags: reactnative, webdev
Published: 2023-09-07 15:48:15

**Written by [Emmanuel John](https://blog.logrocket.com/author/emmanueljohn/)✏️**

Implementing in-app subscription purchases (IASP) is one of the key ways you can earn money from your mobile application. With IAP, you can easily monetize your app’s features, and content, and even offer digital products for sale. 

React Native offers different libraries built on top of both Apple’s [StoreKit framework](https://developer.apple.com/storekit/) and the [Google Play Billing Library](https://developer.android.com/google/play/billing/integrate), which helps simplify IAP integration in mobile apps. In this article, we’ll explore a selection of some of the best IAP libraries for implementing in-app subscriptions in your React Native application. 

_Jump ahead:_

*   [Choosing the right React Native in-app purchase subscription library](#choosing-right-react-native-in-app-purchase-subscription-library)
*   [react-native-iap](#react-native-iap)
*   [react-native-adapty](#react-native-adapty)
*   [expo-in-app-purchases](#expo-in-app-purchases)
*   [react-native-purchases](#react-native-purchases)
*   [react-native-qonversion](#react-native-qonversion)
*   [Comparison summary](#comparison-summary)

## Choosing the right React Native in-app purchase subscription library <a name="choosing-right-react-native-in-app-purchase-subscription-library">

When deciding on which IAP library to use in your application, there are several factors you need to consider, including the following:

*   **Documentation and support**: You should generally go for libraries that have up-to-date and comprehensive documentation to ensure a smooth integration process. Additionally, check if there is an active support channel or community that will assist you in case of any issues or questions
*   **Features offered**: Assess the features provided by a library and determine if they align with your requirements. For instance, you may need a library that can handle receipt validation, dynamic product listings, refunds, and so on
*   **Security and** **compliance**: Consider the security measures a library’s developer has put in place to ensure adequate protection of user data, secure payment processing, and adherence to relevant store guidelines
*   **Flexibility**: Assess whether the library is flexible in terms of localization, UI customization, pricing models, and integration with third-party tools
*   **Restoration and synchronization**: Consider whether the library supports restoring purchases across devices and platforms. This feature allows users to regain access to previously purchased content or services when switching devices or reinstalling the application

## react-native-iap <a name="react-native-iap">

*   GitHub stars: 2.4k
*   Weekly downloads: 25k+
*   [GitHub repository](https://github.com/dooboolab-community/react-native-iap#readme)
*   [Documentation](https://react-native-iap.dooboolab.com/)

[react-native-iap](https://www.npmjs.com/package/react-native-iap) is a popular IAP library developed and maintained by [dooboolab](https://dooboolab.com/). It supports in-app subscription implementation for the App Store, Play Store, and Amazon Appstore. 

react-native-iap provides a set of Hooks and exposes a set of APIs for processing product purchases and subscriptions, listening for completed and failed transactions, and fetching your product listing. 

However, react-native-iap does not support receipt validation, so you must verify transactions on your backend. 

Prior to integrating the `react-native-iap` library, you need to configure and create your product catalog with unique identifiers in the respective stores; react-native-iap uses these IDs to fetch your product listing. 

You can install react-native-iap through npm:

```bash
npm install react-native-iap
```

Afterward, follow the installation instructions outlined in the documentation for both [Android](https://react-native-iap.dooboolab.com/docs/get-started#android) and [iOS](https://react-native-iap.dooboolab.com/docs/get-started#ios) to complete the configuration process. 

Example usage:

```javascript
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View, Platform, Pressable } from 'react-native';
import {
  initConnection,
  endConnection,
  finishTransaction,
  flushFailedPurchasesCachedAsPendingAndroid,
  purchaseUpdatedListener,
  purchaseErrorListener,
  getProducts,
  requestPurchase,
} from 'react-native-iap'
const App = () => {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    const initializeConnection = async () => {
      try {
        await initConnection();
        if (Platform.OS === "android") {
          await flushFailedPurchasesCachedAsPendingAndroid();
        }
      } catch (error) {
        console.error("An error occurred", error.message);
      }
    }
    const purchaseUpdate = purchaseUpdatedListener(
      async (purchase) => {
        const receipt = purchase.transactionReceipt;

        if (receipt) {
          try {
            await finishTransaction({ purchase, isConsumable: true });
          } catch (error) {
            console.error("An error occurred", error.message);
          }
        }
      });

    const purchaseError = purchaseErrorListener((error) =>
      console.error('Purchase error', error.message));
    initializeConnection();
    purchaseUpdate();
    purchaseError();
    fetchProducts();
    return () => {
      endConnection();
      purchaseUpdate.remove();
      purchaseError.remove();
    }
  }, []);

  const fetchProducts = async () => {
    try {
      const products = await getProducts({
        skus: Platform.select({
          ios: ['com.rniap.product10', 'com.rniap.product20'],
          android: ['com.rniap.product100', 'com.rniap.product200'],
        })
      });
      setProducts(products);
    } catch (error) {
      console.error("Error occurred while fetching products", error.message);
    }
  };
  const makePurchase = async (sku) => {
    try {
      requestPurchase({ sku })
    } catch (error) {
      console.error("Error making purchase", error.message);
    }
  }

  return (
    <View style={styles.container}>
      {
        products.map((product) => (
          <View key={product.productId} style={styles.row}>
            <Text>{product.title}</Text>
            <Pressable onPress={() => makePurchase(product.productId)}>Buy Product</Pressable></View>
        ))
      }
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 10
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 16,
    marginEnd: 20
  }
});
export default App;
```

This code snippet sets up the necessary connections and listeners for in-app purchases, fetches products from the store, and allows the user to make purchases by pressing a button for each product displayed on the screen. 

The `initializeConnection` function initializes the in-app purchase connection using the `initConnection` function. If the platform is Android, it also flushes any failed purchases that are cached as pending using `flushFailedPurchasesCachedAsPendingAndroid`. 

The `purchaseUpdate` function is a listener that is triggered when a purchase is updated. It calls the `finishTransaction` function to finish the transaction after a successful purchase. The `purchaseError` function is a listener that is triggered when a purchase error occurs.

## react-native-adapty <a name="react-native-adapty">

*   GitHub stars: 88
*   Weekly downloads: 900+
*   [GitHub repository](https://github.com/adaptyteam/AdaptySDK-React-Native#readme)
*   [Documentation](https://docs.adapty.io/docs/react-native-installation?utm_source=github&utm_medium=referral&utm_campaign=AdaptySDK-React-Native)

The `react-native-adapty` library allows you to integrate in-app subscriptions into your React Native applications seamlessly. It provides a comprehensive set of features you‘d typically need to manage subscriptions, such as A/B testing, free trials, refunds, renewals, upgrades, downgrades, one-time purchases, and lifetime subscriptions. react-native-adapty can be used in both Expo-managed and native React Native workflows. 

In addition, it offers an intuitive dashboard where you can track performance metrics, view users’ payment history, customize UI elements, and manage product listings without releasing new versions of your application. 

To begin using react-native-adapty, you need to create an [Adapty account](https://app.adapty.io/registration) and then [register your application](https://docs.adapty.io/docs/quickstart), after which you will get your public SDK key for use in your application. You can install the react-native-adapty SDK using Yarn:

```bash
yarn add react-native-adapty
```

After installation, follow the [instructions described in the documentation](https://docs.adapty.io/docs/react-native-installation#pure-react-native) to complete installation for both Android and iOS. 

Example usage:

```javascript
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View, Pressable } from 'react-native';
import { adapty } from 'react-native-adapty';
const App = () => {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    const initialize = async () => {
      try {
        await adapty.activate("PUBLIC_SDK_KEY", {
          customerUserId: "USER_ID",
          logLevel: 'ERROR',
        });
      } catch (error) {
        console.error("An error occurred while activating adapty", error.message);
      }
    }

    initialize();
    fetchPaywall("paywall_id");
  }, []);

  //pawywallId is the id specified when creating a paywall in the adapty dashboard
  const fetchPaywall = async (paywallId) => {
    try {
      const paywallResult = await adapty.getPaywall(paywallId);
      const productResult = await adapty.getPaywallProducts(paywallResult);
      setProducts(productResult);
    } catch (error) {
      console.error("Error occured while fetching paywall", error.message);
    }
  };
  const makePurchase = async (product) => {
    try {
      await adapty.makePurchase(product)
    } catch (error) {
      console.error("Error making purchase", error.message);
    }
  }

  return (
    <View style={styles.container}>
      {
        products.map((product) => (
          <View key={product.vendorProductId} style={styles.row}>
            <Text>{product.localizedTitle}</Text>
            <Pressable onPress={() => makePurchase(product)}>Buy Product</Pressable></View>
        ))
      }
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 10
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 16,
    marginEnd: 20
  }
});
export default App;
```

Use the `adapty.makePurchase` method enables in-app purchases. The `fetchPaywall` function is an asynchronous function that fetches the paywall using the `adapty.getPaywall` method and then fetches the paywall products using the `adapty.getPaywallProducts` method. 

The `initialize` function is an asynchronous function that activates the Adapty SDK using the `adapty.activate` method. It takes a public SDK key, customer user ID, and log level as parameters. 

To use this code, you need to have the necessary dependencies installed, including the Adapty SDK. Additionally, you need to replace:

*   `"PUBLIC_SDK_KEY"` with your actual Adapty SDK public key
*   `"USER_ID"` with the customer user ID
*   `"paywall_id"` with the ID of the paywall you want to fetch

## expo-in-app-purchases <a name="expo-in-app-purchases">

*   GitHub stars: N/A, in-built Expo package
*   Weekly downloads: 4k+
*   [GitHub repository](https://github.com/expo/expo/tree/sdk-48/packages/expo-in-app-purchases)
*   [Documentation](https://docs.expo.dev/versions/latest/sdk/in-app-purchases/)

[expo-in-app-purchases](https://www.npmjs.com/package/expo-in-app-purchases) is a lightweight IAP library created by Expo, and is basically a wrapper for both the Apple StoreKit framework and Google Play Billing Library. It exposes a simple set of APIs for retrieving product listings, fetching user purchase history, handling purchases, and so on. It’s important to note that the library’s development is currently on hold at the time of writing this article. 

Before using the expo-in-app-purchases library, you should configure in-app purchases and product listing details in [App Store Connect](https://appstoreconnect.apple.com/) and the [Google Play console](https://developer.android.com/distribute/console/). 

Install the library through npm:

```bash
npm install expo-in-app-purchases
```

If you’re using an Expo-managed workflow, you will also have to create a development build. 

After installation, run the following command to perform additional configuration for iOS:

```bash
npx pod-install
```

Example usage:

```javascript
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View, Pressable, Platform } from 'react-native';
import * as InAppPurchases from 'expo-in-app-purchases';

const storeItems = Platform.select({
  ios: ['com.rniap.product10', 'com.rniap.product20'],
  android: ['com.rniap.product100', 'com.rniap.product200'],
});
const App = () => {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    const initializeConnection = async () => {
      try {
        await InAppPurchases.connectAsync();
      } catch (error) {
        console.error('Error initializing connection', error.message);
      }
    }
    initializeConnection();
    InAppPurchases.setPurchaseListener(purchaseListener);
    fetchProducts();
    return () => {
      InAppPurchases.disconnectAsync();
    }
  }, []);
  const purchaseListener = ({responseCode, results, errorCode}) => {
    if(responseCode === InAppPurchases.IAPResponseCode.OK) {
      results.forEach(purchase => {
        if(!purchase.acknowledged) {
          //Process transaction and unlock content for user
          InAppPurchases.finishTransactionAsync(purchase, true);
        }
      });
    }
  }

  const fetchProducts = async () => {
    try {
      const { responseCode, results } = await InAppPurchases.getProductsAsync(storeItems);
      if(responseCode === InAppPurchases.IAPResponseCode.OK) {
        setProducts(results);
      } 
    } catch (error) {
      console.error("Error occured while fetching products", error.message);
    }
  };
  const makePurchase = async (productId) => {
    try {
      await InAppPurchases.purchaseItemAsync(productId);
    } catch (error) {
      console.error("Error making purchase", error.message);
    }
  }

  return (
    <View style={styles.container}>
      {
        products.map((product) => (
          <View key={product.productId} style={styles.row}>
            <Text>{product.title}</Text>
            <Pressable onPress={() => makePurchase(product.productId)}>Buy Product</Pressable></View>
        ))
      }
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 10
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 16,
    marginEnd: 20
  }
});
export default App;
```

The `makePurchase` function is an asynchronous function that makes a purchase using the `purchaseItemAsync` method from the `expo-in-app-purchases` library. If an error occurs, it is logged to the console. `getProductsAsync` method from the `expo-in-app-purchases` fetches the products from the store. The `initializeConnection` function is an asynchronous function that attempts to connect to the in-app purchase service. 

To use this code, you need to have the necessary dependencies installed, including `expo-in-app-purchases`. Additionally, you need to set up in-app purchases for your app on both the iOS and Android platforms, and configure the product IDs accordingly.

## react-native-purchases <a name="react-native-purchases">

*   GitHub stars: 533
*   Weekly downloads: 15k+
*   [GitHub repository](https://github.com/revenuecat/react-native-purchases)
*   [Documentation](https://www.revenuecat.com/docs)

[react-native-purchases](https://www.npmjs.com/package/react-native-purchases) is a user-friendly IAP library developed and maintained by [RevenueCat](https://www.revenuecat.com/). It is a wrapper around the StoreKit framework, Google Play Billing Library, and the RevenueCat backend. However, if you’re using an Expo-managed workflow, you will need to create a [development build](https://docs.expo.dev/development/build/) as well. 

It has built-in support for receipt validation, subscription status tracking, analytics metrics, and webhooks, which you can use to set up notifications for specific purchase events. In addition, you can remotely configure your product listings from your dashboard, view users' transaction history, and easily integrate with third-party analytic tools. 

To get started with integrating react-native-purchases in your application, you first need to sign up for a [RevenueCat account](https://app.revenuecat.com/signup) and also [set up a new project](https://www.revenuecat.com/docs/projects#configure-a-new-project), and then proceed to add your application, after which you will obtain an API key for use in your project. 

You can install the react-native-purchases SDK through npm:

```bash
npm install react-native-purchases
```

After installation, you also have to perform some [additional configuration for iOS](https://www.revenuecat.com/docs/reactnative#additional-ios-setup). Additionally, remember to also include the “Billing” permission in your `AndroidManifest.xml` file.

```xml
<uses-permission android:name="com.android.vending.BILLING" />
```

Example usage:

```javascript
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View, Pressable } from 'react-native';
import Purchases from 'react-native-purchases';
const App = () => {
  const [packages, setPackages] = useState([]);

  useEffect(() => {
    Purchases.setLogLevel(Purchases.LOG_LEVEL.ERROR);
    const initialize = () => {
      Purchases.configure({
        apiKey: "API_KEY",
        appUserID: null,
        observerMode: false,
        useAmazon: false
      });
    }
    initialize();
    fetchPackages();
  }, []);

  const fetchPackages = async () => {
    try {
      const offerings = await Purchases.getOfferings()
      if(offerings.current !== null) {
        setPackages(offerings.current.availablePackages)
      }
    } catch (error) {
      console.error("Error occured while fetching packages", error.message);
    }
  };
  const makePurchase = async (pkg) => {
    try {
      const {customerInfo} = await Purchases.purchasePackage(pkg);
      if(typeof customerInfo.entitlements.active["ENTITLEMENT_ID"] !== 'undefined') {
        //do something
      }
    } catch (error) {
      if(!error.userCancelled) {    
      console.error("Error making purchase", error.message);
      }
    }
  }

  return (
    <View style={styles.container}>
      {
        packages.map((pkg) => (
          <View key={pkg.identifier} style={styles.row}>
            <Text>{pkg.title}</Text>
            <Pressable onPress={() => makePurchase(pkg)}>Buy Product</Pressable></View>
        ))
      }
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 10
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 16,
    marginEnd: 20
  }
});
export default App;
```

This code sets up a React Native app with a purchases integration for in-app purchases. It initializes purchases, fetches the available packages, and provides a UI to display and purchase those packages. 

A call to `Purchases.purchasePackage` initiates the purchase process. `Purchases.getOfferings` fetches the offerings. The `initialize` function configures purchases with the API key, `appUserID`, `observerMode`, and `useAmazon` properties using `Purchases.configure`. If an error occurs during configuration, it is logged to the console.

## react-native-qonversion

*   GitHub stars: 118
*   Weekly downloads: 600+
*   [GitHub repository](https://github.com/qonversion/react-native-sdk#readme)
*   [Documentation](https://documentation.qonversion.io/docs/quickstart)

react-native-qonversion is another notable IAP library that allows you to swiftly incorporate in-app subscriptions into your application, eliminating the need to set up a backend for receipt validation — this is all handled by Qonversion. 

You can also send users personalized push notifications triggered by purchase events, discover optimal pricing options via A/B tests, view detailed subscription analytics, share subscription data with your favorite analytics tool, handle both App Store and Play Store purchases, and so on. 

To begin integrating react-native-qonversion, you need to [create an account](https://dash.qonversion.io/site/signup) and proceed to [create a project](https://dash.qonversion.io/app/start/create) and register your application. After that, you can get your project key for use in your application. Also, don’t forget to create your IAP products on [App Store Connect](https://appstoreconnect.apple.com/) and the [Google Play console](https://play.google.com/apps/publish/)! 

The react-native-qonversion library can be installed through npm:

```bash
npm install react-native-qonversion
```

However, if you’re developing with Expo, you need to create a development build as well. 

Example usage:

```javascript
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View, Pressable } from 'react-native';
import Qonversion, {QonversionConfigBuilder, LaunchMode, Entitlement} from 'react-native-qonversion'
const config = new QonversionConfigBuilder(
  'PROJECT_KEY',
  LaunchMode.SUBSCRIPTION_MANAGEMENT
).build();
const App = () => {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    const initialize = () => {
      Qonversion.initialize(config);
    }
    initialize();
    fetchProducts();
  }, []);

  const fetchProducts = async () => {
    try {
      const offerings = await Qonversion.getSharedInstance().offerings();
      if(offerings.main != null && offerings.main.products.length > 0) {
        setProducts(offerings.main.products);
      }
    } catch (error) {
      console.error("Error occured while fetching products", error.message);
    }
  };
  const makePurchase = async (product) => {
    try {
      const entitlements = await Qonversion.getSharedInstance().purchaseProduct(product);
      if(entitlements !== null && entitlements['premium'].isActive) {
        //do something
      }
    } catch (error) {
      if(!error.userCanceled) {    
      console.error("Error making purchase", error.message);
      }
    }
  }

  return (
    <View style={styles.container}>
      {
        products.map((product) => (
          <View key={product.qonversionID} style={styles.row}>
            <Text>{product.qonversionID}</Text>
            <Pressable onPress={() => makePurchase(product)}>Buy Product</Pressable></View>
        ))
      }
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 10
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 16,
    marginEnd: 20
  }
});
export default App;
```

This code sets up a React Native app with Qonversion integration for subscription management. It initializes the Qonversion SDK, fetches the available products, and provides a UI to display and purchase those products. 

The `QonversionConfigBuilder` object is created using the `'PROJECT_KEY'` and `'LaunchMode.SUBSCRIPTION_MANAGEMENT'` values. This configures the `Qonversion` SDK with the appropriate project key and sets the launch mode to subscription management. 

A call to `Qonversion.getSharedInstance().purchaseProduct(product)` initiates the purchase process. `Qonversion.getSharedInstance().offerings()` fetches the product offerings.

## Comparison summary

The following table shows an overview of the features of each of the highlighted IAP libraries:

<table>

<thead>

<tr>

<th>Library</th>

<th>react-native-iap</th>

<th>react-native-adapty</th>

<th>expo-in-app-purchases</th>

<th>react-native-purchases</th>

<th>react-native-qonversion</th>

</tr>

</thead>

<tbody>

<tr>

<td>Stores supported</td>

<td>Apple App Store, Google Play Store, Amazon Appstore</td>

<td>Apple App Store and Google Play Store</td>

<td>Apple App Store and Google Play Store</td>

<td>Apple App Store, Google Play Store, and Amazon Appstore</td>

<td>Apple App Store and Google Play Store</td>

</tr>

<tr>

<td>Receipt validation</td>

<td>No</td>

<td>Yes</td>

<td>No</td>

<td>Yes</td>

<td>Yes</td>

</tr>

<tr>

<td>Supports A/B tests</td>

<td>No</td>

<td>Yes</td>

<td>No</td>

<td>Yes</td>

<td>Yes</td>

</tr>

<tr>

<td>No-code paywall</td>

<td>No</td>

<td>Yes</td>

<td>No</td>

<td>No</td>

<td>No</td>

</tr>

<tr>

<td>Dynamic paywall</td>

<td>No</td>

<td>Yes</td>

<td>No</td>

<td>Yes</td>

<td>Yes</td>

</tr>

<tr>

<td>Third-party integrations</td>

<td>No</td>

<td>Yes</td>

<td>No</td>

<td>Yes</td>

<td>Yes</td>

</tr>

<tr>

<td>Pricing</td>

<td>Free</td>

<td>Free up to $10,000 monthly tracked revenue (MTR)</td>

<td>Free</td>

<td>Free up to $10,000 MTR</td>

<td>Free up to $1,000 MTR</td>

</tr>

</tbody>

</table>

## Conclusion

In-app purchase is an important method of app monetization. When incorporating IAP in React Native applications, several libraries stand out for their robust features, flexibility, and cross-platform support. These libraries simplify the process of integrating IAP functionality and offer various capabilities such as purchasing products, verifying receipts, listing products, managing subscriptions, and so on. 

By harnessing the features provided by these libraries, you can streamline the integration of in-app purchases in your React Native application, enabling effective app monetization and enhancing the overall user experience.

---

##[LogRocket](https://lp.logrocket.com/blg/react-native-signup): Instantly recreate issues in your React Native apps.

[![LogRocket Signup](https://blog.logrocket.com/wp-content/uploads/2021/10/react-native-plug_v2-2.png)](https://lp.logrocket.com/blg/react-native-signup)

LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.

[LogRocket](https://lp.logrocket.com/blg/react-native-signup) also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your React Native apps — [try LogRocket for free](https://lp.logrocket.com/blg/react-native-signup).