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 as ROAS, cost per trial, and cost per paid user.
This integration is separate from Meta Conversion API, which forwards subscription webhook events to a Meta Pixel.
We are gradually rolling out performance marketing. If you don't see Performance Marketing under Integrations, reach out to us at support@superwall.com and we'll enable it for your app.
This page describes the new dashboard at app.superwall.com. The Meta page in the legacy dashboard uses different labels and lacks some of the controls described here.
Requirements
- An iOS app using SuperwallKit 4.16.0 or later. Meta Ads attribution is iOS only for now. On Expo, use expo-superwall 1.2.0 or later and ship a new app build (an EAS Update can't change the native SDK). On Flutter, use superwallkit_flutter 2.5.0 or later.
- Revenue tracking configured for your app.
- A Meta ad account you have admin access to, and access to Meta Events Manager. Confirming custom events in Step 3 requires full control of the dataset in your business portfolio.
- If you sell outside of Superwall paywalls, enable observer mode so transactions are tracked.
Attribution only applies to new installs. The SDK matches an install once, shortly after first launch, and only when that first launch happens within 7 days of the ad click. 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.
Use a web dataset, the kind backed by a Meta Pixel. In Meta, your app is itself a dataset, and you can't use it here: Superwall sends its events as website events, and app datasets don't accept them. The dataset picker in Superwall only lists web datasets, so if yours is missing, this is usually why.
- 1
Create a web dataset
Go to Meta Events Manager and click Datasets in the left menu. If you already have a web dataset backed by a Meta Pixel, select it and skip to the next step.
Otherwise, click Connect data, choose Web in the Connect a new data source dialog (not App, even though its description mentions installs and purchases), then follow the prompts to name and create the dataset.

- 2
Link the dataset to your ad account
Link the dataset to the ad account you'll run campaigns from.
- 3
Generate a Conversions API access token
Open the dataset in Events Manager: click Datasets in the left menu, select your dataset, and click the Settings tab. Scroll to the Conversions API section and find Set up direct integration. Leave Set up with Dataset Quality API selected and click Generate access token. Copy the token; you'll paste it into Superwall in the next step.
Events Manager lists other ways to set up the Conversions API, like partner integrations. Skip them. Superwall is the direct integration, and the access token is all it needs.

Step 2: Connect Meta in Superwall
- 1
Open the integration
In your app's dashboard, go to Integrations, find Performance Marketing, and click the Meta card.

- 2
Connect your Meta account
Click Connect Meta account and sign in with a Facebook account that has admin access to your business portfolio. Meta's consent dialog is where you choose which ad accounts Superwall may read. There is no separate account picker afterwards.
- 3
Choose your dataset and paste the access token
Pick your dataset from the Dataset dropdown. Options are labelled by the business portfolio or ad account that owns them, so several datasets with similar names are still easy to tell apart. If Superwall can't read the list from the Meta account you connected, a text field takes its place and accepts a dataset ID typed in directly.
Paste the access token from step 1 into Conversions API Access Token and click Save. Superwall checks the pair with Meta first and won't store a dataset and token Meta rejects, showing you what Meta said instead.

Once saved, the page shows your configuration as a summary and the token as its last four characters. Superwall never sends the token back to your browser, so it can't be displayed or copied. To change it, click Edit configuration and then Replace token; leaving the token alone keeps the stored one. The Events to send and Ad links cards only appear once a dataset and token are saved.
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 |
Events are sent for every user, not just users attributed to your ads. Meta uses them for delivery optimization and its own attribution.
Because organic users are included, the dataset's Event Match Quality score in Events Manager reads lower than it would for a pixel on a website. Organic users have no ad click for Meta to match against, so their events carry fewer matching signals. This is expected and doesn't affect attribution in Superwall. To raise the score, set user attributes as described in Improving Event Match Quality below.
When Subscription Start is enabled, a free trial converting to paid also sends sw_subscription_start, carrying the purchase's value and currency plus is_trial_conversion: true in custom_data, so Meta sees revenue at the moment a trial starts paying, not just the trial start. Direct paid signups and trial conversions share one event on purpose: Meta's delivery optimizes per event, and pooling both keeps its volume high. Ordinary renewals (rebills) are never sent.
If you connected Meta before trial-conversion forwarding shipped, it activates the next time you click Save changes on this page.
Meta requires you to acknowledge new custom events and allow the domain they come from:
- 1
Send test events
Click Save changes, then Send test events. Test events are sent from your saved selection, so save first if you've just changed which events are ticked. They appear in your dataset's Test events tab within a few minutes.
- 2
Confirm the custom events
Meta flags new custom events for review. Confirm they belong to you so they can be used in ad campaigns. In Events Manager, open your dataset, click the Settings tab, and scroll to Data controls. Under Manage event blocking, click Review to open the Event statuses dialog. In its Action required tab, select every event that starts with
sw_, click Next, choose Confirm the custom event, click Review, then click Done. The events usually show up here within a few minutes of sending test events.After you confirm them, all six move to the Confirmed tab with the status Confirmed by you:

The Overview tab can also show a Confirm custom event(s) that belong to you warning with a Review events button that leads to the same review. That warning can take up to 30 minutes to appear and sometimes never does, so don't wait for it.
If the
sw_events are already under Confirmed, there's nothing to do. If Meta blocked an event, it appears under Blocked. Select it and click View details to request a review.Confirmed events also stay listed in the Overview events table under the Conversions API integration:

- 3
Allow the install.link domain
In your dataset's Settings, under Traffic permissions - websites, click Create allow list, enter
install.link, click Next, then click Confirm.The domain is
install.link, notsuperwall.com. Superwall sends every event with aninstall.linkURL as its source, so that is the domain Meta checks the allow list against. Previously, setup usedsuperwall.com. If that is the domain you allowed, addinstall.linkas well, or Meta will not accept your events.
Improving Event Match Quality
Meta scores every event on how many signals it can match to a person. Superwall always sends a hashed external_id. Everything else comes from user attributes you set, so setting them as early as you know them is the highest-leverage change you can make:
Superwall.shared.setUserAttributes([
"email": "someone@example.com",
"phoneNumber": "+1 555-123-4567",
"firstName": "Ada",
"lastName": "Lovelace",
"city": "London",
"state": "England",
"postalCode": "SW1A 1AA",
"birthday": "1992-05-14"
])Superwall normalizes each value and hashes it with SHA-256 before it leaves Superwall, the way Meta's Advanced Matching expects. Raw email addresses, phone numbers and names are never sent. An attribute you haven't set is omitted rather than sent empty.
| Attribute | Meta field | Notes |
|---|---|---|
email | em | Lowercased before hashing |
phoneNumber | ph | Must include the country code. Plus signs, spaces and punctuation are stripped, so +1 555-123-4567 hashes as 15551234567 |
firstName / lastName | fn / ln | If you store one whole name under name instead, Superwall splits it on the last space, so Mary Anne Evans becomes Mary Anne and Evans. A single word is sent as the first name only |
city | ct | Accents are folded and everything except letters is stripped, so St. Louis hashes as stlouis |
state | st | Use the two-letter code for the US and Canada and the region name elsewhere, as Meta expects. Superwall lowercases and strips spaces but doesn't convert names to codes |
postalCode | zp | Spaces stripped, so SW1A 1AA hashes as sw1a1aa |
birthday | db | Year, month, day. Separators are stripped, so 1992-05-14 works. Anything that isn't eight digits afterwards is dropped rather than sent |
country | country | Two-letter code. Read for paywall and transaction events only. Purchase events always use the store transaction's country |
Superwall also accepts spellings you may already use: phone_number / phone, first_name, last_name, name / fullName / full_name, region for state, postal_code / zip / zipCode, and dateOfBirth. Paywall and transaction events also read date_of_birth, countryCode and country_code.
Purchase events pick up new attributes immediately. Paywall and transaction events pick them up within about five minutes.
Country is sent whenever Superwall has one. Free Trial Start, Subscription Start and One-Time Purchase use the store transaction's country. Paywall and transaction events use the country attribute when set, otherwise the region of the user's matched install or the device's locale.
If the score stays low, the usual causes are attributes stored under names Superwall doesn't read, a phone number without its country code, or a birthday that isn't in year-month-day order. The last two hash to a value that matches nobody.
Step 4: Create your ad links
Under Ad links, Superwall generates the URL you'll use in your Meta ads.
- 1
Add a link
Click Add ad link. The first row is set to English; later rows ask you to pick an App Store language. The Product page column reads Default, meaning the ad opens your app's default App Store listing, so there's nothing else to fill in.
To send the ad to a Custom Product Page instead, click that cell. It opens prefilled with the row's current URL, the default one to begin with, which is the right starting point: a Custom Product Page URL is the default one plus
?ppid=<id>. The cell then reads Custom (<id>). Clearing it returns the link to the default.You can pick the same language more than once. Add an English link for each Custom Product Page you want to test, and each row gets its own Website URL to use in a different ad. The App Store language is fixed once a row is saved.
Links that share a language are told apart by their Custom Product Page, so the confirmation shown before a save deletes a live link names the row as
English (winter-sale)rather than just its language. When neither row uses a Custom Product Page, rows are named by position instead, asEnglish (#1)andEnglish (#2). - 2
Save to activate
Click Save changes. It saves the whole page, so a change to your event selection and a change to your ad links are picked up together. (The Save/Update button in the configuration card saves the page too, after checking your dataset and token with Meta.)
A link only starts working once it's saved, and stays locked until then: the Website URL shows a padlock rather than a copy button while a row is unsaved, because the URL wouldn't resolve yet.
- 3
Copy the link
Click the copy button beside the URL in the Website URL column. It already includes the parameters Meta fills in with your campaign, ad set, and ad details. For Meta ads, don't edit them.

Deleting or disabling a link immediately breaks any live ads pointing at it. Keep links in place while campaigns are running.
Influencer and affiliate links
You can give a creator a link on your own domain, like yourapp.com/creator, that redirects to an ad link. Create an ad link for each creator. The copied link contains placeholders that only Meta fills in, URL-encoded, so {{campaign.name}} appears as %7B%7Bcampaign.name%7D%7D:
https://install.link/pk_abc123/meta-mfk3x9q2?app_store_language=english&placement=%7B%7Bplacement%7D%7D&campaign_name=%7B%7Bcampaign.name%7D%7D&site_source_name=%7B%7Bsite_source_name%7D%7D&campaignid=%7B%7Bcampaign.id%7D%7D&...Replace them with your own values and remove the ones you don't use:
https://install.link/pk_abc123/meta-mfk3x9q2?app_store_language=english&campaign_name=creator&campaignid=creatorSet campaignid as well as campaign_name. The Acquisition Campaign chart breakdown groups by campaign ID and shows installs without one as Organic. These installs are recorded with meta as the network, so they count toward Meta in charts, including its ROAS.
Reconnecting and disconnecting
The Meta page header shows whether your account is connected, with two controls beside it.
Reconnect runs the sign-in again against the same app. Use it if Meta's access expires or you granted the wrong ad accounts the first time. Your dataset, token and event selection are left alone.
Disconnect clears the Meta account, the dataset, the Conversions API token and your event selection, and stops sending events. It asks for confirmation first, because none of it can be recovered from Superwall: the token isn't readable once stored, so reconnecting means generating a new one in Events Manager and setting the integration up again.
Disconnecting does not delete your ad links, but it does stop events reaching
Meta, so campaigns optimising on sw_ events lose their signal. Your links
keep redirecting and installs keep being attributed.
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.
- 1
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.

- 2
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.
- 3
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.
- 4
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.

- 5
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 anattribution_matchevent 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 and sends them to the App Store. If they install and open your app, Superwall looks for a recent ad click that may correspond to that install. When a match can be made, the install is attributed to the campaign. Otherwise, it remains unattributed and appears as organic.
- Matching runs once per install, within 7 days of the click.
- No ATT prompt or IDFA is required; matching never uses them.
- Unmatched installs stay unattributed and show as
Organicin 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, or the value you set on the link |
acquisition_campaign_id | The Meta campaign ID, or the value you set on the link |
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. Links that share a language report the same value |
acquisition_product_page_id | The Custom Product Page ID, when the link uses one. Omitted for links on the default listing. To tell two links on the same language apart in every case, use acquisition_link_id |
acquisition_deeplink_id | The link's deep link ID, when set |
Use them as breakdowns and filters in charts, or in audience filters 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 | matched when the install was attributed. Otherwise no_candidates, 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:
- Ad Spend
- ROAS: proceeds divided by spend
- CPM: cost per thousand impressions
- CPT: cost per trial
- CPP: cost per paid user
- 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.
- The app must be opened for the first time within 7 days of the ad click.
SuperwallOptions.eventTrackingBehaviormust 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.
My dataset isn't listed in Superwall
The Dataset dropdown only shows web datasets. If the only dataset you see in Events Manager is your app, create a web dataset as described in Step 1 and use that instead.
If a text field appears instead of the dropdown, Superwall couldn't read the dataset list from the Meta account you connected. Type the dataset ID in directly; saving still validates it against Meta.
Events aren't showing in Meta
- Sandbox purchases are never forwarded. Only production events are sent to Meta; use Send test events 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 under Settings > Data controls > Manage event blocking in Events Manager. - Add
install.linkto the dataset's website traffic allow list. Allowingsuperwall.cominstead is the most common cause: it is the wrong domain.
No transaction or purchase events
- If you sell outside of Superwall paywalls, enable observer mode.
- Check that revenue tracking is configured. Subscription events come from App Store server notifications.
How is this guide?
Superwall as your MMP
Use Superwall as your mobile measurement partner (MMP). Attribute installs to your ad campaigns, send conversion events back to ad networks, and measure ROAS without adding another SDK.
Webhooks
Use webhooks to get real-time notifications about your app's subscription and payment events.