Get help with your SDK implementation.
Recently active
Dear RevenueCat Community,I am using the RevenueCat SDK in my Flutter application and have implemented App Tracking Transparency (ATT) permission on iOS. When the user grants permission, I call the method Purchases.collectDeviceIdentifiers() to obtain the device's IDFA. This value is correctly set and included in the events sent through the webhooks.In my Flutter app, users can purchase subscriptions using Stripe. For this, a web view is opened for the user to complete the payment. Once the purchase is completed and the user returns to the app, the app submit to this endpoint https://api.revenuecat.com/v1/receipts the subscription ids to upload the purchase to RevenueCat. This is how the user gains access to the app features after the purchase.To receive purchase events centrally in my backend, I have added a webhook in RevenueCat that reports Initial Purchase and Renewal events to my endpoint.I have observed the following: For purchases made within the app (IAP), the IDFA is correctly
Hi RevenueCat team,All of my agreements and tax information are already set up and working. I also have other apps where In-App Purchases are working fine. However, with this new app I’m stuck because of Apple’s requirement:“Your first subscription must be submitted with a new app version. Create your subscription, then select it from the app’s In-App Purchases and Subscriptions section on the version page before submitting the version to App Review.”Because of this, I cannot send my IAP for review, and Apple is rejecting the submission under 2.1 - Performance - App Completeness with the note:We found that your in-app purchase products exhibited one or more bugs which create a poor user experience. Specifically, after selecting both weekly and yearly subscriptions an error message is displayed.Review device details:• Device type: iPhone 13 mini• OS version: iOS 26.0At the same time, I get this warning from RevenueCat:[RevenueCat] ⚠️ RevenueCat SDK is configured correctly, but contains
This code checks to see if a customer should be shown the paywall. let customerInfo = try await Purchases.shared.customerInfo(fetchPolicy: .fetchCurrent) let timeInterval = Date.now.timeIntervalSince(customerInfo.firstSeen) let ninetyDays: TimeInterval = 90 * 24 * 60 * 60 return timeInterval >= ninetyDaysThis check is returning false.On the RevenueCat dashboard for this user first seen was 27 June 2024. They never changed their App User ID. However they only seen the paywall today 17 September 2025. Which is much greater than the 90 days. What could be causing the delay in showing the paywall? I appreciate that the customerInfo could be cached but not for over a year.
I am getting the following crashes on Android using revenueCat KMP SDK. And it has increased recently. What could be the issue?The attached two files are of the PaywallState and Purchase click button codes Exception java.lang.IllegalStateException: at com.revenuecat.purchases.kmp.di.AndroidProviderKt.requireActivity (AndroidProvider.kt:83) at com.revenuecat.purchases.kmp.Purchases.purchase (Purchases.android.kt:275) at com.revenuecat.purchases.kmp.Purchases.purchase$default (Purchases.android.kt:266) at utils.PaywallState.purchaseSelectedPackage (PaywallState.kt:29) at pro.ui.paywall.PaywallScreenKt.PaywallScreen$lambda$41$lambda$40$lambda$39$lambda$26$lambda$25 (PaywallScreen.kt:230) at androidx.compose.foundation.ClickableNode.onPointerEvent-H0pRuoY (Clickable.kt:1018) at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass (HitPathTracker.kt:436) at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass (HitPathTracker.kt:422) at androidx.compose.ui.input.poin
Hi everyone,I have a mobile app that originally relied on $RCAnonymousIDs to manage subscriptions. Now, we’ve introduced mandatory signup, so I’m now working on migrating from anonymous IDs to our own custom user IDs.What’s not clear to me is the best way to handle the transition: How can I merge an existing custom user ID with the old $RCAnonymousID values already in the system? Should this be done via the API, or does the SDK handle it automatically? In some cases, the custom user ID is already listed as an alias of an anonymous ID. How can I “promote” the custom ID so it becomes the original_app_user_id instead of the anonymous one? Has anyone here gone through a similar migration? Any guidance on the best practices would be really helpful.Thanks!
I noticed that we had inflated install numbers on RC vs. App Store. I trust Apple more with the installs, so I went on to find the root cause.We have a Flutter app and I call Purchases.logOut() when a user logs out. This sometimes happens automatically. I now read in the docs that logOut will clear the saved appUserID. This will generate a random user id and save it in the cache.Since RC seems to count appUserIDs as installs, each log-out will count as an additional install. Question: Should I even call Purchases.logout when our users log out? They are still on the same device, with the same Apple ID (most likely). Seems to me that this is wrong and inflates our install numbers.
Hello, I have a flutter app that is working fine on Android but can’t fetch offers from Appstore Connect. I have verified all the details, from product id, bundle id, products are approves, agreements signed, bank account added, etc. I can see where the issue lies in any config setting. What else could be causing this problem? I went through the “Why are offerings or products empty?” checklist. I did see where it stated about a shared secret but that was for storekit 1 which is not what we are using. I have done the certificate for storekit 2. This is only on iOS. Any help is greatly appreciated.
Hello,I plan to use virtual currencies within my app.For me, spending or gaining is straight forward and I will use my backend for such calls.Evaluating the available tokens within the app raises more questions and I tried to understand the official doc here https://www.revenuecat.com/docs/offerings/virtual-currency but I still wonder about some aspects.Exact use case: I need to know within my view models if the user has tokens or not.What should I use: Purchases.shared.cachedVirtualCurrencies or Purchases.shared.virtualCurrencies()?I understand the fact that I need to call the Purchases.shared.invalidateVirtualCurrenciesCache() each time there is a backend transaction, but then what?Is calling Purchases.shared.invalidateVirtualCurrenciesCache() updating the Purchases.shared.cachedVirtualCurrencies? or do I need to fist call Purchases.shared.virtualCurrencies() and then use the cachedVirtualCurrenciesHow about this flow:App launch call Purchases.shared.virtualCurrencies() and store it
Something is wrong with the checkTrialOrIntroductoryPriceEligibility function. I'm not sure if I'm doing it right; to be sure, I wanted to share my problem here first.In my iOS app, I use this snippet to check whether there is an eligible introductory price:if (Platform.OS === 'ios') { // Purchases.checkTrialOrIntroductoryPriceEligibility is only available for iOS const introEligibilityStatuses = await Purchases.checkTrialOrIntroductoryPriceEligibility([ pkg.product.identifier, ]); return ( introEligibilityStatuses[pkg.product.identifier].status === Purchases.INTRO_ELIGIBILITY_STATUS.INTRO_ELIGIBILITY_STATUS_ELIGIBLE ); } In one account, everything works fine—I haven't bought anything with that account yet.But the second account (with expired introductory subscription) returns wrong information:The status returns INTRO_ELIGIBILITY_STATUS_ELIGIBLE (2), which means the introductory price is available, so I show the discount in the app. Ho
Hi, I’ve been using Paywall with Flutter, and it’s been great so far, but it doesn’t handle subscription upgrades/downgrades for Google Play, which is a major issue.Without this essential feature, Paywall becomes almost unusable for managing multiple subscriptions on the Play Store.Are there any solutions to make RevenueCat Paywall work for upgrades/downgrades with Google subscriptions in Flutter?
I’ve uploaded a new version of my app with sdk version 9.5.0 and I’m seeing this error in production, did anyone encounter this?here is the stack trace: com.revenuecat.purchases.CoroutinesExtensionsCommonKt$awaitGetProducts$2$2.invoke (CoroutinesExtensionsCommon.kt:146) com.revenuecat.purchases.CoroutinesExtensionsCommonKt$awaitGetProducts$2$2.invoke (CoroutinesExtensionsCommon.kt:141) com.revenuecat.purchases.ListenerConversionsCommonKt$getStoreProductsCallback$1.onError (ListenerConversionsCommon.kt:36) com.revenuecat.purchases.PurchasesOrchestrator$getProducts$1.onError (PurchasesOrchestrator.kt:517) com.revenuecat.purchases.PurchasesOrchestrator$getProductsOfTypes$1$2$1.invoke (PurchasesOrchestrator.kt:1128) com.revenuecat.purchases.PurchasesOrchestrator$getProductsOfTypes$1$2$1.invoke (PurchasesOrchestrator.kt:1126) com.revenuecat.purchases.PurchasesOrchestrator.dispatch$lambda$63 (PurchasesOrchestrator.kt:1158) com.revenuecat.purchases.PurchasesOrchestrator.$r8$lambda$vfpu2r8Y3li
I currently use API v8, there are lifetime products in my app that were incorrectly configured as “consumable” in the RevenueCat dashboard (I fixed that to be “non-consumable” but many users have already purchased these before). I understand that in API v9 (which uses Play Billing Library 8), I can’t restore consumed products. Does that mean that if I upgrade then these products will be non-restorable?In other words, does fixing the products from “consumable” to be “non-consumable” solve the issue for all purchases, or does it apply only to new purchases after the fix?
I have created a Paywall with some icons as you can see in the screenshot attached. But when I try to open the paywall in my app, or even in the RevenueCat app, the icons do not appear. iOS 26RevenueCat SDK 5.39.0
Hi.. I’ve got an old ObjC project that uses RevCat. I don’t rely on the system localization but allow the user to choose the language to override it.. so I want to also override the paywall localization. I found another post that says this is possible in ios: Purchases.shared.overridePreferredUILocale("es")My app is ObjC and generally I can call any func with objC but this one doesn't seem to be found.. trying:[[RCPurchases sharedPurchases] overridePreferredUILocale:@”es”];But that’s not found.. is there a way? Or would I need to switch over and have some swift in my project (I haven’t really done that, I know it’s possible.. just trying to find the easiest solution at the moment) Thanks!D
Hi,In my app, users can manually select their preferred language, since many of them don’t change their phone’s system language to match their native one.Because of this, the app language is controlled through my own state management system rather than relying on the device’s localization settings.The problem is that I can’t find a way to localize the paywall to match this internal language setting.Am I missing something here, or does this mean I can’t localize the paywall at all?This feature is essential for us, and it could determine whether we continue with RevenueCat or need to explore alternatives.Please help!
Error loading subscriptions: PlatformException(23, There is an issue with your configuration. Check the underlying error for more details. There's a problem with your configuration. None of the products registered in the RevenueCat dashboard could be fetched from App Store Connect (or the StoreKit Configuration file if one is being used).More information: https://rev.cat/why-are-offerings-empty, {code: 23, readableErrorCode:CONFIGURATION_ERROR, message: There is an issue with your configuration. Check the underlying error for more details. There's a problem with your configuration. None of the products registered in the RevenueCat dashboard could be fetched from App Store Connect (or the StoreKit Configuration file if one is being used).More information: https://rev.cat/why-are-offerings-empty, readable_error_code:CONFIGURATION_ERROR, underlying ErrorMessage:
I’m integrating Customer Center into my app (with purchases-kmp) and the Customer Center Composable always shows a blank screen. Any ideas on what could be wrong? https://drive.google.com/file/d/1YT3z5aytElJVvgDZvJHN_VwCV-aRu7X8/view?usp=sharing
We have multiple paywalls configured in RevenueCat and would like to implement dynamic paywall decisioning based on the user’s attributes or behavior.What is the recommended approach to determine and show the correct paywall for each user?Is there a way to manage or customize which paywall is presented at runtime using RevenueCat’s SDK or dashboard?
Getting a bunch of these in my logs12.1.0 - [FirebaseAnalytics][I-ACS023141] Purchase is a duplicate and will not be reported. Product ID: test3Is this from RevenueCat? I’m not sending this data to analytics. Thanks!
I tested successfully purchasing a subscription : I downloaded the app from Play Store, and purchase it, everything is fine.Is it possible to do the same test when deploying from Android Studio or installing manually the apk ? When I try, I get an error “This version of the application is not configured for billing through Google Play”.Both tests are done on an emulator. Thank you
Hello RevenueCat community,We would like to open a discussion around the initialization behavior of the Amazon Appstore SDK when used with RevenueCat, particularly on Fire TV devices and low-spec kindle tablets. EnvironmentReact Native Purchases: react-native-purchases: 8.11.10 RevenueCat Amazon Store: purchases-store-amazon:8.22.0 Amazon Appstore SDK: com.amazon.device:amazon-appstore-sdk:3.0.5Devices tested:Fire TV Stick (Fire OS 5.2.9.5) Kindle Fire 7, 7th generation (Fire OS 5.7.1.0) Issue observed When configuring RevenueCat withPurchases.configure({ apiKey: REVENUE_CAT_API_KEY_AMAZON, useAmazon: true })we sometimes experience very long initialization times (up to 30–60 seconds). This affects the ability to fetch offerings at app startup.Errors observed in React Native:[RevenueCat] Error obtaining storefront in Amazon: PurchasesError( code=UnknownError, underlyingErrorMessage=Timeout error trying to get Amazon user data., message='Unknown error.')[RevenueCat] 😿‼️ PurchasesE
Hi Everyone,I’m trying to give an existing subscriber a free month using RevenueCat’s “Google Play: Defer a Subscription” API (https://www.revenuecat.com/docs/api-v1#tag/transactions/operation/defer-a-google-subscription), but I keep getting "Subscription not found for subscriber" in the response.I’m posting to this URL: https://api.revenuecat.com/v1/subscribers/{app_user_id}/subscriptions/{product_identifier}/deferI copied the product ID from the "product_id" field of the event data from when the user purchased the subscription, to make sure I was using the correct value. I have tried it with the product ID as both plain text and URL-encoded. The user ID contains only letters and numbers, so URI-encoding makes no difference there.My POST body looks like this:{ "expiry_time_ms": 1762620360000}I can’t figure out what I’m doing wrong. Does anyone have any insight?
import SwiftUIimport RevenueCatimport RevenueCatUIstruct BuyPremiumInfoOrButton: View { @EnvironmentObject var store: Store @State private var displayPaywall = false var body: some View { Group { switch store.premiumState { case .notLoaded: Text("Loading...") case .hasPremium: Label("You have premium", systemImage: "crown") case .doesNotHavePremium: Button { displayPaywall.toggle() } label: { Label("Upgrade to Premium", systemImage: "crown") } case .error: Text("There was an error loading your premium status") } }.sheet(isPresented: self.$displayPaywall, onDismiss: { store.refresh() }) { PaywallView() } }}The above is my code. Its just using the PaywallView() from the RevenueCatUI. But this one seems to not dismiss the sheet that the
We noticed a weird issue that is happening to some users. When we present the paywall we are using the loaded offerings and if they are not loaded we wait for them to be refreshed. In our code we first fetch customerInfo and then the offerings. By looking at the logs from one of our users call to the customerInfo() never seems to end - it doesn’t return nor throw an error.public func refreshData() async throws { logger.log("Refresh data") try await refreshCustomerInfo() try await refreshProducts()}inside the refreshCustomerInfo() we are logging everything but only Begin refreshing customer info seems to be included in the logs.public func refreshCustomerInfo() async throws { logger.log("Begin refreshing customer info") do { customerInfo = try await purchases.customerInfo() logger.log("Refreshing customer info succeeded. Bought: \(purchased)") } catch let error { logger.error("Refreshing customer info failed", error) throw PurchaseError(erro
I’ve created a paywall with a “redeem code” button. It has a “Navigate to” “Offer code redemption” action. However, the button doesn’t show up in my app.I’ve added all translations. When adding a plain text label with the same string it shows just fine.Anything I’m missing here?
Already have an account? Login
No account yet? Create an account
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.