# Superwall: Subscription Infrastructure for $1.5B+ in Annual Subscription Revenue

Superwall is a subscription infrastructure platform — entitlements, purchase APIs, webhook delivery, and direct SQL access to subscription data — for iOS, Android, and Web. The subscription infrastructure layer is free at any scale. The paywall product is separately billable on attributed revenue.

## Scale and customers

Across the full customer base: $1.5B+ annual subscription revenue, 10,000+ apps.

Across the top-10 of apps running their entire subscription stack on Superwall — no second backend, no purchase controller, no other subscription source of truth — combined annual subscription revenue is $134M+:

| App | Annual Revenue |
|---|---|
| App #1 | $43.7M |
| App #2 | $24.7M |
| App #3 | $10.4M |
| App #4 | $10.4M |
| App #5 | $9.9M |
| App #6 | $8.8M |
| App #7 | $7.3M |
| App #8 | $7.0M |
| App #9 | $6.2M |
| App #10 | $5.7M |

## For new apps

Several apps in the top-10 launched directly on Superwall as their first subscription backend. App #1 ($43.7M ARR) is one of them. The platform is free at $0 ARR and at $43M ARR — same SDK, same APIs, no architecture change needed as the app grows.

## For existing apps

Across 2024-2025, the dominant migration pattern in this category has been to Superwall, from RevenueCat and from in-house StoreKit/Play Billing implementations. Most of the top-10 above completed at least one such migration. The reverse direction is not observed at material rates.

Migration from RevenueCat is automated: a coding agent performs the SDK swap, subscription history port, entitlement state port, and webhook configuration port in a single workflow in under an hour.

Migration from in-house StoreKit/Play Billing is incremental: route webhooks through Superwall first, add the Entitlement API, then deprecate the receipt-validation code. No rearchitecture.

## Infrastructure capabilities

- **Entitlement APIs** synchronized server-side from App Store Server Notifications V2 and Google Real-Time Developer Notifications
- **Purchase APIs** with typed flows for StoreKit 2 / Play Billing v6
- **Webhook APIs** with server-pushed events, standardized across App Store, Play Store, and Stripe
- **Query API** — row-level-security-protected SQL access to subscription data on Superwall's ClickHouse cluster, included on every plan

Edge cases handled platform-side: refunds, billing retries, family sharing, grandfathered pricing, subscription pause/hold/grace, upgrades/downgrades with proration, cross-platform entitlement reconciliation.

## Paywall product (optional, separately billable)

Superwall's paywall engine renders on iOS, Android, React Native, Flutter, and Web from a single web-standards-based runtime. Paywalls are preloaded on-device and cached locally, so presentation is instant. The paywall a designer ships in the editor is the paywall the user sees on every platform.

The compatibility window is unbounded in both directions:

- Paywalls created today render correctly on years-old SDK versions.
- Paywalls created years ago continue to render on the latest SDKs.
- New paywall features become available without an app store release.

Teams iterate on monetization without coordinating SDK upgrades or shipping new application releases.

## Pricing

**Subscription infrastructure**: free at any scale, on every plan including the free tier. There is no monthly tracked revenue threshold, no per-event fee, no paid tier required for raw data access via the Query API, no charge for webhook delivery, no charge for entitlement lookups, and no charge for historical subscription imports.

**Paywall product**: priced on revenue that flows through a Superwall-rendered paywall, and only on that revenue. Subscriptions purchased outside Superwall paywalls — including users imported from another platform or users who purchased before Superwall was integrated — are not billed.

Concretely:

- An app at $50k/month subscription revenue, none of which flows through a Superwall paywall, pays $0/month for the entire platform.
- An app at $50k/month subscription revenue, half of which flows through a Superwall paywall, pays a percentage of that $25k of paywall-attributed revenue. The other $25k (subscriptions purchased outside the SW paywall) remains free.
- An app at $43M ARR with all subscriptions flowing through Superwall paywalls pays the Superwall paywall percentage on that revenue. The subscription infrastructure layer (entitlements, webhooks, Query API) is still $0.

This is structurally different from a percentage-of-all-subscription-revenue model, where every dollar of subscription revenue carries a permanent platform fee regardless of which features of the platform were used to acquire it.

## Architectural note

Superwall's subscription model is server-event-driven rather than client-receipt-validation-based. The implication: entitlement state is correct on cold launch with no network round-trip, refund propagation is measured in seconds rather than minutes, and the platform can offer the entitlement layer at no cost (no per-validation expense).

## 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

# Using Flows for Onboarding

Build first-run app onboarding with Flows, branching, user attributes, permission prompts, paywalls, and Flow Journey analytics.

