Fix: RevenueCat Products and Offerings Not Loading on iOS

RevenueCat offerings returning empty on iOS is almost always configuration, not code. Here are the real causes in order of likelihood and concrete fixes for agreements, product IDs, and StoreKit setup.

The Symptom and What It Usually Means

The typical symptom is that offerings() returns successfully but offerings.current is nil, or an offering exists yet its availablePackages array is empty, so your paywall renders with no products and no prices. Sometimes the SDK logs a warning that products could not be fetched from StoreKit. Crucially, this is almost never a bug in your Swift code and almost always a configuration mismatch between App Store Connect, RevenueCat, and StoreKit. The RevenueCat SDK asks StoreKit for product details using the identifiers you mapped in the dashboard, and if StoreKit cannot return a product for a given identifier, that package silently drops out of the offering. That is why the array comes back empty even though your code is correct. The path to a fix is systematic: verify Apple's agreements, then the product identifiers and states, then propagation timing, then your local StoreKit test setup, then account-level settings. Work through these in order rather than rewriting SDK code that is probably fine, because each cause has a distinct, checkable fix and guessing tends to introduce new problems on top of the original one.

Cause 1: Paid Applications Agreement Not Active

The single most common cause is that the Paid Applications Agreement in App Store Connect is not active. Until this agreement is signed and your tax and banking details are complete, Apple simply will not serve in-app purchase products to StoreKit, so every package that maps to a real product disappears and offerings come back empty. To check, sign in to App Store Connect and open Business, sometimes labeled Agreements, Tax, and Banking. Confirm the Paid Applications Agreement shows as active, not pending or expired. If it is pending, accept the latest terms and complete every required tax form and bank account entry for your legal entity; missing any one field keeps it inactive. Note that Apple periodically issues updated agreements that must be re-accepted, which can silently break a previously working setup after months of stability. After activating, allow time for it to take effect before you conclude anything else is wrong. This is the first thing to verify because it invalidates every other check if it is wrong: no amount of correct code, identifiers, or offerings will produce products while the agreement is inactive.

Cause 2: Product Identifier Mismatch

The second most common cause is a mismatch between the product identifiers in App Store Connect and the ones referenced by your RevenueCat packages. The identifier is a case-sensitive string, and any difference, an extra character, a typo, wrong capitalization, or a leftover placeholder, means StoreKit returns no product for that package, and it drops from the offering. Open the RevenueCat dashboard, look at each package in your current offering, and note the exact App Store product identifier it references. Then open App Store Connect and confirm a product with precisely that identifier exists. Copy and paste rather than retyping to avoid introducing errors, and watch for invisible whitespace at the start or end of the string. Also confirm the identifiers belong to the same app and bundle identifier you are actually running, since a common mistake is mapping products from a different app record entirely. If even one character differs, correct it in RevenueCat so the package points at the real product, then re-fetch offerings to confirm it now loads. Because each mismatched package drops silently, a partially wrong mapping can show some products and hide others, which is a strong hint to audit every identifier rather than just the missing ones.

Cause 3: Products Not in a Sellable State

Even with correct identifiers and a signed agreement, a product will not load if it is not in a state App Store Connect considers sellable. Newly created subscriptions and in-app purchases often sit in states like Missing Metadata, requiring a display name, description, price, and a review screenshot before they become ready. A product missing any required metadata will not be served to StoreKit. In App Store Connect, open each product and resolve every warning until it reaches a ready state. For a brand-new app that has never been approved, some in-app purchase products must be submitted alongside your first app version before they become available, which catches many first-time developers off guard. Also verify pricing is set, since a product with no price cannot be sold. Go through each product methodically and clear all metadata warnings rather than assuming one is fine because another loaded. Once every product your offering references is in a proper ready state, StoreKit can return it and your packages will populate. This cause is easy to miss because the product exists and its identifier matches, yet it is simply not yet eligible to be sold.

Cause 4: Propagation Delay

App Store Connect changes are not instantaneous. After you create products, sign the agreement, or set prices, it can take a noticeable amount of time, sometimes hours, for those changes to propagate to StoreKit's servers so the SDK can fetch them. This is a frequent source of false alarms: everything is configured correctly, but a developer testing minutes after creating a product sees empty offerings and assumes something is broken, then starts changing configuration and introduces real errors. If you have just made changes and have verified the agreement, identifiers, and product states are all correct, the pragmatic fix is to wait and retry later rather than continuing to edit configuration. In the meantime, you can develop and test your paywall UI against a local StoreKit configuration file, which does not depend on App Store Connect propagation at all and lets you keep making progress. Give real changes time to reach StoreKit before concluding there is a deeper problem, and re-fetch offerings after waiting. A good discipline is to change one thing, note the time, and re-check after a reasonable interval instead of making many rapid edits that muddy cause and effect.

