Get Products, Offerings & Prices with RevenueCat

Overview

To show a paywall, you need to load the products you sell and display their prices. RevenueCat gives you two ways to do this: Offerings (the recommended path) and raw products fetched by id. An Offering is a set of Package objects you configure in the RevenueCat dashboard, and each package wraps a StoreProduct with a localized priceString.

The two APIs are:

  • getOfferings(): returns the offerings (and their packages) configured in the dashboard. Prefer this so you can change products without an app update.
  • getProducts([ids]): returns specific StoreProduct objects by store identifier. Use this only when you need a particular product by id.
Prefer Offerings over raw products. Because offerings are configured in the RevenueCat dashboard, you can swap which products you sell, run experiments, and adjust pricing tiers without shipping a new app build. Reach for getProducts only when you genuinely need a specific product by its store id.
Prerequisites: The RevenueCat SDK must already be installed and configured with configure(...). See the Configure the SDK guide and the platform tutorials (React Native, iOS, Android, Flutter) for setup.

Get the Current Offering

Call getOfferings() and read the current offering. The current offering is the one you marked as default in the dashboard. Its availablePackages array holds the packages you can present on a paywall.

typescript
// React Native (preferred): load the current offering
import Purchases from 'react-native-purchases';

const offerings = await Purchases.getOfferings();
const current = offerings.current;

if (current && current.availablePackages.length > 0) {
  const pkg = current.availablePackages[0];
  const priceLabel = pkg.product.priceString; // already localized, e.g. "$9.99"
  console.log('First package price:', priceLabel);
}

The same idea on each native platform:

swift
// iOS (Swift): load the current offering
let offerings = try await Purchases.shared.offerings()
if let pkg = offerings.current?.availablePackages.first {
    let label = pkg.storeProduct.localizedPriceString // e.g. "$9.99"
    print("First package price:", label)
}
kotlin
// Android (Kotlin): load the current offering
val offerings = Purchases.sharedInstance.awaitOfferings()
val pkg = offerings.current?.availablePackages?.firstOrNull()
val label = pkg?.product?.price?.formatted // localized price string, e.g. "$9.99"
println("First package price: $label")
dart
// Flutter (Dart): load the current offering
Offerings offerings = await Purchases.getOfferings();
final pkg = offerings.current?.availablePackages.first;
final label = pkg?.storeProduct.priceString; // localized price string, e.g. "$9.99"
print('First package price: $label');
current can be null. If no offering is marked as current in the dashboard, or the products are not approved on the store yet, offerings.current will be null and availablePackages can be empty. Always guard for these cases before reading a package.

Read the Package & Product Price

Each Package wraps a StoreProduct. The product holds the localized price string you should render directly in your UI. Below, the full list of packages is mapped to display values:

typescript
// React Native: build display rows for every package
const offerings = await Purchases.getOfferings();
const packages = offerings.current?.availablePackages ?? [];

const rows = packages.map((pkg) => ({
  packageId: pkg.identifier,                 // e.g. "$rc_monthly"
  productId: pkg.product.identifier,         // store product id
  title: pkg.product.title,                  // localized product title
  price: pkg.product.priceString,            // localized price, e.g. "$9.99"
}));

console.log(rows);

The priceString (called localizedPriceString on iOS and price.formatted on Android) is provided by the store and is already formatted for the user's region. Render it as-is.

Get Raw Products by ID

When you need a specific product by its store identifier (for example a one-off consumable that is not part of an offering), call getProducts. It returns an array of StoreProduct objects.

typescript
// React Native: fetch products by id
import Purchases, { PRODUCT_CATEGORY } from 'react-native-purchases';

const products = await Purchases.getProducts(
  ['my_product_id'],
  PRODUCT_CATEGORY.SUBSCRIPTION,
);

if (products.length > 0) {
  const product = products[0];
  console.log(product.identifier, product.priceString);
}
swift
// iOS (Swift): fetch products by id
let products = await Purchases.shared.products(["my_product_id"])
if let product = products.first {
    print(product.productIdentifier, product.localizedPriceString)
}
dart
// Flutter (Dart): fetch products by id
List<StoreProduct> products = await Purchases.getProducts(['my_product_id']);
if (products.isNotEmpty) {
  final product = products.first;
  print('${product.identifier} ${product.priceString}');
}
getProducts only returns approved products. A product id that is not configured and approved on the App Store or Google Play will simply be missing from the returned array. If the result is empty, double-check the product id, its store status, and your app bundle id.

StoreProduct Fields Reference

A StoreProduct exposes the same core information on every platform, though a few field names differ slightly. These are the fields you will use most:

What you want Field Notes
Product id identifier / productIdentifier The store product id. iOS uses productIdentifier.
Display name title Localized product title from the store.
Description description Localized product description from the store.
Raw price price A number. Useful for comparisons, not for display.
Localized price string priceString / localizedPriceString Already formatted, e.g. "$9.99". Display this. iOS uses localizedPriceString.
Currency currencyCode ISO currency code, e.g. "USD". Already baked into the price string.

On Android, the localized price is read through the price object as product.price.formatted. If you are unsure of an exact field name on a given platform, consult the official RevenueCat docs.

Always Use the Localized Price String

The single most important rule when displaying prices: always show the store-provided localized price string (priceString / localizedPriceString / price.formatted). Never hardcode a currency symbol or amount, and never build the price from the raw price number yourself.

  • The localized string already includes the correct currency symbol and locale formatting for the user.
  • Prices differ by region, and stores apply rounding rules you should not try to reproduce.
  • Hardcoding amounts breaks the moment you change pricing or launch in a new market.
Do. Render pkg.product.priceString (or the platform equivalent) directly in your paywall. Do not. Write something like "$" + product.price, which ignores currency, locale, and store rounding.

Prefer Offerings (configured in the dashboard) so you can change which products you sell without an app update. Use getProducts only when you need a specific product by id.

FAQ

How do I get products with purchases_flutter (getProducts)?
Call await Purchases.getProducts(['my_product_id']), which returns a List<StoreProduct>. Each item has identifier, title, description, price (a number), priceString (localized), and currencyCode. For paywalls, prefer Purchases.getOfferings() and read offerings.current?.availablePackages.

How do I get the localized price from a StoreProduct?
Read the store-formatted string: product.priceString on React Native and Flutter, storeProduct.localizedPriceString on iOS, and product.price.formatted on Android. These already include the user's currency and locale formatting.

What is the difference between getOfferings and getProducts?
getOfferings returns the packages you configured in the dashboard, so you can change what you sell without an app update. getProducts fetches specific products by store id. Prefer Offerings for paywalls.

Which StoreProduct fields are available?
The product id (identifier / productIdentifier), title, description, the raw price number, the localized price string (priceString / localizedPriceString), and currencyCode. Always display the localized price string.

Related Guides