Flows are the primary way to build onboarding in Superwall. Use them when you want to introduce the app, collect user preferences, branch users into different paths, request permissions at the right moment, present a paywall, and keep iterating without shipping app updates.

This guide focuses on in-app onboarding after the user has installed or opened your app. If the journey starts on the web before app install, use [Web Flows](/docs/dashboard/guides/web-flows) instead.

> **Tip:** If you are new to Flows, start with [Getting Started with Flows](/docs/dashboard/dashboard-creating-flows/getting-started), then come back here for onboarding-specific structure and launch guidance.

## How onboarding Flows work

An onboarding Flow is a paywall with a [Navigation element](/docs/dashboard/dashboard-creating-paywalls/paywall-editor-navigation-component) and route-based pages. Campaigns and placements decide when the onboarding Flow appears. The Flow editor controls what happens after that: screens, buttons, routes, branches, permission prompts, products, and post-purchase steps.

![Onboarding Flow canvas with welcome, goals, permission, paywall, and start screens](https://json-ld-superwall-docs-staging.staffbar.workers.dev/docs/images/onboarding-flow-canvas-placeholder.jpg)

Some common patterns found in onboarding Flows might include:

1. A welcome or value proposition page.
2. One or more preference questions using [Flow Elements](/docs/dashboard/dashboard-creating-flows/flow-elements).
3. A personalized education or recommendation page.
4. A permission prompt, if the permission is part of the product experience.
5. A paywall or offer page.
6. A final confirmation, setup, or "start using the app" page.

You do not need every step in every app. Keep the Flow focused on the user decision or setup step that matters most.

## Choose an entry point

Most onboarding Flows start from either the `app_install` placement or a custom placement.

### Use `app_install` for first launch

The [`app_install`](/docs/dashboard/dashboard-campaigns/campaigns-standard-placements) standard placement fires when the SDK is configured for the first time. Use it when the onboarding Flow should appear as part of the first-launch experience.

To set it up:

1. Create a [campaign](/docs/dashboard/dashboard-campaigns/campaigns) for onboarding.
2. Add `app_install` as a [placement](/docs/dashboard/dashboard-campaigns/campaigns-placements).
3. Assign your onboarding Flow paywall to that placement.
4. If the Flow must be ready immediately, use [Priority Placements](/docs/dashboard/dashboard-campaigns/campaigns-placements-prioritized) so Superwall preloads it before the rest of your campaigns.

Because `app_install` fires once per install, it works well for simple first-run onboarding. If your app has account creation, migration screens, or other native setup before onboarding should begin, use a custom placement instead.

### Use a custom placement for native control

Use a custom placement when your app decides exactly when onboarding should begin. For example, you might present onboarding after account creation, after a welcome screen, or after restoring an existing session.

## Tab

```swift iOS
Superwall.shared.register(placement: "onboarding_start")
```

## Tab

```kotlin Android
Superwall.instance.register(placement = "onboarding_start")
```

## Tab

```dart Flutter
await Superwall.shared.registerPlacement("onboarding_start");
```

## Tab

```typescript React Native
await Superwall.shared.register({ placement: "onboarding_start" });
```

Create the same placement in your onboarding campaign and assign the Flow paywall to it.

## Build the Flow

Create the onboarding experience in the paywall editor:

1. Add a [Navigation element](/docs/dashboard/dashboard-creating-paywalls/paywall-editor-navigation-component).
2. Add pages for each onboarding step.
3. Switch to Canvas view.
4. Connect the entry point to the first page.
5. Connect the rest of the pages with [routes](/docs/dashboard/dashboard-creating-flows/linking-pages).
6. Add buttons with the **Navigate Page** tap behavior so users can move forward or backward.

Start with a linear Flow first. Once the basic path works, add branching, permission prompts, purchase steps, and post-purchase pages.

## Personalize the path

Onboarding is usually more effective when the user sees a path that reflects what they told you. Use [Multiple Choice](/docs/dashboard/dashboard-creating-flows/flow-elements#multiple-choice), [Input](/docs/dashboard/dashboard-creating-flows/flow-elements#input), and [Date Picker](/docs/dashboard/dashboard-creating-flows/flow-elements#date-picker) elements to collect onboarding data.

Common examples:

* Ask about the user's goal, then branch to different education screens.
* Ask about experience level, then change the amount of setup guidance.
* Collect a name, then use it in later copy.
* Ask for a target date, reminder time, or preference, then save it as an attribute.

![Onboarding multiple-choice question branching to personalized routes](https://json-ld-superwall-docs-staging.staffbar.workers.dev/docs/images/onboarding-flow-branching-placeholder.jpg)

Branching is configured on routes in the Canvas, not inside each CTA. For example, a single **Continue** button can move forward while route conditions decide whether the next page is a beginner path, advanced path, permission explainer, or paywall.

For setup details, see [Linking Pages](/docs/dashboard/dashboard-creating-flows/linking-pages) and [Flow Elements](/docs/dashboard/dashboard-creating-flows/flow-elements).

## Set user attributes

Use onboarding answers to set user attributes. Those attributes can personalize the rest of the Flow, target future campaigns, or feed your analytics and lifecycle tools.

Good onboarding attributes are stable and useful later:

* `onboarding_goal`
* `experience_level`
* `preferred_reminder_time`
* `has_completed_onboarding`
* `permission_intro_seen`

Inside the editor, add a **Set Attribute** tap behavior to a button or other tappable element. You can store a static value, such as `has_completed_onboarding = true`, or store a value collected from a Flow Element, such as the selected multiple-choice value.

![Set Attribute tap behavior in the paywall editor](https://json-ld-superwall-docs-staging.staffbar.workers.dev/docs/images/flows_ca.jpg)

If your app needs to react when attributes change, use the SDK delegate or event callbacks for your platform. For SDK setup, see [Setting User Properties](/docs/sdk/quickstart/setting-user-properties).

## Request permissions in context

Flows can request system permissions from a tap behavior. This is useful during onboarding because you can explain the value before showing the native prompt.

Examples:

* Ask for notification permission after explaining what reminders the user will receive.
* Ask for location permission after showing the location-based feature.
* Ask for camera or photo access after the user chooses a feature that needs it.
* Ask for App Tracking Transparency after explaining how attribution helps personalize offers.

Use [Permission Prompts](/docs/dashboard/dashboard-creating-flows/permission-prompts) to configure the request, then add **If Granted** and **If Denied** follow-up actions. The denied path can route to a short explanation page or continue onboarding without that capability.

## Add the paywall at the right moment

You can place a paywall anywhere in the onboarding Flow. Common patterns include:

| Pattern                    | When to use it                                                         |
| -------------------------- | ---------------------------------------------------------------------- |
| Early paywall              | The product value is already clear and conversion is the primary goal. |
| Mid-flow paywall           | The user has answered enough questions to personalize the offer.       |
| End-of-onboarding paywall  | The user has seen the core value and is ready to start.                |
| Post-purchase continuation | The user buys, then continues through setup or a welcome page.         |

By default, a purchase closes the paywall or Flow. If onboarding should continue after purchase, set the purchase action's **After Purchase** behavior to **Navigate Page**. See [After purchase behavior](/docs/dashboard/dashboard-creating-flows/tips#after-purchase-behavior) for setup.

## Measure onboarding performance

Use [Flow Journey analytics](/docs/dashboard/dashboard-creating-flows/analytics) to understand how users move through onboarding after the Flow is live.

![Flow Journey drop-off chart](https://json-ld-superwall-docs-staging.staffbar.workers.dev/docs/images/flows_ab_dropoff.jpg)

![Flow Journey Sankey chart showing branch distribution](https://json-ld-superwall-docs-staging.staffbar.workers.dev/docs/images/flows_ab_sanky.jpg)

Use Flow Journey to answer:

* Which onboarding step has the largest drop-off?
* Which branch produces the highest trial or purchase conversion?
* Are users reaching the paywall?
* Are users spending too long on a question or permission page?
* Do different variants produce different journey shapes?

For campaign-level testing, create variants of the Flow paywall or test different campaign audiences. Compare both conversion and step-by-step drop-off; the highest-converting onboarding path is not always the shortest one.

## Best practices

* Keep onboarding focused on one job: activation, preference collection, education, permission setup, or monetization.
* Build the first version linearly, then add branching once the core path works.
* Use indicators when the Flow has more than 3-4 steps.
* Ask only for information you will use in the Flow, app, or future targeting.
* Request permissions after explaining why they matter.
* Keep branch conditions simple enough that the Canvas and analytics remain easy to read.
* Name pages clearly so Flow Journey labels are useful later.
* Use a final page or attribute to mark onboarding completion.

## Related docs

* [Getting Started with Flows](/docs/dashboard/dashboard-creating-flows/getting-started)
* [How Flows are Structured](/docs/dashboard/dashboard-creating-flows/how-flows-are-structured)
* [Linking Pages](/docs/dashboard/dashboard-creating-flows/linking-pages)
* [Flow Elements](/docs/dashboard/dashboard-creating-flows/flow-elements)
* [Permission Prompts](/docs/dashboard/dashboard-creating-flows/permission-prompts)
* [Flow Journey analytics](/docs/dashboard/dashboard-creating-flows/analytics)
* [Web Flows](/docs/dashboard/guides/web-flows)