Get help with your SDK implementation.
Recently active
Hi team 👋I’m using RevenueCat for both subscriptions and consumable credits.My backend receives webhook events, and the frontend/flutter has a listener which when gets triggered calls getUserProfile() (which hits the be endpoint which calls RevenueCat API) whenever the user opens the app.I want to make sure my backend always has the latest purchase info instantly, even if a webhook is delayed or missed Should I: Use both webhooks and the RevenueCat API (as a fallback) to sync the latest transactions? Always update the stored store_transaction_identifier based on the latest transaction from the purchases associated with customer API? Just want to confirm the best practice to ensure no missed updates across subscriptions and one-time purchases.Thanks!
Hi!I’m currently building an iOS app using React Native and RevenueCat for handling subscriptions.In App Store Connect, I’ve set up one subscription group that contains the following four auto-renewable subscriptions: PREMIUM – Monthly PREMIUM – Weekly SIGNATURE – Monthly SIGNATURE – Weekly I have a few questions regarding how upgrades and downgrades work within this setup, especially when using the Purchases.purchasePackage(pkg) method in RevenueCat. Question 1 – Upgrading Between Monthly PlansIf a user is currently subscribed to SIGNATURE Monthly and decides to upgrade to PREMIUM Monthly (both within the same subscription group and both having the same time duration - 1 month): Will the upgrade take effect immediately, or only after the current billing period ends? Does iOS handle this automatically, or do I need to write any additional code to manage upgrades (similar to Android)? In other words, does RevenueCat automatically trigger the upgrade and reflect the entitlement
Hey guys,I have a bit of a weird situation: I have one offering configured in RC, containing two products:monthly Sub lifetime itemWhen testing, everything seems to work properly. Especially the lifetime item works as expected.Funnily, when I hit the purchase button in my app for the Sub on Android and DO NOT purchase the item, I throw the correct error at the user, but the user still gets access to the premium features somehow.This does not happen on a lifetime item.When I checked my app behaviour, I found, that the difference in my app is, that on a monthly sub I already send the apps userID to RC before doing the purchase (which I do not on the lifetime item).As I use FlutterFlow for my app (with the RC integration), I added some custom code before the purchase action.This is the code I call: await Purchases.configure(PurchasesConfiguration(publicApiKey)); await Purchases.logIn(userId);Could that be the culprit?Am I doing something wrong here? Should I call this AFTER the purchase
Hi everybody,I’m implementing a setup where a custom subscription offering should be shown to users when they enter a specific key (referral code).Here’s my setup: • The custom offering (referral_offering) includes a package with two products — one for iOS and one for Android. • I’m using Flutter and calling Purchases.getOfferings() after setting a customer attribute (referrerCode) with Purchases.setAttributes(). • On iOS, getOfferings() works perfectly — 2 offerings are returned, and I can use the correct one from the map. • On Android, however, getOfferings() only returns the default offering. The referral_offering never appears in the JSON response.Things I’ve already tried: • Verified that the Android product in the custom offering is active, imported correctly, and linked to the right entitlement. • Confirmed that both the default and referral offerings are active and visible in the dashboard. • Tested with clean installs, cache deletion,
Dear RevenueCat Community,I am using the RevenueCat SDK in my Flutter application and have implemented App Tracking Transparency (ATT) on iOS, requesting the user’s permission before a purchase. When the user grants permission, I call Purchases.collectDeviceIdentifiers() to obtain device identifiers such as the IDFA.In my Flutter app, users can purchase subscriptions via 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 submits the subscription information to https://api.revenuecat.com/v1/receipts 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 behavior: For in-app purchases (IAP), in the RevenueCat dashboard > Recent Transactions > Customer
Hey, I have 2 different Paywall Screens (coded myself).One: You Subscribtion is paused, click here to Resume (deeplink to playstore)Other One: Resubscribe, choose between those plans.But at the moment I dont know how i should decide which screen i should show. Any Ideas? Webhook and RestAPI are not a option for me. I just want it from the Client SDK.Thanks in advance!
I’m using .presentPaywall() and I tried to use RevenueCatUI.Paywall component, but it’s always on this “Sheet View”, with that weird margin. How can I fix it? Also, the RevenueCatUI.Paywall component is crashing my app on Android.
Is there any way to achieve this?in documentation it states that default proration mode is WITHOUT_PRORATION, is it stays the same in case of using paywall builder? even in case of downgrading to less expensive tier?
i am not using purchases_ui_flutter anymore i had it and then i deleted it but in the google console i am getting this crash report on the version that doesn’t include purchases_ui_flutter is this crash has any connection with the purchases_ui_flutter package or there is another reason for this crash.Exception java.util.ConcurrentModificationException: at java.util.LinkedHashMap$LinkedHashIterator.nextNode (LinkedHashMap.java:1061) at java.util.LinkedHashMap$LinkedKeyIterator.next (LinkedHashMap.java:1084) at com.revenuecat.purchases.paywalls.FontLoader.addFileToCache (FontLoader.kt:119) at com.revenuecat.purchases.paywalls.FontLoader.access$getFontInfosForHash$p (FontLoader.kt:27) at com.revenuecat.purchases.paywalls.FontLoader.access$addFileToCache (FontLoader.kt:27) at com.revenuecat.purchases.paywalls.FontLoader$startFontDownload$1.invokeSuspend (FontLoader.kt:90) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33) at kotlinx.coroutines.Dispat
Getting a NetworkError sometimes on `Purchases.sharedInstance.restorePurchases` (KMP SDK).Minor bug report: `underlyingErrorMessage` seems to be a result of parsing HTML as JSON.# java.lang.Throwable: PurchasesError(code=NetworkError, underlyingErrorMessage=Value <!DOCTYPE of type java.lang.String cannot be converted to JSONObject, message='Error performing request.')## Issue SummaryPurchase History Network Error: Failed Device ID Linking**What's wrong:** Failed to link device ID with purchases. **NetworkError** during purchase history retrieval. Internal error code 12.**In the trace:** App entered foreground and resumed normally. **Network available** and capable.**Possible cause:** A **transient server-side issue** with the purchase history API may have caused the network error.
Hi everyone! I’m new here and still learning, so please be patient if I say something silly 😅I’m using Expo Go (React Native) in my app, and I’m implementing RevenueCat.I’m currently using the Test Store to simulate subscriptions.In my case, users can upgrade or downgrade between plans.The only difference between the plans is the cloud storage limit, which is controlled by the active product_id.In my app, users can only have one active subscription at a time. Current setup in RevenueCatOfferings Created one offering called default Packages Inside this offering, I created “Custom” packages since all of my plans are monthly (the package only allows one monthly product per offering, so I used “Custom”) Products I have subscriptions imported from Google Play And test subscriptions configured in the Test Store with similar product_ids Entitlements I have only one entitlement called storage_access In my Expo appI list all the packages from the current offering and let the user pick one to
I’ve added a 50% off offer on my yearly-autorenewing subscription in revenuecat which you can see in the image below. It’s called “mente-argentina”.This is for people who’ve never subscribed to my app. I’ve signed into my app with a fresh account, that’s never made any subscriptions to test this.This is a react native app and I’m using the react-native-purchases package.I’m calling the following function to get an object with all of my subscriptions/offerings in it:const offerings = await Purchases.getOfferings();When logging all pieces of this object, I can’t see the mente-argentina offering anywhere.I thought maybe I should try to create another product in the revenuecat ui but there I’m unable to get revenuecat to find the offering by id in the playstore, so I’m thinking that’s not the case.Is there anything I need to do to sync my google play offers and revenuecat? And how do I get these offers to show up in my code so I can show them to the user.
Hello,While reviewing my app analytics, I noticed that some user purchases failed with the error code “paymentPendingError.”I couldn’t find much documentation or discussion about this specific error online, so I have a few questions: Is this error caused by something on my app’s side or on the user’s side? If it’s on my side, what steps should I take to resolve or prevent it? If it’s on the user’s side, how should I guide them? Is there anything specific I can suggest (e.g., retrying, restoring purchases, etc.)? Any insights or guidance would be greatly appreciated.Thanks in advance!
## SummaryOn iPhone (portrait), RevenueCat's `PaywallView` renders a wide/tablet layout (right-side truncation, overflow) for our custom paywalls. The same device renders your default template paywall correctly. This points to a sizing/constraints issue in the custom paywall runtime or size-class detection.## Environment- RC SDKs: - purchases_flutter: 9.8.0 (also reproduced on 8.10.6) - purchases_ui_flutter: 9.8.0 (also reproduced on 8.10.6) ## Expected vs Actual- Expected: On iPhone portrait, `PaywallView` should use a compact/phone layout and fully respect the parent’s width; no horizontal overflow.- Actual: The paywall renders a wide/tablet layout, appears left-aligned, extends past the right edge, truncating headline text and CTA.## Minimal Repro (no app-specific wrappers)We clamp the width to a phone-safe max and center it. The behavior persists even with a very small max width and no scroll views around it.```dart// Inside a page bodyreturn SafeArea( child: LayoutBuilder( b
I previously implemented the subscription feature using SwiftyStoreKit, and all receipts were processed locally only. Recently, I applied RevenueCat and implemented a custom paywall. The implementation is complete, and I am currently testing it in TestFlight.In the TestFlight environment, I was able to restore purchases from my actual App Store account with the old setup, but with the RevenueCat SDK, restoration does not work. Is this the expected behavior? I am worried that existing users may not be able to restore their purchases when the app is released on the App Store.Purchases.shared.syncPurchases() For receipt migration, I executed the above code once to synchronize existing purchase history. I understand that server-side synchronization of previous purchases is recommended, but since there is no existing backend history, I cannot use that method. In this state, if I release the app on the App Store, will existing users be able to safely restore their past purchases?
If an entitlement is unlocked by multiple products at the same time, how do you see all of the products that unlocked the Entitlement? The EntitlementInfo class has a productIdentifier field on it that is a string but that only seems to show the last product that unlocked the entitlement, not all the products. https://revenuecat.github.io/purchases-ios-docs/5.43.0/documentation/revenuecat/entitlementinfo/productidentifier Thanks
Flutter, purchases_flutter: ^9.8.0purchases_ui_flutter: ^9.8.0 The paywall shows monthly and yearly SKUs in different currencies.Yearly - eur (expected, as I’m looking at it from Europe)Monthly - USD (default currency) - is not localized this is both on iOS and Android. Any ideas where to check for it?
Using RC’s V2 paywalls, my app is crashing every time I open the paywall in my React Native Android app with the exception:java.lang.IllegalStateException: Software rendering doesn't support hardware bitmapsThis is continuing the conversation on a past issue, as it was never really solved but @db888 found out that if he removed `expo-blur` the issue goes away. I’m encountering the same problem now but we have a requirement for blur views in the design so it’s not as simple as just removing this.Is there any plans to getting an actual fix out for this in Paywalls? I believe this is a hint at a potential solution: https://stackoverflow.com/a/58315279 Edit: I’m using `@sbaiahmed1/react-native-blur` and not `expo-blur`. It seems to not be an issue with `expo-blur`. Maybe they changed the library or something, I don’t think they use native blur views on Android.Referenced Issue:
Hi. I am running into problem initializing RevenueCat for my Expo react-native app. I spent a lot of time debugging the issue and finally narrowed to the Purchases.configure() call. First of all I had everything working fine in a “development” build (a native build with “developmentClient=true”. It is not an Expo Go build.). I am using a RevenueCat “Test Store” because I haven’t set up anything on App Store or Play Store. It worked fine on both iOS and Android. Then I tried to make internal “preview” builds (with “developmentClient=false”) and it started having problem. On iOS the app immediately crashed and disappeared once the Purchases.configure() is called. On Android the app became a blank screen right after the configure() call, but it does seem like different symptoms of the same problem. I set up the “Purchases.configure()” call within a button onPress() event to help the debugging, and hardcoded the Test Store API key in codes to rule out the possible environment variable iss
I’ve set up my app store IAP and set up the various RC things needed for it. But in App Store Connect, my IAP entry says “Missing Metadata.” I have verified that all agreements/forms/etc are done under “Business” and all say “Active.” I’ve added the price for the IAP as well as the localization entry and image. However, the localization and image say “Prepare for Submission” not “Ready to Submit” so I don’t understand what I’m supposed to do.The only thing that I haven’t added is a screenshot, because I don’t understand how I’m supposed to offer a screenshot of the app if I can’t actually get the IAP from the SDK yet?? Like, show an empty screen where the IAPs are supposed to appear?? I can’t find ANY guidance on this aspect. The help popover just says “We’ll only use the screenshot for our review — it won’t be displayed on the App Store.” The help page says “A screenshot of the in-app purchase that clearly shows the item or service being offered.”So how on earth are you supposed to do
Hey everyone,I’m running into an odd issue while testing subscriptions. I’ve gone through all the usual setup steps, and the offerings fetch seems okay, but the purchase sheet never appears. What I have so far App built with Vue 3 + Capacitor. Integrated the RevenueCat SDK (capacitor-purchases). Offerings are fetched successfully from RevenueCat, so configuration seems correct. Testing on a physical device via Xcode, not TestFlight. Device is signed in with my personal Apple ID, while the sandbox ID is logged into developer settings On the manual subscription test (developer settings), the Apple sandbox pay sheet showed up, I subscribed, and in my app I can see the purchase reflected in customerInfo. ✅ The issueWhen I try to purchase the package (the code executes correctly and uses the correct package data), I don’t get nothing. No xcode logs, no freezes, no pay sheets. It’s like I’m not pressing the button. The function is being called and the logs stop right before.await
Stack: Flutter, purchases_flutter 9.7.0, iOS target 14, RC sandbox Web Billing, same RC project for App Store + Web Billing.Entitlement: premium (Web product appname_weekly_web attached).App User ID: e.g., YuSUDJGSSUQqYkeJqu0xoH2 (logged in via Purchases.logIn(uid)). WPL (identified):https://pay.rev.cat/sandbox/<TOKEN>/<APP_USER_ID>?package_id=$rc_weekly Server says it’s active:REST /v1/subscribers/<APP_USER_ID> shows premium entitlement active (store: rc_billing, is_sandbox: true). WPL revisits show “Success” (already subscribed). Client says it’s not:On app resume:await Purchases.invalidateCustomerInfoCache(); final info = await Purchases.getCustomerInfo(); print(info.entitlements.active.keys); // => () I have tried polling every 2 seconds and the entitlement never gets updated. What does work:If I build the WPL with originalAppUserId (or anonymous flow) and tap the Redeem Purchase deep link:final r = await Purchases.parseAsWebPurchaseRedemption(url); if (r != n
My app requires login, so when i call Purchases.configure(new PurchasesConfiguration.Builder(mActivity, apiKey).appUserID(customUserId).build());i always pass a customUserId, that i expect to receive on the webhooks to track user purchases on my backend.I also never call logout. On RC backend i have these options activated:Tracking new purchases from server to server notifications.Keep with original App User ID I understand that the server to server event might sometimes arrive before the SDK one, thus an anonymousUserId is created and the corresponding webhook does not provide usefull user information (customUserId). My question is once the SDK updated information arrives to RC backend, is a new webhook created with the updated info? Or do i need to listen for a diferent kind of webhook when the alias with my customUserId is created on a later time? I don’t want to be polling RC backend to detect these changes.I could disable server-to-server event, and probably will, but i worry tha
Hi guys!There is an issue with Flutter SDK (on the latest 9.5.0 as well) for Android with multiple placements.In my app I have multiple placements with different offerings. Then I set up targeting in the Dashboard without specifying any placements, only the default offering. I would expect that all placements in my app would show that default offering. This is actually the case in iOS. But in Android no paywalls is shown at all.Many times I forget to list all the placements when targeting and my Android app won’t show paywalls in missed placements. Recently I run an experiment without specifying placements in the experiment settings and after 3 days I figured that the Android app wasn’t showing any paywalls at all because of this issue :(You can find more information in this GitHub issue:https://github.com/RevenueCat/purchases-flutter/issues/1225
When running the SDK using Unity 2022.3.51f1 and built for Android 15, I get the following error in ADB log. What can I do about it? 10-16 14:52:13.767 19513 19557 E Unity : AndroidJavaException: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/auth/blockstore/Blockstore;10-16 14:52:13.767 19513 19557 E Unity : java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/auth/blockstore/Blockstore;10-16 14:52:13.767 19513 19557 E Unity : at com.revenuecat.purchases.blockstore.BlockstoreHelper.<init>(BlockstoreHelper.kt:29)10-16 14:52:13.767 19513 19557 E Unity : at com.revenuecat.purchases.PurchasesOrchestrator.<init>(PurchasesOrchestrator.kt:146)10-16 14:52:13.767 19513 19557 E Unity : at com.revenuecat.purchases.PurchasesFactory.createPurchases(PurchasesFactory.kt:357)10-16 14:52:13.767 19513 19557 E Unity : at com.revenuecat.purchases.PurchasesFactory.createPurchases$default(PurchasesFactory.kt:68)10-16 14:52:13.
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.