Web Checkout
Sell the same paywall on the web with one config key — Stripe payment in a sheet, Apple Pay, or a hosted checkout page, with purchase() unchanged.
One config key sells the same paywall on the web:
checkout: "sheet",Native hosts ignore it — drop the same paywall into your iOS app and it buys through the App Store. Your components don't change, and neither does purchase().
This page covers the framework side: config, modes, and prefetching. Stripe keys, web apps, products, and campaigns are set up in the dashboard — see the Web Checkout section for that half.
Modes
| Mode | The purchase | Use when |
|---|---|---|
sheet | Stripe checkout in a sheet over the paywall — nobody leaves mid-flow | The default choice for the web |
applePay | Straight to Apple Pay where available, sheet as fallback | Apple-Pay-heavy audiences |
external | Superwall's hosted checkout page, then back | You want zero payment UI in the paywall |
Only sheet and applePay add payment UI to the paywall (about 85 kB); external adds nothing.
Products
Web paywalls sell Stripe products, declared with the price inside the identifier — {environment}:{priceId}:{offer}:
products: {
monthly: "live:price_1ABC…:7days-free",
},A paywall can declare store and Stripe products side by side. See Products.
The purchase, unchanged
With sheet or applePay and a Stripe product, the same purchase() call opens the payment sheet in-page — a brief loading overlay covers the session creation unless it was prefetched. The outcomes map exactly as they do natively:
completed— payment succeededabandoned— the shopper closed the sheetfailed— a payment or session error
The web sheet does not set isPurchasing — react to the awaited result, which is the right pattern everywhere anyway. A web paywall also typically drops the close button and restore link its native sibling carries: there's no host app to close back to.
Prefetch — make the sheet open instantly
Creating a checkout session takes a network round-trip. Prefetching does it before the tap, so the sheet opens with nothing to wait for.
Automatic: every sheet/applePay paywall warms its first Stripe product on load. Steer it in config:
checkout: { mode: "sheet", prefetch: "pro" } // which product warms first
checkout: { mode: "sheet", prefetch: false } // disable auto-prefetchOn selection — do this whenever there's a product selector. The default warms one plan; prefetch the selected one so whichever plan is on screen opens instantly:
import { usePurchase, type ProductReference } from "superwall/hooks";
const { purchase, prefetch } = usePurchase();
const [reference, setReference] = React.useState<ProductReference>("monthly");
React.useEffect(() => {
prefetch(reference);
}, [prefetch, reference]);prefetch is safe to call unconditionally — it's a no-op for store products, for paywalls without web checkout, and for already-warm sessions (sessions stay warm for about ten minutes). It's a hint; never await it.
The sheet is not yours to style
It takes no colors, fonts, or spacing from the page around it, and there's no prop to change that. This is deliberate: payment UI that borrows the paywall's design stops looking like payment UI — and the payment step is the one place a shopper is entitled to see something they recognize. Safe areas, scroll locking, and Escape handling (never mid-payment) are handled for you.
Verify on a pushed version
superwall dev previews the flow and the copy, but it does not mount the payment sheet. Push and open the live URL to verify the checkout itself — see Push, promote & publish.
A full web funnel
The web-funnel example is the reference: question steps as pages, a typed plan selector with on-selection prefetch, then purchase(reference) — the whole flow in one paywall.
How is this guide?
Free Trials
Fork your paywall on trial eligibility the store reports, pull trial terms from product variables, and remind users before a trial ends.
Variables & Personalization
React to user attributes, device state, and placement parameters — and write paywalls the dashboard can experiment on without a rebuild.