Skip to content
This repository was archived by the owner on Jun 23, 2025. It is now read-only.
This repository was archived by the owner on Jun 23, 2025. It is now read-only.

[BUG] iOS paywall not showing for anonymous users #67

@ybentz

Description

@ybentz

New issue checklist

  • I have reviewed the README and documentation
  • I have searched existing issues and this is not a duplicate
  • I have attempted to reproduce the issue and include an example project.

General information

  • @superwall/react-native-superwall version: 2.0.6
  • React Native version: 0.76.7
  • Expo version (if applicable): 52.0.36
  • Platform affected (Android and/or iOS): iOS
  • OS versions affected, e.g. iOS 18.3.1 (if applicable): All (that we've tested)
  • Devices/Simulators affected: All iOS devices
  • Reproducible in the example app? (Yes/No): Not sure
  • Related issues: N/A

Describe the bug

We've recently upgraded the Superwall dependency from 1.4.7 to 2.0.6. We followed the migration guide and also made sure that our PurchaseController is implemented exactly the same as the Superwall docs for using with RevenueCat here. Our app has users in 2 states - anonymous and logged in. For anonymous users we don't call identify until they log in.

Starting after this migration, we noticed that logged in users on iOS and all users on Android see the paywall as and when expected, however, anonymous users on iOS don't see the paywall until they log in. We started digging and found out that the paywallPresentationRequest event has $status = timeout and $status_reason = subscriptionStatus_timeout. We found this part of the docs which led to the realization that the anonymous user's subscription state is probably not being state so it's "stuck" at unknown (that's stated in a different part of the same docs page here).

Add some logs we found out that using the code provided in the docs for the PurchaseController, looks like for our anonymous users, Purchases.addCustomerInfoUpdateListener isn't being triggered on the first render of the app for some reason so Superwall.shared.setSubscriptionStatus is never called because that's the only place in the code that calls it.

We implemented a workaround that seems to work in the meantime but we believe this is either a regression or the example code in the docs should be updated to reflect this change.

Our workaround simply makes sure we set the subscription status when we add the listener:

  async syncSubscriptionStatus() {
    const updateSubscriptionStatus = (customerInfo: CustomerInfo) => {
      const entitlementIds = Object.keys(customerInfo.entitlements.active)
      void Superwall.shared.setSubscriptionStatus(
        entitlementIds.length === 0
          ? SubscriptionStatus.Inactive()
          : SubscriptionStatus.Active(entitlementIds),
      )
    }
    const customerInfo = await Purchases.getCustomerInfo()
    updateSubscriptionStatus(customerInfo)

    // Listen for changes
    Purchases.addCustomerInfoUpdateListener((customerInfo) => {
      updateSubscriptionStatus(customerInfo)
    })
  }

Steps to reproduce

  • Set up an app using RevenueCat and Superwall and the code provided in the Superwall docs as is.
  • On an iOS device, make sure Superwall.shared.identify was NOT called.
  • Trigger showing a paywall by sending the event that triggers it.
  • Paywall is expected to be shown but it does not.

Other Information

Suggestions how to fix: Check why the listener doesn't run on first render, specifically on iOS. If needed, change the code so it does, otherwise, update the example code in the docs to reflect needing to set the subscription state manually.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions