# 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

# Meta Ads

Run Meta ads with Superwall as your mobile measurement partner. Superwall attributes installs to your campaigns and sends conversion events back to Meta.

The Meta Ads integration makes Superwall your mobile measurement partner (MMP) for Meta campaigns. Superwall generates the links you put in your ads, attributes installs to the campaign, ad set, and ad that drove them, and sends conversion events back to Meta so it can optimize delivery. Spend and results show up in [charts](/docs/dashboard/charts) as ROAS, cost per trial, and cost per paid user.

This integration is separate from [Meta Conversion API](/docs/integrations/meta-conversion-api), which forwards subscription webhook events to a Meta Pixel.

> **Note:** We are gradually rolling out performance marketing. If you don't see
> **Performance Marketing** under **Integrations**, reach out to us at
> [support@superwall.com](mailto\:support@superwall.com) and we'll enable it for
> your app.

## Requirements

* An iOS app using [SuperwallKit](/docs/ios) 4.16.0 or later. Meta Ads attribution is iOS only for now.
* [Revenue tracking](/docs/dashboard/dashboard-settings/overview-settings-revenue-tracking) configured for your app.
* A Meta ad account you have admin access to, and access to [Meta Events Manager](https://business.facebook.com/events_manager2).
* If you sell outside of Superwall paywalls, enable [observer mode](/docs/ios/guides/advanced/observer-mode) so transactions are tracked.

> **Warning:** Attribution only applies to new installs. The SDK matches an install once,
> shortly after first launch, and only within 7 days of install. Users who
> installed your app before it shipped with SDK 4.16.0 are never attributed, so
> test with a fresh install.

## Step 1: Set up your Meta dataset

Superwall sends conversion events to a Meta dataset. Set it up before connecting Superwall:

1. Go to [Meta Events Manager](https://business.facebook.com/events_manager2). If you don't have a dataset, click **Connect data** and follow the prompts to create one.
2. Link the dataset to the ad account you'll run campaigns from.
3. Generate an access token: open your dataset, go to **Settings** > **Conversions API**, and find **Set up direct integration**. Leave **Set up with Dataset Quality API** selected, then click **Generate access token**. Copy it for the next step.

## Step 2: Connect Meta in Superwall

## Open the integration

In your app's dashboard, go to **Integrations**, find **Performance Marketing**, and click the **Meta** card.
![The Integrations page showing the Performance Marketing section with the Meta card](https://jordan-sw-5719-mmp-docs-superwall-docs.staffbar.workers.dev/docs/images/mmp_performance_marketing_section.jpg)

## Connect your Meta account

Click **Connect account** and sign in with a Facebook account that has admin access to your business portfolio.

## Choose your dataset and paste the access token

Pick your dataset from the **Dataset** dropdown. If it isn't listed, click **Refresh datasets** or paste the dataset ID manually. Paste the access token from step 1 into **Conversion API Access Token** and click **Save**. The button reads **Update** when you're editing an existing configuration. Superwall validates both against Meta before saving.
![The Meta setup page with the Dataset dropdown and Conversion API Access Token field](https://jordan-sw-5719-mmp-docs-superwall-docs.staffbar.workers.dev/docs/images/mmp_meta_dataset_token.jpg)

## Step 3: Choose events to send

Superwall sends these events to your dataset. All six are on by default; leave them on unless you have a reason not to.

| Dashboard label     | Superwall event                | Sent to Meta as                   |
| ------------------- | ------------------------------ | --------------------------------- |
| Paywall Open        | `paywall_open`                 | `sw_paywall_open`                 |
| Transaction Start   | `transaction_start`            | `sw_transaction_start`            |
| Transaction Abandon | `transaction_abandon`          | `sw_transaction_abandon`          |
| Free Trial Start    | `freeTrial_start`              | `sw_freeTrial_start`              |
| Subscription Start  | `subscription_start`           | `sw_subscription_start`           |
| One-Time Purchase   | `nonRecurringProduct_purchase` | `sw_nonRecurringProduct_purchase` |

![The Events to send card with all six events checked](https://jordan-sw-5719-mmp-docs-superwall-docs.staffbar.workers.dev/docs/images/mmp_meta_events_to_send.jpg)

Events are sent for every user, not just users attributed to your ads. Meta uses them for delivery optimization and its own attribution.

Meta requires you to acknowledge new custom events and allow the domain they come from:

## Send test events

Click **Save changes**, then **Send test events to Meta**. The button stays disabled until your event selection is saved. The events appear in your dataset's **Test events** tab within a few minutes.

## Confirm the custom events

Once the test events arrive, open your dataset's **Overview** tab in Events Manager. A warning appears: **Confirm custom event(s) that belong to you**. Click **Review events**, click **I acknowledge**, select all events starting with `sw_`, click **Next**, then choose **Confirm custom event** and click **Confirm**. Events can take up to 30 minutes to reach the **Overview** tab, and if no warning appears, the events were already confirmed.Once confirmed, the warning goes away and the `sw_` events stay listed in the **Overview** events table under the **Conversions API** integration:
![A confirmed sw_subscription_start event listed in the dataset](https://jordan-sw-5719-mmp-docs-superwall-docs.staffbar.workers.dev/docs/images/mmp_meta_events_confirmed.jpg)

## Allow the superwall.com domain

In your dataset's **Settings**, under **Traffic permissions - websites**, click **Create allow list** and add `superwall.com`.

## Step 4: Create your ad links

Under **Ads links**, Superwall generates the URL you'll use in your Meta ads.

## Add a link

Click **+ Add ad link** and pick an App Store language. Create one link per storefront language you advertise in. The link automatically sends people to your app's default App Store product page, so there's nothing else to fill in. Only add a URL under &#x2A;*Custom product page (optional)** if you want the ad to open a custom product page instead.

## Save to activate

Click **Save changes**. A link only starts working after it's saved.

## Copy the link

Click the URL in the **Website URL** column to copy it. It already includes the parameters Meta fills in with your campaign, ad set, and ad details, so don't edit them.
![The Ads links table with a saved English link showing the copyable Website URL](https://jordan-sw-5719-mmp-docs-superwall-docs.staffbar.workers.dev/docs/images/mmp_meta_ad_links.jpg)

> **Warning:** Deleting or disabling a link immediately breaks any live ads pointing at it.
> Keep links in place while campaigns are running.

## Step 5: Create your Meta campaign

Superwall ad links are website links. That means you'll run a **Sales** campaign with a website conversion location, not an App Promotion campaign, even though the goal is installs. When someone taps your ad, the link records the click and sends them straight to the App Store.

## Create a manual Sales campaign

In Ads Manager, click **Create** and choose the **Sales** objective. Set the campaign up manually; don't use Meta's AI-assisted setup.
![Meta Ads Manager campaign creation with Manual campaign setup and the Sales objective selected](https://jordan-sw-5719-mmp-docs-superwall-docs.staffbar.workers.dev/docs/images/mmp_meta_campaign_objective.jpg)

## Point the ad set at your dataset

Set **Conversion location** to **Website**. Choose your dataset and the conversion event to optimize for. We recommend `sw_transaction_start`, since starting a transaction signals purchase intent.
![The ad set level showing Website conversion location, the dataset, and the conversion event](https://jordan-sw-5719-mmp-docs-superwall-docs.staffbar.workers.dev/docs/images/mmp_meta_adset_conversion.jpg)

## Restrict placements to iOS

Under **Placements**, click **Show more settings**, then limit devices to **Mobile** and operating systems to **iOS**, and turn off **Audience Network**.

## Add the link to your ad

Paste the Superwall link into the ad's **Website URL** field. Leave **URL parameters** under the ad's **Tracking** section empty; the link already carries them.
![The ad level with the Superwall link pasted into the Website URL field](https://jordan-sw-5719-mmp-docs-superwall-docs.staffbar.workers.dev/docs/images/mmp_meta_ad_website_url.jpg)

## Publish the campaign

Click **Publish** to put your campaign and ads live.

## Verify it's working

* Test events appear in the **Test events** tab of your dataset in Events Manager.
* Once ads run, attributed users appear in Superwall with `acquisition_` user attributes set and an `attribution_match` event in their event stream.
* The **Advertising** charts populate after spend syncs from Meta, which happens daily.

## How attribution works

When someone taps your ad, Superwall records the click along with its IP address, device signals, and the campaign parameters Meta filled into the link, then sends them on to the App Store. When the app launches for the first time, the SDK asks Superwall to match the install against recent clicks. Matching is probabilistic: IP address, how recently the click happened, platform, language, timezone, and screen size all contribute to a score, and the install is attributed only when the score clears a threshold.

* Matching runs once per install, within 7 days of install.
* No ATT prompt or IDFA is required; matching never uses them.
* Unmatched installs stay unattributed and show as `Organic` in charts.

### User attributes

A matched install sets these user attributes. Attributes without a value are omitted.

| Attribute                        | Value                                              |
| -------------------------------- | -------------------------------------------------- |
| `acquisition_source`             | The network that drove the install, like `meta`    |
| `acquisition_network`            | Same as `acquisition_source`                       |
| `acquisition_channel`            | Always `paid`                                      |
| `acquisition_campaign_name`      | The Meta campaign name                             |
| `acquisition_campaign_id`        | The Meta campaign ID                               |
| `acquisition_ad_set_name`        | The ad set name                                    |
| `acquisition_ad_set_id`          | The ad set ID                                      |
| `acquisition_ad_name`            | The ad name                                        |
| `acquisition_ad_id`              | The ad ID                                          |
| `acquisition_placement`          | The Meta placement that showed the ad              |
| `acquisition_site_source_name`   | Where the ad ran, like `ig` or `fb`                |
| `acquisition_link_id`            | The Superwall ad link ID                           |
| `acquisition_click_id`           | The matched click ID                               |
| `acquisition_matched_at`         | When the match happened                            |
| `acquisition_app_store_language` | The link's App Store language                      |
| `acquisition_product_page_id`    | The Custom Product Page ID, when the link uses one |
| `acquisition_deeplink_id`        | The link's deep link ID, when set                  |

Use them as breakdowns and filters in [charts](/docs/dashboard/charts), or in [audience filters](/docs/dashboard/dashboard-campaigns/campaigns-audience) to show different paywalls to users acquired from ads.

### The attribution_match event

The SDK tracks `attribution_match` when the match request completes, matched or not.

| Parameter     | Value                                                                   |
| ------------- | ----------------------------------------------------------------------- |
| `provider`    | `mmp`, or `apple_search_ads` for Apple Search Ads attribution           |
| `matched`     | Whether the install was attributed                                      |
| `source`      | The network, like `meta`                                                |
| `confidence`  | `high`, `medium`, or `low`                                              |
| `match_score` | The match score                                                         |
| `reason`      | Why a match failed: `below_threshold`, `ambiguous`, or `request_failed` |

The event and its parameters are available in charts and audience filters. It can't be used to trigger a paywall directly.

## Charts

With the integration enabled, Superwall pulls campaign spend from Meta daily and adds an **Advertising** chart group:

![The Advertising chart group in the Charts sidebar, listing Ad Spend, ROAS, CPM, CPT, CPP, and Blended CPT](https://jordan-sw-5719-mmp-docs-superwall-docs.staffbar.workers.dev/docs/images/mmp_advertising_chart_section.jpg)

* **[Ad Spend](/docs/dashboard/charts/ad-spend)**
* **[ROAS](/docs/dashboard/charts/roas)**: proceeds divided by spend
* **[CPM](/docs/dashboard/charts/cpm)**: cost per thousand impressions
* **[CPT](/docs/dashboard/charts/cpt)**: cost per trial
* **[CPP](/docs/dashboard/charts/cpp)**: cost per paid user
* **[Blended CPT](/docs/dashboard/charts/blended-cpt)**: total spend divided by all trials, including organic

Revenue charts can also be broken down by **Acquisition network** and **Acquisition campaign** to split any metric by the campaign that acquired the user. Those breakdowns fill in as installs match; unmatched installs group under `Organic`.

## Troubleshooting

### Installs aren't being attributed

* The app must ship SuperwallKit 4.16.0 or later, and the install must be new. Delete and reinstall the app to test; updating an existing install never attributes.
* Matching only runs within 7 days of install.
* `SuperwallOptions.eventTrackingBehavior` must not be set to `.none`. That setting disables install matching entirely.
* The ad link must be saved and enabled. A deleted or disabled link returns a 404 and records no clicks.

### Events aren't showing in Meta

* Sandbox purchases are never forwarded. Only production events are sent to Meta; use **Send test events to Meta** to validate before going live.
* Confirm the dataset ID and access token still validate by editing and re-saving the configuration.
* Confirm the `sw_` custom events in **Review events** in Events Manager.
* Add `superwall.com` to the dataset's website traffic allow list.

### No transaction or purchase events

* If you sell outside of Superwall paywalls, enable [observer mode](/docs/ios/guides/advanced/observer-mode).
* Check that [revenue tracking](/docs/dashboard/dashboard-settings/overview-settings-revenue-tracking) is configured. Subscription events come from App Store server notifications.