If you've [configured Offerings](🔗) in RevenueCat, you can control which products are shown to users without requiring an app update. Building paywalls that are dynamic and can react to different product configurations gives you maximum flexibility to make remote updates.
Before products and offerings can be fetched from RevenueCat, be sure to initialize the Purchases SDK by following our [Quickstart](🔗) guide.
# Fetching Offerings
Offerings are fetched through the SDK based on their [configuration](🔗) in the RevenueCat dashboard.
getOfferings` method will fetch the Offerings from RevenueCat. These are pre-fetched in most cases on app launch, so the completion block to get offerings won't need to make a network request in most cases.
Offerings, products or available packages empty
If your offerings, products, or available packages are empty, it's due to some configuration issue in App Store Connect or the Play Console.
The most common reasons for this in App Store Connect are an out-of-date 'Paid Applications Agreement' or products not at least in the 'Ready To Submit' state. For Google Play, this usually occurs when the app is not published on a closed track and a valid test user added.
You can find more info about trouble shooting this issue in our [Help Center](🔗).
You must choose one Offering that is the "Current Offering" - which can easily be accessed via the `
current` property of the returned offerings.
To change the current Offering, navigate to the Offerings tab for your project in the RevenueCat dashboard and click **Make current** next to the Offering you'd like to enable.
Offerings can be updated at any time, and the changes will go into effect for all users right away.
## Custom Offering identifiers
It's also possible to access other Offerings besides the "Current Offering" directly by its identifier.
# Displaying Packages
Packages help abstract platform-specific products by grouping equivalent products across iOS, Android, and web. A package is made up of three parts: identifier, type, and underlying store product.
|Identifier||The package identifier (e.g. `|
|Type||The type of the package:
|Product||The underlying product that is mapped to this package which includes details about the price and duration.|
Packages can be access in a few different ways:
via the `
.availablePackages` property on an Offering.
via the duration convenience property on an Offering
via the package identifier directly
### Getting the Product from the Package
Each Package includes an underlying product that includes more information about the price, duration, and other metadata. You can access the product via the `
# Choosing which Offering to display
In practice, you may not want to display the default current Offering to every user and instead have a specific cohort that see a different Offering.
For example, displaying a higher priced Offering to users that came from [paid acquisition](🔗) to help recover ad costs, or a specific Offering designed to show [iOS Subscription Offers](🔗) when a user has [cancelled their subscription](🔗).
This can be accomplished with custom Offering identifiers for each of these "cohorts".
As of now, cohort logic needs to be managed outside of RevenueCat.
# Best Practices
|✅ Make paywalls dynamic by minimizing or eliminating any hardcoded strings||❌ Make static paywalls hardcoded with specific product IDs|
|✅ Use default package types||❌ Use custom package identifiers in place of a default option|
|✅ Allow for any number of product choices||❌ Support only a fixed number of products|
|✅ Support for different free trial durations, or no free trial||❌ Hardcode free trial text|
# Next Steps
Now that you've shown the correct products to users, time to [make a purchase ](🔗)
Check out our [sample apps ](🔗) for examples of how to display products.