npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-billing-sdk

v0.5.1

Published

Implementation of Android Billing Client v8.0

Readme

React Native Billing SDK

npm version License: MIT

A React Native library that exposes the native Google Play Billing Library functionality, implementing the latest Android Billing Client v8.0 for handling in-app purchases and subscriptions.

✅ Latest Version: This library uses Billing Library 8.0, which exceeds Google's requirement for version 7+ by the August 31, 2025 deadline and includes the latest features and security improvements.

Features

  • 🛒 One-Time Products - Handle consumable and non-consumable in-app purchases
  • 🔄 Subscriptions - Complete subscription lifecycle with grace periods, hold states, and renewals
  • 📱 Latest Android Billing - Direct access to Google Play Billing Library v8.0 APIs
  • 🎯 TypeScript Support - Full type safety with comprehensive TypeScript definitions
  • Real-Time Updates - Purchase state changes and billing service events
  • 🔧 Simple Integration - React Native wrapper around native billing functionality
  • Pending Transactions - Support for delayed payment methods and pending states
  • 📊 Multi-Quantity - Handle multiple quantities of the same product in one purchase

Platform Support

| Platform | Status | |----------|--------| | Android | ✅ Full support (Billing Client v8.0) | | iOS | ❌ Not implemented yet |

Installation

npm install react-native-billing-sdk
# or
yarn add react-native-billing-sdk

Android Setup

  1. Add BILLING permission to your android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="com.android.vending.BILLING" />
  1. Configure your app in Google Play Console with in-app products/subscriptions.

iOS Setup

iOS support is not yet implemented. The library will reject calls on iOS with "Unsupported platform" error.

Purchase Lifecycle

Following the official Google Play Billing flow, this library supports the complete purchase lifecycle:

  1. Show Products - Query and display available products to users
  2. Launch Purchase - Initiate the billing flow for user acceptance
  3. Verify Purchase - Validate purchases on your server (recommended)
  4. Deliver Content - Provide the purchased content to the user
  5. Acknowledge Purchase - Confirm delivery for non-consumables or consume for consumables

Subscription States

Subscriptions can transition through various states as defined in the Android Billing documentation:

  • Active - User has access and subscription is in good standing
  • Cancelled - User cancelled but retains access until expiration
  • Grace Period - Payment issue occurred, user retains access while Google retries payment
  • On Hold - Payment issue occurred, user loses access while Google retries payment
  • Paused - User paused their subscription access

Usage

Basic Setup

import { BillingSdkAndroid, BillingSdkAndroidConstants } from 'react-native-billing-sdk';

// Initialize billing connection
const initializeBilling = async () => {
  try {
    await BillingSdkAndroid.startConnection();
    console.log('Billing client connected');
  } catch (error) {
    console.error('Failed to connect billing client:', error);
  }
};

// Set up purchase listener
const removePurchaseListener = BillingSdkAndroid.setPurchaseUpdatedListener(
  ({ responseCode, purchases, debugMessage }) => {
    if (responseCode === BillingSdkAndroidConstants.ResponseCode.OK && purchases) {
      purchases.forEach(purchase => {
        console.log('Purchase received:', purchase);
        // Handle purchase (acknowledge, consume, etc.)
      });
    } else {
      console.error('Purchase failed:', debugMessage);
    }
  }
);

// Clean up listeners when component unmounts
return () => {
  removePurchaseListener();
};

Querying Products

// Query in-app products
const queryProducts = async () => {
  try {
    const products = await BillingSdkAndroid.queryProductDetails(
      ['your_product_id_1', 'your_product_id_2'],
      BillingSdkAndroidConstants.ProductType.INAPP
    );
    
    products.forEach(product => {
      console.log(`Product: ${product.title}`);
      console.log(`Price: ${product.oneTimePurchaseOfferDetails?.formattedPrice}`);
    });
  } catch (error) {
    console.error('Failed to query products:', error);
  }
};

// Query subscriptions
const querySubscriptions = async () => {
  try {
    const subscriptions = await BillingSdkAndroid.queryProductDetails(
      ['your_subscription_id'],
      BillingSdkAndroidConstants.ProductType.SUBS
    );
    
    subscriptions.forEach(subscription => {
      console.log(`Subscription: ${subscription.title}`);
      subscription.subscriptionOfferDetails?.forEach(offer => {
        console.log(`Offer: ${offer.pricingPhases[0]?.formattedPrice}`);
      });
    });
  } catch (error) {
    console.error('Failed to query subscriptions:', error);
  }
};

Making Purchases

