Skip to main content

Overview

This guide will help you migrate from the legacy react-native-superwall SDK to the new expo-superwall SDK. The new SDK is built specifically for Expo and requires Expo SDK 53 or newer.
Expo SDK 53+ Required: This SDK only supports Expo SDK version 53 and newer. If you’re using an older Expo version, continue using the legacy React Native SDK.

Choose Your Migration Path

You have two options for migrating to expo-superwall:

Hooks-based SDK

Recommended for most projects. Modern React hooks interface with better TypeScript support and developer experience.

Compat SDK

Quick migration path. Drop-in replacement with minimal code changes. Uses the familiar class-based API.
If you’re starting a new project or want the best developer experience, choose the Hooks-based SDK. If you need to migrate quickly with minimal changes, use the Compat SDK.

Option 1: Hooks-based SDK

The hooks-based SDK provides a modern React interface with better state management and TypeScript support.

Step 1: Update Dependencies

First, uninstall the old package and install the new one:
npm uninstall react-native-superwall
npx expo install expo-superwall

Step 2: Replace Configuration

import Superwall from 'react-native-superwall';

// In your app initialization
await Superwall.configure({
  apiKey: 'your_api_key',
  options: {
    // options
  },
});

Step 3: Migrate User Management

import Superwall from 'react-native-superwall';

// Identify user
await Superwall.shared.identify({ userId: 'user_123' });

// Set user attributes
await Superwall.shared.setUserAttributes({
  name: 'John Doe',
  email: '[email protected]',
});

// Reset user
await Superwall.shared.reset();

Step 4: Migrate Paywall Registration

import Superwall from 'react-native-superwall';

// Register placement
await Superwall.shared.register({
  placement: 'my_placement',
  feature: () => {
    // Feature logic
    console.log('Feature unlocked!');
  },
});

Step 5: Migrate Event Handling

import Superwall, { SuperwallDelegate } from 'react-native-superwall';

class MyDelegate extends SuperwallDelegate {
  handleSuperwallEvent(eventInfo) {
    console.log('Event:', eventInfo.event.type);
  }

  subscriptionStatusDidChange(from, to) {
    console.log('Subscription changed:', from, to);
  }
}

const delegate = new MyDelegate();
await Superwall.shared.setDelegate(delegate);

Step 6: Handle Loading States

The new SDK provides components to handle loading states:
import { 
  SuperwallProvider,
  SuperwallLoading,
  SuperwallLoaded,
  SuperwallError 
} from 'expo-superwall';

export default function App() {
  return (
    <SuperwallProvider apiKeys={{ ios: API_KEY }}>
      <SuperwallLoading>
        <ActivityIndicator style={{ flex: 1 }} />
      </SuperwallLoading>

      <SuperwallError>
        {(error) => (
          <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Failed to initialize: {error}</Text>
          </View>
        )}
      </SuperwallError>

      <SuperwallLoaded>
        <MainApp />
      </SuperwallLoaded>
    </SuperwallProvider>
  );
}

Option 2: Compat SDK (Quick Migration)

For a faster migration path with minimal code changes, use the compat SDK. See the Compat SDK Guide for detailed instructions.

Breaking Changes

Version 1.0.0+

Removed: The collectAdServicesAttribution option has been removed. AdServices attribution is now collected automatically by the native iOS SDK.

Package Name

  • Old: react-native-superwall
  • New: expo-superwall

Minimum Requirements

  • Expo SDK: Version 53 or newer required
  • React Native: Version compatible with Expo SDK 53+

Configuration

  • SDK is now configured via <SuperwallProvider> component instead of imperative configure() call
  • API keys are now separated by platform (ios and android)

API Differences

Old APINew Hooks APINotes
Superwall.shared.identify()useUser().identify()Must be called inside a component
Superwall.shared.setUserAttributes()useUser().update()Supports updater function
Superwall.shared.reset()useUser().signOut()Renamed for clarity
Superwall.shared.register()usePlacement().registerPlacement()Callbacks moved to hook options
SuperwallDelegate classuseSuperwallEvents() hookEvent-based instead of class-based
Superwall.shared.dismiss()useSuperwall().dismiss()Same functionality
Superwall.shared.preloadAllPaywalls()useSuperwall().preloadAllPaywalls()Same functionality

New Configuration Options

Version 1.0.0 added several new configuration options:
<SuperwallProvider
  apiKeys={{ ios: API_KEY }}
  options={{
    // New iOS & Android option
    shouldObservePurchases: true, // Observe purchases made outside Superwall
    
    // New iOS-only options
    shouldBypassAppTransactionCheck: false, // Disable app transaction check
    maxConfigRetryCount: 6, // Number of config fetch retries
    
    // New Android-only option
    useMockReviews: false, // Enable mock review functionality
  }}
/>

Migration Checklist

1

Update dependencies

Uninstall react-native-superwall and install expo-superwall
2

Choose your approach

Decide between Hooks-based SDK (recommended) or Compat SDK (quick migration)
3

Update configuration

Replace Superwall.configure() with <SuperwallProvider> or Superwall.configure() in compat
4

Migrate user management

Update identify, setUserAttributes, and reset calls
5

Migrate paywall registration

Update placement registration calls
6

Migrate event handling

Replace SuperwallDelegate with event hooks or keep using compat delegate
7

Test thoroughly

Test all paywall flows, user identification, and event handling

Common Migration Issues

Issue: “Expo SDK version not supported”

Solution: Upgrade to Expo SDK 53 or newer, or continue using the legacy react-native-superwall package.

Issue: “Cannot access Superwall.shared before configure”

Solution: With the Hooks SDK, ensure your components are wrapped in <SuperwallProvider>. With the Compat SDK, call Superwall.configure() before accessing Superwall.shared.

Issue: “User attributes not updating”

// ❌ Wrong: Direct object
await update({ name: 'John' });

// ✅ Correct: Use updater function to merge with existing attributes
await update((oldAttributes) => ({
  ...oldAttributes,
  name: 'John',
}));

Getting Help

If you encounter issues during migration:

Next Steps

Compat SDK Guide

Learn about the quick migration path using the compatibility SDK

API Reference

Explore the complete API documentation

Build docs developers (and LLMs) love