Using RevenueCat

If you want to use RevenueCat to handle your subscription-related logic with Superwall, follow this guide.

1. Create a PurchaseController

Create a new file called RCPurchaseController.swift, then copy and paste the following:

import SuperwallKit
import RevenueCat

final class RCPurchaseController: PurchaseController {
  // MARK: Sync Subscription Status
  /// Makes sure that Superwall knows the customers subscription status by
  /// changing `Superwall.shared.subscriptionStatus`
  func syncSubscriptionStatus() {
    assert(Purchases.isConfigured, "You must configure RevenueCat before calling this method.")
    Task {
      for await customerInfo in Purchases.shared.customerInfoStream {
        // Gets called whenever new CustomerInfo is available
        let hasActiveSubscription = ! // Why? ->
        if hasActiveSubscription {
          Superwall.shared.subscriptionStatus = .active
        } else {
          Superwall.shared.subscriptionStatus = .inactive

  // MARK: Handle Purchases
  /// Makes a purchase with RevenueCat and returns its result. This gets called when
  /// someone tries to purchase a product on one of your paywalls.
  func purchase(product: SKProduct) async -> PurchaseResult {
    do {
      let storeProduct = RevenueCat.StoreProduct(sk1Product: product)
      let revenueCatResult = try await Purchases.shared.purchase(product: storeProduct)
      if revenueCatResult.userCancelled {
        return .cancelled
      } else {
        return .purchased
    } catch let error as ErrorCode {
      if error == .paymentPendingError {
        return .pending
      } else {
        return .failed(error)
    } catch {
      return .failed(error)

  // MARK: Handle Restores
  /// Makes a restore with RevenueCat and returns true, unless an error is thrown.
  /// This gets called when someone tries to restore purchases on one of your paywalls.
  func restorePurchases() async -> RestorationResult {
    do {
      _ = try await Purchases.shared.restorePurchases()
      return .restored
    } catch let error {
      return .failed(error)

As discussed in Purchases and Subscription Status, this PurchaseController is responsible for handling the subscription-related logic. Take a few moments to look through the code to understand how it does this.

2. Configure Superwall

Initialize an instance of RCPurchaseController and pass it in to Superwall.configure(apiKey:purchaseController):

let purchaseController = RCPurchaseController()

  apiKey: "superwall_api_key", 
  purchaseController: purchaseController

3. Sync the subscription status

Then, call purchaseController.syncSubscriptionStatus() to keep Superwall's subscription status up to date with RevenueCat.

That's it! Check out our RevenueCat example app for a working example of this integration.