ScaleRocket/Mobile

Mobile Payments

In-app purchases with RevenueCat for iOS and Android subscriptions, and why Stripe direct doesn't work on mobile.

Mobile Payments

In-app purchases on iOS and Android must go through Apple and Google's payment systems. You cannot use Stripe's checkout directly for digital goods sold inside a mobile app.

Why Not Stripe Direct?

Apple and Google require that digital goods and subscriptions sold within apps use their in-app purchase (IAP) systems:

PlatformRequirementCommission
iOSApple IAP required for digital goods15-30%
AndroidGoogle Play Billing required for digital goods15-30%

Stripe can still be used for: physical goods, services performed outside the app, or web-based subscriptions that don't unlock in-app content.

RevenueCat

RevenueCat is the recommended solution. It wraps both Apple and Google IAP APIs into a single, simple SDK:

npx expo install react-native-purchases

Setup

import Purchases from "react-native-purchases";
import { Platform } from "react-native";

async function initRevenueCat() {
  Purchases.configure({
    apiKey: Platform.OS === "ios"
      ? "appl_your_ios_api_key"
      : "goog_your_android_api_key",
  });
}

Call this in your root layout:

// app/_layout.tsx
useEffect(() => {
  initRevenueCat();
}, []);

Display Products

async function loadOfferings() {
  const offerings = await Purchases.getOfferings();
  const current = offerings.current;

  if (current) {
    const monthly = current.monthly;  // Monthly package
    const annual = current.annual;    // Annual package

    return { monthly, annual };
  }
}

Purchase a Subscription

async function purchaseSubscription(packageToPurchase: PurchasesPackage) {
  try {
    const { customerInfo } = await Purchases.purchasePackage(packageToPurchase);
    const isPro = customerInfo.entitlements.active["pro"] !== undefined;

    if (isPro) {
      // Unlock premium features
      router.push("/dashboard");
    }
  } catch (error: any) {
    if (!error.userCancelled) {
      Alert.alert("Purchase Failed", error.message);
    }
  }
}

Check Subscription Status

Sync subscription status with your Supabase database using RevenueCat webhooks:

// Check locally first
const customerInfo = await Purchases.getCustomerInfo();
const isPro = customerInfo.entitlements.active["pro"] !== undefined;

// RevenueCat webhook updates your Supabase database
// Configure at: RevenueCat Dashboard > Integrations > Webhooks
// Endpoint: https://your-project.supabase.co/functions/v1/revenucat-webhook

Sync subscription status with Convex using RevenueCat webhooks:

// Check locally first
const customerInfo = await Purchases.getCustomerInfo();
const isPro = customerInfo.entitlements.active["pro"] !== undefined;

// RevenueCat webhook calls your Convex HTTP action
// Configure at: RevenueCat Dashboard > Integrations > Webhooks
// Endpoint: https://your-project.convex.site/revenucat-webhook

Restore Purchases

Required by Apple — users must be able to restore purchases on new devices:

async function restorePurchases() {
  try {
    const customerInfo = await Purchases.restorePurchases();
    const isPro = customerInfo.entitlements.active["pro"] !== undefined;
    Alert.alert(isPro ? "Restored!" : "No active subscription found");
  } catch (error) {
    Alert.alert("Error", "Could not restore purchases");
  }
}

Paywall Screen

Build a paywall screen:

function PaywallScreen() {
  const [offerings, setOfferings] = useState<PurchasesOfferings | null>(null);

  useEffect(() => {
    Purchases.getOfferings().then(setOfferings);
  }, []);

  return (
    <ScreenLayout>
      <Text style={styles.title}>Upgrade to Pro</Text>
      <Text style={styles.subtitle}>Unlock all features</Text>

      {offerings?.current?.availablePackages.map((pkg) => (
        <TouchableOpacity key={pkg.identifier} onPress={() => purchaseSubscription(pkg)}>
          <Text>{pkg.product.title}</Text>
          <Text>{pkg.product.priceString}/month</Text>
        </TouchableOpacity>
      ))}

      <Button title="Restore Purchases" variant="ghost" onPress={restorePurchases} />
    </ScreenLayout>
  );
}

App Store Setup

  1. Create subscriptions in App Store Connect (iOS) and Google Play Console (Android)
  2. Add product IDs to RevenueCat dashboard
  3. Create Entitlements (e.g., "pro") and link them to products
  4. Configure webhook endpoints for server-side validation

On this page