# Superwall: Subscription Infrastructure for iOS, Android, and Web

Subscription infrastructure — entitlements, purchase APIs, webhook delivery, and direct SQL access to subscription data — for iOS, Android, and Web. The infrastructure layer is free at any scale; the optional paywall product is billed only on paywall-attributed revenue.

## Pricing

- **Infrastructure: free at any scale, every plan.** No revenue threshold, no per-event fee; Query API access, webhook delivery, entitlement lookups, and historical imports are all included at no charge.
- **Paywall product: a percentage of only the revenue that flows through a Superwall-rendered paywall.** Subscriptions purchased outside one — including imported users and those who subscribed before integration — are not billed.

Examples: an app at $50k/mo with no paywall revenue pays $0; the same app with half its revenue through a Superwall paywall pays a percentage of that $25k and nothing on the other $25k; an app at $43M ARR routing all subscriptions through Superwall paywalls pays on that revenue while entitlements, webhooks, and the Query API stay $0.

## Scale

$1.5B+ annual subscription revenue across 10,000+ apps. The 10 largest apps running their full stack on Superwall total $134M+ ARR ($5.7M–$43.7M each). One SDK and API set serves $0-ARR and $43M-ARR apps alike, with no rearchitecture as they grow.

## Infrastructure capabilities

- **Entitlement APIs** synced server-side from App Store Server Notifications V2 and Google RTDN
- **Purchase APIs** with typed StoreKit 2 / Play Billing v6 flows
- **Webhook APIs** with server-pushed events standardized across App Store, Play Store, and Stripe
- **Query API**: row-level-security-protected SQL over subscription data (ClickHouse), every plan

Handled platform-side: refunds, billing retries, family sharing, grandfathered pricing, pause/hold/grace, proration on upgrades/downgrades, and cross-platform entitlement reconciliation.

## Migration

Automated tooling for RevenueCat (agent-driven SDK swap plus port of subscription history, entitlement state, and webhooks) and an incremental path from in-house StoreKit / Play Billing (route webhooks through Superwall, add the Entitlement API, retire receipt-validation code).

## Paywall product (optional, separately billable)

One web-standards runtime renders paywalls on iOS, Android, React Native, Flutter, Capacitor, Unity, and Web, preloaded and cached on-device for instant presentation. Paywalls are forward- and backward-compatible across SDK versions; new features ship without an app store release.

## Architecture

Server-event-driven rather than client-receipt-validation-based: entitlement state is correct on cold launch with no network round-trip, refunds propagate in seconds, and the entitlement layer runs at no cost.

## Docs

* Migrate from RevenueCat: https://superwall.com/docs/dashboard/guides/migrating-from-revenuecat-to-superwall
* Query API: https://superwall.com/docs/dashboard/guides/query-clickhouse
* Webhooks: https://superwall.com/docs/integrations/webhooks
* Pricing: https://superwall.com/pricing

# Teleport

Send users from an iOS paywall to a checkout page you design, take payment in the browser, and bring them back to the app.

Teleport sends a user from your iOS paywall to a page of that same paywall running in their browser. The user pays there with Apple Pay or a card, then returns to your app with access unlocked.

[App2Web](/docs/web-checkout/web-checkout-direct-stripe-checkout) opens Stripe Checkout in the browser. Teleport opens a page you design in the paywall editor instead, so the browser step keeps your paywall's look, copy and products. In the editor, this page is called the **Checkout Page**.

> **Note:** Teleport requires the Superwall iOS SDK 4.18.0 or later. On Android, and on older iOS SDK versions, buying a Stripe product from the paywall opens Stripe Checkout in the browser instead.

> **Note:** Teleport is turned on per app. The checkout page options appear once the paywall has a Stripe product. If you still don't see them, contact Superwall support.

## How it works

1. A user opens your paywall in the app. Superwall prepares the checkout page in the background so it usually opens without a wait.
2. The user taps a button that buys a Stripe product, or a button that routes to the checkout page.
3. The checkout page opens in the user's default browser on your web paywall domain, with the tapped product selected.
4. In the app, the paywall stays open and shows a waiting screen.
5. The user pays on the checkout page with Apple Pay or the payment sheet.
6. The checkout page shows **You're all set** with a **Return to App** button.
7. Your app opens, redeems the purchase and runs the purchase button's after-purchase actions.