// Purchase an in-app product
const purchaseProduct = async (productId: string) => {
  try {
    await BillingSdkAndroid.launchBillingFlow(productId);
    // Purchase result will be delivered to setPurchaseUpdatedListener
  } catch (error) {
    console.error('Failed to launch billing flow:', error);
  }
};

// Purchase a subscription with specific offer
const purchaseSubscription = async (productId: string, offerToken: string) => {
  try {
    await BillingSdkAndroid.launchBillingFlow(productId, offerToken);
  } catch (error) {
    console.error('Failed to launch billing flow:', error);
  }
};

// Upgrade/downgrade subscription
const changeSubscription = async (
  newProductId: string,
  newOfferToken: string,
  oldPurchaseToken: string
) => {
  try {
    await BillingSdkAndroid.launchBillingFlow(
      newProductId,
      newOfferToken,
      oldPurchaseToken,
      BillingSdkAndroidConstants.SubscriptionReplacementMode.CHARGE_PRORATED_PRICE
    );
  } catch (error) {
    console.error('Failed to change subscription:', error);
  }
};

Managing Purchases

// Acknowledge a purchase (required for non-consumable products)
const acknowledgePurchase = async (purchaseToken: string) => {
  try {
    await BillingSdkAndroid.acknowledgePurchase(purchaseToken);
    console.log('Purchase acknowledged');
  } catch (error) {
    console.error('Failed to acknowledge purchase:', error);
  }
};

// Consume a purchase (for consumable products)
const consumePurchase = async (purchaseToken: string) => {
  try {
    await BillingSdkAndroid.consume(purchaseToken);
    console.log('Purchase consumed');
  } catch (error) {
    console.error('Failed to consume purchase:', error);
  }
};

// Query active purchases
const queryActivePurchases = async () => {
  try {
    const purchases = await BillingSdkAndroid.queryPurchases(
      BillingSdkAndroidConstants.ProductType.INAPP
    );
    
    purchases.forEach(purchase => {
      console.log(`Active purchase: ${purchase.productId}`);
      
      if (!purchase.isAcknowledged) {
        // Acknowledge if needed
        acknowledgePurchase(purchase.purchaseToken);
      }
    });
  } catch (error) {
    console.error('Failed to query purchases:', error);
  }
};

// Query purchase history
const queryPurchaseHistory = async () => {
  try {
    const history = await BillingSdkAndroid.queryPurchaseHistory(
      BillingSdkAndroidConstants.ProductType.INAPP
    );
    
    history?.forEach(record => {
      console.log(`Past purchase: ${record.productId} at ${record.purchaseTime}`);
    });
  } catch (error) {
    console.error('Failed to query purchase history:', error);
  }
};

Handling Pending Transactions

As per Google's documentation, some payment methods may result in pending transactions that complete asynchronously:

// Handle pending purchases in your purchase listener
const removePurchaseListener = BillingSdkAndroid.setPurchaseUpdatedListener(
  ({ responseCode, purchases, debugMessage }) => {
    if (responseCode === BillingSdkAndroidConstants.ResponseCode.OK && purchases) {
      purchases.forEach(purchase => {
        switch (purchase.purchaseState) {
          case BillingSdkAndroidConstants.PurchaseState.PURCHASED:
            // Purchase completed - deliver content and acknowledge
            console.log('Purchase completed:', purchase.productId);
            deliverContent(purchase);
            if (!purchase.isAcknowledged) {
              BillingSdkAndroid.acknowledgePurchase(purchase.purchaseToken);
            }
            break;
            
          case BillingSdkAndroidConstants.PurchaseState.PENDING:
            // Payment is pending - inform user and wait
            console.log('Purchase pending:', purchase.productId);
            showPendingPaymentUI(purchase);
            // Do NOT acknowledge pending purchases
            break;
            
          case BillingSdkAndroidConstants.PurchaseState.UNSPECIFIED_STATE:
            console.log('Unknown purchase state:', purchase.productId);
            break;
        }
      });
    }
  }
);

Important: Only acknowledge purchases when purchaseState is PURCHASED. The 3-day acknowledgment window begins only when the purchase transitions from PENDING to PURCHASED.

Connection Management

// Check connection state
const checkConnection = async () => {
  try {
    const state = await BillingSdkAndroid.getConnectionState();
    console.log('Connection state:', state);
    
    if (state !== BillingSdkAndroidConstants.ConnectionState.CONNECTED) {
      await BillingSdkAndroid.startConnection();
    }
  } catch (error) {
    console.error('Connection check failed:', error);
  }
};

// Handle disconnection
const removeDisconnectionListener = BillingSdkAndroid.setBillingServiceDisconnectedListener(() => {
  console.log('Billing service disconnected, attempting to reconnect...');
  BillingSdkAndroid.startConnection();
});

