Skip to main content

Quickstart

This guide will walk you through setting up the Expo Superwall SDK and displaying your first paywall.

Step 1: Wrap Your App with SuperwallProvider

The SuperwallProvider initializes the SDK with your API key. Wrap your app’s root component:
App.tsx
import { SuperwallProvider } from "expo-superwall";

export default function App() {
  return (
    <SuperwallProvider apiKeys={{ ios: "YOUR_SUPERWALL_API_KEY" /* android: API_KEY */ }}>
      {/* Your app content goes here */}
    </SuperwallProvider>
  );
}
Find your API key in your Superwall dashboard. You can provide separate keys for iOS and Android, or use the same key for both platforms.

Step 2: Handle Loading States

While the SDK initializes, show a loading indicator using the SuperwallLoading and SuperwallLoaded components:
App.tsx
import {
  SuperwallProvider,
  SuperwallLoading,
  SuperwallLoaded,
} from "expo-superwall";
import { ActivityIndicator, View, Text } from "react-native";

const API_KEY = "YOUR_SUPERWALL_API_KEY";

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

function MainAppScreen() {
  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      <Text>Superwall SDK is ready!</Text>
    </View>
  );
}

Step 3: Identify Your User

Use the useUser hook to identify users when they log in:
UserManagement.tsx
import { useUser } from "expo-superwall";
import { Button, Text, View } from "react-native";

function UserManagementScreen() {
  const { identify, user, signOut, subscriptionStatus } = useUser();

  const handleLogin = async () => {
    // Identify the user with a unique ID
    await identify(`user_${Date.now()}`);
  };

  const handleSignOut = async () => {
    await signOut();
  };

  return (
    <View style={{ padding: 20 }}>
      <Text>Subscription Status: {subscriptionStatus?.status ?? "unknown"}</Text>
      {user && <Text>User ID: {user.appUserId}</Text>}

      <Button title="Login" onPress={handleLogin} />
      <Button title="Sign Out" onPress={handleSignOut} />
    </View>
  );
}
User identification is important for tracking subscription status and personalizing the paywall experience.

Step 4: Trigger a Paywall

Use the usePlacement hook to show paywalls at strategic points in your app:
PaywallTrigger.tsx
import { usePlacement } from "expo-superwall";
import { Alert, Button, View } from "react-native";

function PaywallScreen() {
  const { registerPlacement } = usePlacement({
    onError: (err) => console.error("Placement Error:", err),
    onPresent: (info) => console.log("Paywall Presented:", info),
    onDismiss: (info, result) =>
      console.log("Paywall Dismissed:", info, "Result:", result),
  });

  const handleTriggerPlacement = async () => {
    await registerPlacement({
      placement: "your_placement_id", // Replace with your actual placement ID
      feature() {
        // This function is called if the user is already subscribed
        // or successfully subscribes through the paywall.
        console.log("Feature unlocked!");
        Alert.alert("Feature Unlocked!", "You can now access this feature.");
      },
    });
  };

  return (
    <View style={{ padding: 20 }}>
      <Button title="Unlock Premium Feature" onPress={handleTriggerPlacement} />
    </View>
  );
}
Replace "your_placement_id" with an actual placement ID from your Superwall dashboard. Placements are configured remotely and determine when and how paywalls are shown.

Complete Example

Here’s a complete working example combining all the steps:
App.tsx
import {
  SuperwallProvider,
  SuperwallLoading,
  SuperwallLoaded,
  useUser,
  usePlacement,
} from "expo-superwall";
import { ActivityIndicator, Alert, Button, Text, View, StyleSheet } from "react-native";

const API_KEY = "YOUR_SUPERWALL_API_KEY";

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

function MainAppScreen() {
  const { identify, user, subscriptionStatus } = useUser();
  const { registerPlacement } = usePlacement({
    onPresent: (info) => console.log("Paywall presented:", info.name),
    onDismiss: (info, result) => console.log("Dismissed with:", result),
  });

  const handleLogin = async () => {
    await identify(`user_${Date.now()}`);
  };

  const handleShowPaywall = async () => {
    await registerPlacement({
      placement: "campaign_trigger",
      feature() {
        Alert.alert("Success!", "You now have access to premium features.");
      },
    });
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Expo Superwall SDK Demo</Text>
      
      <View style={styles.section}>
        <Text>Status: {subscriptionStatus?.status ?? "unknown"}</Text>
        {user && <Text>User: {user.appUserId}</Text>}
      </View>

      <View style={styles.buttonContainer}>
        <Button title="Login" onPress={handleLogin} />
        <Button title="Show Paywall" onPress={handleShowPaywall} />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: "center",
  },
  title: {
    fontSize: 24,
    fontWeight: "bold",
    marginBottom: 20,
    textAlign: "center",
  },
  section: {
    marginVertical: 20,
    padding: 15,
    backgroundColor: "#f5f5f5",
    borderRadius: 8,
  },
  buttonContainer: {
    gap: 10,
  },
});

What’s Next?

You now have a working Superwall integration! Here are some next steps:

Update User Attributes

Learn how to track custom user properties for targeting and personalization

Handle Events

Set up event listeners to track paywall interactions and analytics

Error Handling

Implement robust error handling for offline scenarios

Advanced Configuration

Explore advanced SDK options and customization

Build docs developers (and LLMs) love