Superwall
Components

CustomPurchaseControllerProvider

A modern, hooks-based approach to handling purchases and purchase restores with the Superwall SDK.

The CustomPurchaseControllerProvider component allows you to integrate your own purchase handling logic with the Superwall SDK. It provides a modern, hooks-based approach to handling purchases and purchase restores.

Usage

import { CustomPurchaseControllerProvider } from 'expo-superwall'
import { SuperwallProvider } from 'expo-superwall'

export default function App() {
  return (
    <CustomPurchaseControllerProvider
      controller={{
        onPurchase: async (params) => {
          if (params.platform === "ios") {
            console.log("iOS purchase:", params)
            // Handle iOS purchase with StoreKit
          } else {
            console.log("Android purchase:", params.productId)
            // Handle Android purchase with Google Play Billing
          }
        },
        onPurchaseRestore: async () => {
          console.log("Restore purchases requested")
          // Handle restore purchases logic
        },
      }}
    >
      <SuperwallProvider apiKeys={{ ios: "YOUR_IOS_KEY", android: "YOUR_ANDROID_KEY" }}>
        {/* Your app content */}
      </SuperwallProvider>
    </CustomPurchaseControllerProvider>
  )
}

Important: The onPurchase and onPurchaseRestore callbacks communicate the outcome through the resolved value or an error:

  • Return/resolve void or a success result → Superwall records a successful purchase or restore
  • Return a failure/cancelled result or throw → Superwall records a failed or cancelled outcome

If your purchase function returns a status like "cancelled" or "error", return a PurchaseResult with that type (or throw) so Superwall records the correct outcome:

onPurchase: async (params) => {
  const result = await yourPurchaseFunction(params.productId);

  if (result !== "success") {
    return { type: "failed", error: `Purchase ${result}` };
  }

  // Only reaches here on success
},

Why this matters: If your callback resolves without signaling failure, Superwall will count it as a conversion.

Props

Prop

Type

CustomPurchaseControllerContext

Prop

Type

OnPurchaseParams (iOS)

Prop

Type

OnPurchaseParams (Android)

Prop

Type

PurchaseResult

Prop

Type

RestoreResult

Prop

Type

Hook

useCustomPurchaseController()

A hook that provides access to the custom purchase controller context from child components.

import { useCustomPurchaseController } from 'expo-superwall'

function MyComponent() {
  const controller = useCustomPurchaseController()
  
  if (!controller) {
    // Not within a CustomPurchaseControllerProvider
    return null
  }
  
  const handlePurchase = async () => {
    // Access controller methods if needed
  }
  
  return <Button onPress={handlePurchase}>Purchase</Button>
}

Prop

Type

How It Works

The CustomPurchaseControllerProvider listens for purchase events from the Superwall SDK using the useSuperwallEvents hook internally. When a purchase or restore event occurs:

  1. It calls your provided onPurchase or onPurchaseRestore method
  2. After your method completes, it notifies the Superwall SDK that the purchase was successful
  3. Superwall then dismisses the paywall and continues with the user flow

Integration with RevenueCat

For a complete RevenueCat integration with error handling, subscription status synchronization, and working examples, see the Using RevenueCat guide.

Notes

  • The provider must wrap your app at a level where both the Superwall SDK and your purchase logic can access it
  • Purchase success/failure handling is automatic - you just need to perform the actual purchase

How is this guide?

Edit on GitHub