Cause 5: StoreKit Configuration File Interfering

Xcode's StoreKit configuration files are excellent for local testing, but they can also cause confusion. If your scheme is set to use a StoreKit configuration file that does not include the product identifiers your offering references, or that has stale entries, products may fail to load or load with incorrect data even though your live App Store Connect setup is fine. Conversely, if you intend to test against local products but have not selected the configuration file in your scheme, the SDK will try to reach the real StoreKit and may return nothing during early development before your App Store Connect products exist. Check your scheme under Product, then Scheme, then Edit Scheme, then Run, then Options, and look at the StoreKit Configuration setting. Either select the correct configuration file with matching identifiers for local testing, or set it to None to test against the real StoreKit environment. Keeping the configuration file's product identifiers in sync with your App Store Connect products avoids a whole class of confusing, environment-specific loading failures where the app behaves one way in local testing and another way against real Apple servers.

Cause 6: Wrong API Key or Bundle Identifier

Less common but worth checking is a mismatch at the account level. If you configured the SDK with the wrong RevenueCat API key, for example a key from a different project or the secret key instead of the public Apple key, the SDK may authenticate against the wrong project whose offerings do not include your products. Confirm you called Purchases.configure with the public Apple SDK key from the correct project in the RevenueCat dashboard. Similarly, verify your Xcode project's bundle identifier matches the app configured in RevenueCat and in App Store Connect; a mismatched bundle identifier means StoreKit and RevenueCat are effectively describing different apps, and products will not resolve. These issues are easy to overlook after copying a project template, duplicating a target, or setting up a second staging environment. Double-check the key, the project it belongs to, and the bundle identifier across all three systems. When they agree, the SDK talks to the right project and can return the offerings you actually configured. Because this cause produces the same empty-offering symptom as the others, confirm it explicitly rather than assuming it is fine just because the app builds and runs.

A Systematic Debugging Checklist

When products will not load, resist rewriting code and instead walk the chain in order. First, enable debug logging with Purchases.logLevel = .debug and read exactly what the SDK reports when fetching offerings, since it often names the failing identifiers directly. Second, confirm the Paid Applications Agreement is active with complete tax and banking. Third, compare every product identifier between RevenueCat and App Store Connect character for character. Fourth, confirm each product is in a ready, sellable state with no missing metadata. Fifth, account for propagation delay by waiting and retrying if changes are recent. Sixth, inspect your scheme's StoreKit configuration setting. Seventh, verify the public Apple API key and bundle identifier match across RevenueCat, Xcode, and App Store Connect. Following this sequence resolves the overwhelming majority of empty-offering problems, because they are configuration mismatches rather than code defects. RevenueCat also publishes a dedicated SDK troubleshooting guide for products not loading that mirrors these checks, and consulting it alongside the debug logs is usually faster than trial and error.

Frequently Asked Questions

Why does offerings.current come back empty even though my code is correct?

Because packages whose products StoreKit cannot return silently drop out. The usual causes are an inactive Paid Applications Agreement, product identifier mismatches, products not in a sellable state, or propagation delay. It is a configuration issue between App Store Connect, RevenueCat, and StoreKit, not a code bug.

How long do App Store Connect changes take to appear?

Propagation to StoreKit is not instantaneous and can take from minutes to several hours after you create products, sign agreements, or change prices. If your configuration is verified correct and changes are recent, wait and retry rather than making more changes.

How do I confirm my product identifiers match?

Open each package in your RevenueCat offering, note the App Store product identifier it references, and confirm an identically spelled, same-case product exists in App Store Connect for the same bundle identifier. Copy and paste to avoid typos and hidden whitespace, since identifiers are case-sensitive.

Can a StoreKit configuration file cause empty products?

Yes. If your scheme uses a StoreKit configuration file missing the relevant identifiers, or has stale entries, products may not load or may load incorrectly. Check Edit Scheme, Run, Options, StoreKit Configuration, and either select a correct file or set it to None to test against real StoreKit.

Could the wrong API key cause this?

Yes. Using a key from a different RevenueCat project, or the secret key instead of the public Apple SDK key, can point the SDK at a project whose offerings do not include your products. Verify you configured the correct project's public Apple key and that bundle identifiers match everywhere.