# 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

# Previewing

To preview a paywall on device, click **Preview** in the top-right side of the editor:

![](https://2a2314a4-superwall-docs.staffbar.workers.dev/docs/images/pe-editor-preview.png)

To enable this functionality, you'll need to use deep links.

#### Adding a Custom URL Scheme (iOS)

To handle deep links on iOS, you'll need to add a custom URL scheme for your app.

Open **Xcode**. In your **info.plist**, add a row called **URL Types**. Expand the automatically created **Item 0**, and inside the **URL identifier** value field, type your **Bundle ID**, e.g., **com.superwall.Superwall-SwiftUI**. Add another row to **Item 0** called **URL Schemes** and set its **Item 0** to a URL scheme you'd like to use for your app, e.g., **exampleapp**. Your structure should look like this:

![](https://2a2314a4-superwall-docs.staffbar.workers.dev/docs/images/1.png)

With this example, the app will open in response to a deep link with the format &#x2A;*exampleapp\://**. You can [view Apple's documentation](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) to learn more about custom URL schemes.

#### Adding a Custom Intent Filter (Android)

For Android, add the following to your `AndroidManifest.xml` file:

```xml
<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="exampleapp" />
    </intent-filter>
</activity>
```

This configuration allows your app to open in response to a deep link with the format `exampleapp://` from your `MainActivity` class.

#### Handling Deep Links (iOS)

Depending on whether your app uses a SceneDelegate, AppDelegate, or is written in SwiftUI, there are different ways to tell Superwall that a deep link has been opened.

Be sure to click the tab that corresponds to your architecture:

## Tab

```swift AppDelegate.swift
import SuperwallKit

class AppDelegate: UIResponder, UIApplicationDelegate {
// NOTE: if your app uses a SceneDelegate, this will NOT work!
func application(\_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return Superwall.shared.handleDeepLink(url)
}
}

```

## Tab

```swift SceneDelegate.swift
import SuperwallKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  // for cold launches
  func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    if let url = connectionOptions.urlContexts.first?.url {
      Superwall.shared.handleDeepLink(url)
    }
  }

  // for when your app is already running
  func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    if let url = URLContexts.first?.url {
      Superwall.shared.handleDeepLink(url)
    }
  }
}
```

## Tab

```swift SwiftUI
import SuperwallKit

@main
struct MyApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
        .onOpenURL { url in
          Superwall.shared.handleDeepLink(url) // handle your deep link
        }
    }
  }
}
```

## Tab

```swift Objective-C
// In your SceneDelegate.m

#import "SceneDelegate.h"
@import SuperwallKit;

@interface SceneDelegate ()

@end

@implementation SceneDelegate

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    [self handleURLContexts:connectionOptions.URLContexts];
}

- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
    [self handleURLContexts:URLContexts];
}

#pragma mark - Deep linking

- (void)handleURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
    [URLContexts enumerateObjectsUsingBlock:^(UIOpenURLContext * _Nonnull context, BOOL * _Nonnull stop) {
        [[Superwall sharedInstance] handleDeepLink:context.URL];
    }];
}

@end
```

#### Handling Deep Links (Android)

In your `MainActivity` (or the activity specified in your intent-filter), add the following Kotlin code to handle deep links:

## Tab

```kotlin Kotlin
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Respond to deep links
        respondToDeepLinks()
    }

    private fun respondToDeepLinks() {
        intent?.data?.let { uri ->
            Superwall.instance.handleDeepLink(uri)
        }
    }

}

```

### Previewing Paywalls

Next, build and run your app on your phone.

Then, head to the Superwall Dashboard. Click on **Settings** from the Dashboard panel on the left, then select **General**:

![](https://2a2314a4-superwall-docs.staffbar.workers.dev/docs/images/c252198-image.png)

With the **General** tab selected, type your custom URL scheme, without slashes, into the **Apple Custom URL Scheme** field:

![](https://2a2314a4-superwall-docs.staffbar.workers.dev/docs/images/6b3f37e-image.png)

Next, open your paywall from the dashboard and click **Preview**. You'll see a QR code appear in a pop-up:

![](https://2a2314a4-superwall-docs.staffbar.workers.dev/docs/images/pe-editor-preview-qr.png)

On your device, scan this QR code. You can do this via Apple's Camera app. This will take you to a paywall viewer within your app, where you can preview all your paywalls in different configurations.

```
```