# 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

# Examples

Complete, standalone example projects — each teaching exactly one idea, from a minimal paywall to trials, funnels, and Rive animations.

Every example is a complete, standalone framework project teaching exactly **one idea**. Styling is deliberately plain so the mechanism is the thing you read. When what you're building matches one, read it before writing code — each `README.md` explains the idea, and every example runs as-is.

## Use an example

```bash
superwall create --example multi-page   # scaffold it as a new project
superwall dev                            # open it in the studio
```

All examples are public at [github.com/superwall/superwall/tree/main/examples](https://github.com/superwall/superwall/tree/main/examples) — browse them there, or copy a directory anywhere for a working `superwall dev`.

## Fundamentals

| Example                                                                                            | The one idea                                                                     | Reach for it when          |
| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------- |
| [`minimal`](https://github.com/superwall/superwall/tree/main/examples/minimal)                     | One page, one product, purchase — a paywall is a React component, not a template | Starting anything          |
| [`product-selection`](https://github.com/superwall/superwall/tree/main/examples/product-selection) | Selection state is ordinary React — the framework has no "selected plan" concept | Multiple plans, price rows |

`minimal` shows the canonical price guard (render the price only when it exists, with bare copy as the fallback). `product-selection` adds a typed plan union, `haptics.selection()` on choice vs `haptics.light()` on the CTA, a real radiogroup with `aria-checked`, store-formatted `price` and `monthlyPrice` side by side, and a designed unpriced state.

## Navigation

| Example                                                                                        | The one idea                                                                                   |
| ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [`multi-page`](https://github.com/superwall/superwall/tree/main/examples/multi-page)           | `router.push`/`back`, the page stack, and chrome in `layout.tsx` that reads router state       |
| [`transitions`](https://github.com/superwall/superwall/tree/main/examples/transitions)         | All four built-ins plus a custom `zoom` — proof a transition is just CSS on two attributes     |
| [`onboarding-quiz`](https://github.com/superwall/superwall/tree/main/examples/onboarding-quiz) | Answers decide where you land; the router carries no state (a plain module outside React does) |

`onboarding-quiz`'s terminal page defends every read — a replayed page never crashes on a missing answer — and hardcodes step labels per page, because a branching flow's depth is not its step number.

## Purchases

| Example                                                                                            | The one idea                                                                                                                     |
| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| [`purchase-states`](https://github.com/superwall/superwall/tree/main/examples/purchase-states)     | The two channels: what your `purchase()` call resolves vs what the SDK reports on its own                                        |
| [`trial-eligibility`](https://github.com/superwall/superwall/tree/main/examples/trial-eligibility) | Two paywalls in one, chosen by the store — every string forks and both states read as intentional                                |
| [`abandonment-offer`](https://github.com/superwall/superwall/tree/main/examples/abandonment-offer) | `purchase()` resolving `abandoned` is a signal only this paywall can act on — a last-chance offer on a custom `sheet` transition |
| [`trial-reminders`](https://github.com/superwall/superwall/tree/main/examples/trial-reminders)     | A local notification declared in config, scheduled by the SDK when the trial starts                                              |
| [`web-funnel`](https://github.com/superwall/superwall/tree/main/examples/web-funnel)               | Selling on the web: steps as pages, then `checkout: "sheet"` — one config key, `purchase()` unchanged                            |

`purchase-states` is the only example showing the full haptic vocabulary (`success()` / `error()` keyed to outcomes). `abandonment-offer` holds the deepest CSS lesson of the set: the scrim behind its sheet reuses the framework's timing variables, so one number drives both the page dim and the backdrop — see [Transitions](/docs/framework/transitions).

## The host

| Example                                                                                        | The one idea                                                                                                   |
| ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| [`personalization`](https://github.com/superwall/superwall/tree/main/examples/personalization) | `useVariables()` — device, user, placement params, and guarding every read                                     |
| [`permissions`](https://github.com/superwall/superwall/tree/main/examples/permissions)         | `requestPermission` (asks the OS) vs `requestCallback` (asks *your app*); a denial is an outcome, not an error |

## Look and feel

| Example                                                                                    | The one idea                                                                                    |
| ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- |
| [`custom-fonts`](https://github.com/superwall/superwall/tree/main/examples/custom-fonts)   | A typeface from a file in your project — relative-path `@font-face`, subset to latin            |
| [`with-tailwind`](https://github.com/superwall/superwall/tree/main/examples/with-tailwind) | Tailwind v4 with zero framework config — and the `dark:` variant redefined onto the SDK's class |
| [`with-motion`](https://github.com/superwall/superwall/tree/main/examples/with-motion)     | In-page animation gated on presentation, plus a price count-up gated on the value existing      |
| [`with-rive`](https://github.com/superwall/superwall/tree/main/examples/with-rive)         | Interactive vector animation — `.riv` as a hosted asset, the WASM engine bundled                |
| [`orientation`](https://github.com/superwall/superwall/tree/main/examples/orientation)     | `useDevice().orientation` — landscape is a two-column reflow, not a shrunken portrait           |

## Localization

| Example                                                                                  | The one idea                                                                                                             |
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| [`localization`](https://github.com/superwall/superwall/tree/main/examples/localization) | Four locales by filename, shared + paywall-local catalogs, guarded `{price}` interpolation, no language picker on device |

## Habits every example carries

These are the "treat it like a real paywall" conventions — carry them into anything you build:

* **Haptics on every meaningful tap** — `light()` for navigation and CTAs, `selection()` for changing a choice, `success()` when a purchase lands ([Styling & mobile design](/docs/framework/styling)).
* **Never a loading state on the buy button** — the store sheet is the feedback, and the SDK owns it ([Purchases](/docs/framework/purchases)).
* **Prices from `useProducts()`**, never hardcoded; example product identifiers are placeholders to repoint at your own ([Products](/docs/framework/products)).
* **Every control reachable** — icon-only buttons carry `aria-label`, tap targets are at least 44px, primary actions sit full-width at the bottom.
* **Links through `openUrl`**, never an `<a href>` ([Actions](/docs/framework/actions)).
* **Light and dark via the `:root.dark` class**, both always checked; safe areas with sensible minimums; responsive from 320px to tablet.