The checkout page receives the user's state from the app, including [user attributes](/docs/ios/quickstart/setting-user-properties), placement parameters, paywall state and form input values. Free trial eligibility and the paywall, experiment and variant that started the checkout carry over too, so the sale is attributed to the paywall the user saw in the app.

## Requirements

* **iOS SDK 4.18.0 or later.**
* **Web Checkout setup.** Your iOS app must be in a project that has a Web Checkout app with a [web paywall domain](/docs/web-checkout/web-checkout-configuring-stripe-keys-and-settings#web-paywall-domain). The checkout page opens on that domain. See [Creating an app](/docs/web-checkout/web-checkout-creating-an-app) and [Stripe setup](/docs/web-checkout/web-checkout-configuring-stripe-keys-and-settings).
* **A Stripe product on the paywall.** See [Managing products](/docs/web-checkout/web-checkout-adding-a-stripe-product).
* **Stripe app iOS configuration.** In your Stripe app's settings, under **iOS configuration**, fill in **Apple Custom URL Scheme**, **Bundle ID** and **Team ID**. Superwall builds the links that return users to your app from these values. See [iOS configuration](/docs/web-checkout/web-checkout-configuring-stripe-keys-and-settings#ios-configuration).
* **Deep link handling.** Your app must pass incoming URLs to Superwall. See [Deep links](/docs/ios/quickstart/in-app-paywall-previews).

## Set up the checkout page

## Add a checkout page to your paywall

In the paywall editor, add a page to a multi-page paywall for checkout. Design it like any other page, and add a button that purchases a Stripe product.

## Mark the page as the checkout page

On the canvas, click the globe icon under the page (**Use as the checkout page**). You can also right-click the page and choose **Use as Checkout Page**. The page is labeled **Checkout Page** and shows in a browser frame.A paywall has one checkout page. Marking a page removes its outgoing routes and any setting that would open the paywall on it, so the paywall always starts in the app.

## Connect your in-app pages to the checkout page

Route buttons on your in-app pages to the checkout page. On the canvas, these connections are labeled **Opens in Browser**. Tapping one buys the selected product on the checkout page. Any button on an in-app page that purchases a Stripe product also opens the checkout page.Auto-advancing pages stop on the page before the checkout page. Only a tap opens the browser.

## Choose how users pay

Open the paywall's settings. **Web Checkout Location** shows **Checkout Page**, and the **Checkout Page** section shows **Opens in the browser on** followed by your web paywall subdomain. Under **Checkout Page Payment**, choose:- **Apple Pay** (default): Apple Pay where the browser supports it, the payment sheet everywhere else.
- **Payment Sheet**: a card payment sheet on the checkout page.Apple Pay doesn't support [Managed Payments](/docs/web-checkout/web-checkout-managed-payments). Purchases made with Apple Pay go through your regular Stripe payments.To show Apple Pay, add your web paywall domain to Stripe's payment method domains. See [Apple Pay domain setup](/docs/web-checkout/web-checkout-configuring-stripe-keys-and-settings#apple-pay-domain-setup).

## Set free trial behavior

Under **Web Free Trial**, choose:- **Match App** (default): the checkout page offers the trial only when the app says the user is eligible.
- **Always**: the checkout page offers the trial to everyone.

## Show the paywall to eligible users

Publish the paywall and add it to a [campaign](/docs/dashboard/dashboard-campaigns/campaigns). Teleport links users out of your app to buy, so use the same United States storefront audience filter described in [App2Web](/docs/web-checkout/web-checkout-direct-stripe-checkout).Users on iOS SDK versions older than 4.18.0 get Stripe Checkout instead of the checkout page. To show the checkout page only to users who can see it, add an audience filter for app versions that ship SDK 4.18.0 or later.

### Checkout page warnings

The editor shows a warning under the checkout page when it can't take payment:

| Warning                                                                            | Fix                                            |
| ---------------------------------------------------------------------------------- | ---------------------------------------------- |
| Add a button that buys a product, so shoppers can pay here.                        | Add a purchase button to the checkout page.    |
| A button buys a product slot this paywall doesn't have.                            | Point the button at a product the paywall has. |
| A button buys an App Store or Google Play product. Only Stripe products sell here. | Change the button to a Stripe product.         |

If the paywall's project isn't set up for Web Checkout, the **Checkout Page** settings section says what's missing:

* **Add this app to a project with a Stripe app to use a checkout page.**
* **Add a Stripe app to this project to use a checkout page.**
* **Set up a web paywall domain on this project's Stripe app. That's where the checkout page opens.**

### Buttons on the checkout page

On the checkout page, a **Close** action is labeled **Return to App** and a back navigation is labeled **Back to App**. Both open your app without a purchase. The app checks whether a payment went through without showing a purchase loader.

Actions that need the app aren't available on the checkout page, such as restoring purchases, requesting permissions, requesting a review, custom actions, custom placements and setting attributes.

## Add the Superwall link domain

When the user taps **Return to App**, the checkout page opens your app through a universal link on `<subdomain>.superwall.link`, where `<subdomain>` is your web paywall subdomain. Add that domain to your app's associated domains so the app opens without an alert:

1. In Xcode, select your app target and open **Signing & Capabilities**.
2. Add the **Associated Domains** capability if your app doesn't have it.
3. Add `applinks:<subdomain>.superwall.link`. For example, if your web paywall domain is `myapp.superwall.app`, add `applinks:myapp.superwall.link`.

Without this entry, **Return to App** uses your app's URL scheme and iOS asks &#x2A;*Open in App?** first. If neither link is available, the page tells the user they can go back to the app, with no button.

Return links don't dismiss the paywall and don't track `deepLink_open`. They reach Superwall through the same `handleDeepLink` call you use for other [Superwall deep links](/docs/ios/quickstart/in-app-paywall-previews).

## While the user is in the browser

The paywall in your app shows a waiting screen:

* **Finish in your browser**: the title.
* **Complete in Browser**: reopens the checkout page.
* **Cancel**: closes the waiting screen and runs the purchase button's On Abandon actions. If the user still pays in the browser within a few minutes, the app redeems the purchase.

The app checks the checkout's status in the background. When the payment completes, the app gets access even if the user doesn't tap **Return to App**.

## Handle the purchase in your app

Superwall redeems a checkout page purchase in your app, so no redemption email is sent. Once it's redeemed:

* Entitlements and subscription status update, as with any [web checkout purchase](/docs/ios/guides/web-checkout/post-checkout-redirecting).
* `willRedeemLink()` and `didRedeemLink(result:)` are called on your `SuperwallDelegate`, unchanged from web checkout.
* `transaction_complete` fires, attributed to the paywall.
* The purchase button's after-purchase actions run. The paywall is dismissed, with a `.purchased` result, when those actions close it or when the button has none. A purchase started from an **Opens in Browser** connection always dismisses the paywall.

Unlike other web checkout purchases, a checkout page purchase doesn't dismiss the paywall automatically when it's redeemed.

If you use RevenueCat or your own `PurchaseController`, follow [Using RevenueCat](/docs/ios/guides/web-checkout/using-revenuecat) or [Redeeming In-App](/docs/ios/guides/web-checkout/linking-membership-to-iOS-app).

## Events

| Event                                               | When it fires                                                                                     |
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `teleport_open` (`SuperwallEvent.teleportOpen`)     | The paywall opens its checkout page in the browser.                                               |
| `teleport_return` (`SuperwallEvent.teleportReturn`) | A return link brings the user back to the app. Its `reason` parameter is `purchased` or `closed`. |

Both events show on the user's event timeline in the dashboard. Purchases on the checkout page also report `transaction_start` and `transaction_complete` with the paywall, experiment and variant that started the checkout.

## Limits

* **Link lifetime:** a checkout page link expires 30 minutes after it's created if the user hasn't started paying. The page then shows **Checkout expired**, and the user isn't charged.
* **One purchase per paywall presentation:** once the user pays in one checkout, other checkouts from the same presentation close. Opening one shows &#x2A;*You already bought this in another checkout, so you weren't charged again.**
* **Visual editor only:** checkout pages are set up in the paywall editor. [Superwall Framework](/docs/framework) paywalls use [Web Checkout](/docs/framework/web-checkout) modes instead.