// End connection when done
const cleanup = async () => {
  await BillingSdkAndroid.endConnection();
  removeDisconnectionListener();
};

API Reference

Methods

| Method | Description | Parameters | Returns | |--------|-------------|------------|---------| | startConnection() | Establishes connection to Google Play Billing | None | Promise<void> | | endConnection() | Terminates the billing connection | None | Promise<void> | | getConnectionState() | Gets current connection state | None | Promise<ConnectionState> | | queryProductDetails() | Retrieves product/subscription details | productIds: string[], productType: ProductType | Promise<ProductDetails[]> | | launchBillingFlow() | Initiates purchase flow | productId: string, offerToken?: string, oldPurchaseToken?: string, replacementMode?: SubscriptionReplacementMode | Promise<void> | | acknowledgePurchase() | Acknowledges a purchase | purchaseToken: string | Promise<void> | | consume() | Consumes a purchase | purchaseToken: string | Promise<void> | | queryPurchases() | Gets active purchases | productType: ProductType | Promise<Purchase[]> | | queryPurchaseHistory() | Gets purchase history | productType: ProductType | Promise<PurchaseHistoryRecord[]> |

Event Listeners

| Listener | Description | Callback Parameters | |----------|-------------|-------------------| | setPurchaseUpdatedListener() | Listens for purchase updates | { responseCode, purchases, debugMessage } | | setBillingServiceDisconnectedListener() | Listens for service disconnection | None |

Constants

ProductType

  • INAPP - In-app products
  • SUBS - Subscriptions

PurchaseState

  • PURCHASED - Purchase completed
  • PENDING - Purchase pending
  • UNSPECIFIED_STATE - Unknown state

ConnectionState

  • DISCONNECTED - Not connected
  • CONNECTING - Connecting
  • CONNECTED - Connected
  • CLOSED - Connection closed

ResponseCode

  • OK - Success
  • USER_CANCELLED - User cancelled
  • SERVICE_UNAVAILABLE - Service unavailable
  • BILLING_UNAVAILABLE - Billing unavailable
  • ITEM_UNAVAILABLE - Item unavailable
  • DEVELOPER_ERROR - Developer error
  • ERROR - General error
  • And more...

Error Handling

This library exposes the native Google Play Billing response codes. All API calls should be wrapped in try-catch blocks to handle various error conditions:

try {
  await BillingSdkAndroid.startConnection();
} catch (error) {
  switch (error.code) {
    case BillingSdkAndroidConstants.ResponseCode.BILLING_UNAVAILABLE:
      console.log('Billing not available on this device');
      break;
    case BillingSdkAndroidConstants.ResponseCode.SERVICE_UNAVAILABLE:
      console.log('Google Play Store service is unavailable');
      break;
    case BillingSdkAndroidConstants.ResponseCode.USER_CANCELLED:
      console.log('User cancelled the purchase');
      break;
    case BillingSdkAndroidConstants.ResponseCode.ITEM_ALREADY_OWNED:
      console.log('User already owns this item');
      break;
    case BillingSdkAndroidConstants.ResponseCode.DEVELOPER_ERROR:
      console.error('Developer error - check your configuration');
      break;
    default:
      console.error('Billing error:', error.message);
  }
}

Common Error Scenarios

  • BILLING_UNAVAILABLE - Device doesn't support billing (e.g., emulator without Google Play)
  • SERVICE_UNAVAILABLE - Google Play Store is not available or outdated
  • ITEM_UNAVAILABLE - Product ID not found in Google Play Console
  • DEVELOPER_ERROR - App not properly configured in Google Play Console

Testing

Follow the official testing guidelines from Google:

Test Environments

  1. Google Play Console Test Tracks - Use internal/closed testing tracks
  2. Test Accounts - Add test accounts in Google Play Console
  3. License Testing - Test with special license testing accounts
  4. Test Products - Create test products that won't charge real money

Testing Pending Transactions

You can test pending transactions using license testing with special test payment methods that simulate delayed payment completion or cancellation.

Test Cards and Payment Methods

  • Use test credit cards provided by Google for different scenarios
  • Test various payment methods including those that result in pending states
  • Verify proper handling of declined payments and cancellations

Important: Always test your complete purchase flow including server-side verification before releasing to production.

Requirements

  • React Native >= 0.60
  • Android API level 21+
  • Google Play Billing Library 8.0+
  • Node.js >= 16.0.0

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.

Official Google Documentation

This library is a React Native wrapper around the native Google Play Billing Library. For comprehensive information about billing concepts, best practices, and advanced features, refer to the official documentation:

Support

Author

Kaan Çembertaş - @kaancembertas


Made with ❤️ for the React Native community