# 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

# Migrating from the editor

Rebuild a paywall made in Superwall's visual editor as a framework paywall: what the CLI scaffolds, what an agent rebuilds, how you review it against the original, and how the switch happens.

A paywall built in the visual editor becomes a framework paywall by being rebuilt as code: the same design, products, pages and actions, written as routes, hooks and your own CSS. The CLI does the part that is deterministic, a coding agent rebuilds the pages, you review the result next to the original in the studio, and the original keeps serving until a campaign points at the new one.

## Start from the dashboard paywall

In your app's root (or an empty directory), with the paywall's id from the dashboard URL:

```bash
superwall create --from 65920
```

This reads the paywall and its served document, then scaffolds a project with:

* `paywalls/<slug>/config.ts` carrying the name, platform, product slots, presentation style and geometry, feature gating, scroll, game controller and cache settings, and the background color, all as the paywall has them today. Nothing under `app/` is migrated; it is the starter, to be replaced.
* `paywalls/<slug>/MIGRATION.md`, the brief: the source URL, the dashboard screenshot, a product table, and an inventory of the pages, drawers, elements, actions, product variables and locales the source uses.
* An `origins` entry in `superwall.lock`, which is what puts **Original** in the studio's Compare menu.
* The project connected to the same app, so the new paywall lands beside the old one.

`--from` needs a login and cannot be combined with `--example` or `--no-connect`. A paywall that is already built with the framework is refused; pull its source from the dashboard instead.

> **Note:** Template paywalls have no real products: their slots show `"missing"` in `config.ts`, and a push refuses them. Point each slot at a real product (or create one with `superwall products create`) before pushing.

## Rebuild the pages

The rebuild is agent work with you in the loop, and the CLI offers it as soon as the scaffold is done:

```
◇ Rebuild the pages now?
  › With Claude Code        runs here, headless; you review in the studio after
    Copy the prompt         paste it into Claude Code, Codex, Cursor, or another agent
    Not now                 superwall migrate 65920 picks this up later
```

The same choice is one command away at any time, and it scaffolds first if the paywall isn't in the project yet:

```bash
superwall migrate 65920            # in the app root, or inside superwall/
superwall migrate 65920 --skill    # print the prompt instead, once it is scaffolded
```

Running it with your agent hands it the brief and the rebuild playbook from the `superwall-framework` skill (`references/migrate-from-editor.md`), headless, in the `superwall/` directory, with a fixed order of work: confirm the inventory against the editor's document store embedded in the served page, lift the design tokens, one route per page with shared chrome in `layout.tsx`, every action as a hook call, every state and locale rebuilt, `typecheck` green. It cannot push, promote or touch campaigns. The mapping it follows (a navigation element's children become routes, a drawer becomes a sheet, a tap action becomes a hook call, Liquid product templates become `useProducts()` reads) is the `superwall-framework` skill's `references/migrate-from-editor.md`, which the agent reads as well.

Copying the prompt gives you the same instructions without the headless protocol, for an agent you drive yourself, which is the way to keep the inventory step conversational: ask for the inventory first and approve it before any code is written.

## Review against the original

When the agent finishes, the CLI offers to open the studio, and opens it straight onto the rebuilt paywall with **Original** in the second pane: the dashboard paywall served exactly as it is today, beside your local build. The same view is in the toolbar's Compare menu at any time, and a link with `?compare=origin` lands on it. Walk every page on a phone with a Dynamic Island, an iPhone SE, a Pixel and an iPad, in both color schemes, and compare.

It is your code now. Anything that doesn't match is a tweak to ask your agent for, or to make yourself, under `paywalls/<slug>/`; the studio reloads as you save.

The Original pane is view-only. It does not receive the studio's theme, locale, device or product variables, so it renders in light mode with the editor's example prices. Your side does receive them, which is how you check the dark scheme and the real prices the original never showed.

## Switch when you are ready

`superwall push` creates a **new** dashboard paywall and binds it in `superwall.lock`; the editor paywall is untouched and keeps serving. To go live, point the campaign's variant at the new paywall in the dashboard. Rolling back is pointing it at the old one again. Nothing about a migration promotes on its own, and an agent following the playbook pushes only when asked and never touches campaigns.

Delete `MIGRATION.md` once you are satisfied. The `origins` entry in the lock stays, so Compare › Original keeps working for later edits.

## What does not carry over

* The original cannot be converted in place; a framework paywall is always a new dashboard paywall.
* Editor-only behavior with no framework equivalent, such as surveys attached to the paywall, is not carried over. The playbook names each such item in its hand-off rather than approximating it.
* The editor's example prices. The framework never invents a price; every product variable is guarded and the unpriced state is designed, as everywhere else in the framework.