AppsFlyer OneLink
For mobile teams using AppsFlyer OneLink for install attribution and deferred deep linking. You'll have a success-page button that hands off paid users to OneLink with funnel context already encoded as conversion parameters. You need an AppsFlyer account with a OneLink template configured.
What it does#
The AppsFlyer OneLink component is a variant of the standard Deep Link Button that integrates with AppsFlyer's OneLink Smart Script. On mount it loads the Smart Script from onelinksmartscript.appsflyer.com. On click it builds a OneLink config from your destination URL and parameters, then calls AF_SMART_SCRIPT.generateOneLinkURL() to produce a click URL that AppsFlyer can attribute. If the Smart Script fails to load or returns an invalid URL, the button falls back to appending the same parameters directly to the destination URL.
Setup#
1. Add the component to your success page#
In the funnel builder, drag the AppsFlyer OneLink component from the component library (under Others) onto the page positioned after your paywall (the success page).

Click the placed component to open its configuration panel on the right side of the builder.

2. Set the Destination URL#
Paste your OneLink template URL into the Destination URL field, e.g. https://yourapp.onelink.me/abc1. You can include pid and c query params on this URL — they become the OneLink campaign's media source and campaign name.
3. Toggle Built-in Parameters#
Toggle on the contextual values you want appended to the OneLink URL — App User ID, Email, Funnel ID, etc. See Built-in Parameters below for the full list and rationale.
4. Add OneLink Parameters (optional)#
For arbitrary key/value pairs that don't fit the built-in list — for example, re-mapping ad-network params from the funnel landing URL to AppsFlyer keys — use the dedicated OneLink Parameters section. See OneLink Parameters below.
5. Read params in your app#
The mobile-side wiring is unchanged from a standard AppsFlyer integration — no Zellify-specific SDK. Initialize the AppsFlyer SDK with your dev key and OneLink ID, implement onConversionDataSuccess, and read the af_* conversion params plus any custom params you sent (app_user_id, email, etc.). A common pattern: call your backend with app_user_id to look up the funnel session, fetch the user's plan or RevenueCat entitlement, and drop them in the right onboarding step. See AppsFlyer's conversion data docs for the full SDK API.
Built-in Parameters#
Same nine fields as the standard Deep Link Button — Funnel ID, Organization ID, Campaign ID (default key af_c_id), Experiment ID, Email, App User ID, Stripe Customer ID, Meta FBP, Meta FBC. All disabled by default; toggle on the ones your app needs.
When the Smart Script is active, every enabled built-in parameter is added to the OneLink config as an afCustom entry with keys: []. Setting keys: [] is deliberate — it forces AppsFlyer to use only the value Zellify provides and stops it from scanning the current page URL for a matching key. Without that guard, ambient ad-network parameters on the funnel URL (?auid=..., etc.) can collide with conversion params and produce corrupted values like uuid_我的_dddd.
If the Smart Script falls back, the same parameters are appended directly to the destination URL.
See the Deep Link Button reference for the per-field source mapping.
OneLink Parameters#
The dedicated OneLink Parameters section lets you add arbitrary key/value pairs that don't fit the built-in list. Toggle Enable OneLink Parameters on to expose the editor.
Each row has two columns and the order matters:
- Label → the AppsFlyer parameter key (e.g.
af_siteid,c,af_adset) - Description → the value sent for that key
Two value modes are supported:
- Static text — used as-is. Sanitized to ASCII before sending.
- Landing-page reference — write
{{paramName}}to resolveparamNamefrom the funnel landing page'swindow.location.search. Empty/missing params resolve to nothing and the row is skipped.
Example: row with Label af_sub1 and Description {{fbclid}} forwards fbclid from the funnel's landing URL into the OneLink as af_sub1=<value>.
{{template}} always goes on the right (Description). See Forwarding Meta ad data for a worked example.Special handling for pid and c#
If a OneLink Parameter row uses Label pid or c, it overrides the corresponding values from the destination URL:
pid→ maps tomediaSource.defaultValue(defaults to whatever's in the destination URL, then"organic"if absent)c→ maps tocampaign.defaultValue(defaults to whatever's in the destination URL, then empty string)
All other rows go into afCustom. Any query params already present on the destination URL (excluding pid and c) are preserved as additional afCustom entries.
Forwarding Meta ad data#
A typical Meta + AppsFlyer setup forwards placement, campaign, ad set, ad ID, etc. from the Meta ad through the funnel into AppsFlyer's conversion params. Two pieces:
1. Configure Meta to pass macros into the funnel landing URL#
In Meta Ads Manager, on the ad level, set the URL parameters field so Meta substitutes its macros into every click URL:
Meta automatically appends fbclid, so you don't need to add it.
2. Re-map landing-page params to AppsFlyer keys#
In OneLink Parameters, add one row per field — AppsFlyer key on the left, {{landing_param}} on the right:
| Label (AppsFlyer key) | Description (value) |
|---|---|
af_siteid | {{placement}} |
c | {{campaign_name}} |
af_c_id | {{campaign_id}} |
af_adset | {{adset_name}} |
af_adset_id | {{adset_id}} |
af_ad | {{ad_name}} |
af_ad_id | {{ad_id}} |
af_sub1 | {{fbclid}} |
af_sub2 | {{site_source_name}} |
You don't need to add pid, af_click_lookback, _fbp, _fbc, or lpurl:
pidandaf_click_lookbackbelong on the destination URL, e.g.https://yourapp.onelink.me/abc1?pid=metaweb_int&af_click_lookback=7d._fbpand_fbcare read automatically from cookies via Built-in Parameters.lpurlis handled by AppsFlyer's Smart Script.
new URLSearchParams(location.search).toString() in the browser console. You should see placement=...&campaign_name=...&fbclid=... in the output. If those are empty, fix step 1 before re-testing — the {{...}} lookups in step 2 will resolve to nothing without them.Common mistake: swapped columns#
A common error is to enter the Meta param name on the left and the AppsFlyer key on the right (e.g. placement → af_siteid). This generates ?placement=af_siteid&campaign_name=c on the OneLink URL — AppsFlyer never sees af_siteid or c set to a real value, and attribution fails. The right pattern is AppsFlyer key on the left, {{landing_param}} on the right (as in the table above).
App Store Buttons mode#
Switch Button Type to "App Store Buttons" to render Apple + Google Play badges instead of a single CTA. Both badges go through the OneLink Smart Script — the App Store and Play Store URLs each get the same parameter-injection treatment.
This is the right pattern when your OneLink template auto-routes platform-specific store URLs. If you want each badge to point at a different OneLink (e.g. an iOS-only OneLink and a separate Android-only one), put the relevant URL in each badge's Link field.
Fallback behaviour#
The button gracefully degrades when AppsFlyer is unavailable:
| Situation | What happens |
|---|---|
| Smart Script still loading | Button uses direct URL fallback (params appended to destination) |
| Smart Script fails to load | Same — direct URL fallback |
generateOneLinkURL() returns null | Console warning + direct URL fallback |
generateOneLinkURL() returns invalid URL | Console warning + direct URL fallback |
| Live mode disabled (preview/editor) | No URL is built; click is a no-op |
Open the browser console to see exactly which path was taken. Lines are prefixed with [DeepLinkButton].
Test and verify#
- Open the funnel in Live mode (the URL builder is no-op in editor preview).
- Open the browser DevTools console.
- Tap the button. You should see
[DeepLinkButton] AF Smart Script loadedfollowed by[DeepLinkButton] URL: https://yourapp.onelink.me/...?.... - Inspect the URL — confirm your enabled built-in params are present with the expected keys, and your OneLink params are resolved.
- On a real device with AppsFlyer SDK installed, tap the live link and confirm
onConversionDataSuccessreceives the params.
Troubleshooting#
| Symptom | Likely cause | Fix |
|---|---|---|
| Click does nothing | Funnel is in preview/editor mode | Open the live funnel URL, not the builder |
| Params missing from final URL | Field is disabled, or source value is empty | Toggle on in Built-in Parameters; check the source value resolves (e.g. is the user actually a Stripe customer?) |
Generated URL has e.g. placement=af_siteid instead of af_siteid=Facebook_Mobile_Feed | Label and Description are swapped | Put the AppsFlyer key on the left (Label) and {{landing_param}} on the right (Description). See Common mistake: swapped columns |
All {{...}} rows resolve to empty values | Meta's URL parameters field isn't passing macros into the landing URL | Add the macros in Meta Ads Manager (see Forwarding Meta ad data) |
| Garbled non-ASCII characters in params | Ad network injected unicode into the source value | Already sanitized — verify in the console output that the cleaned value looks right |
[DeepLinkButton] AF Smart Script failed to load or ERR_BLOCKED_BY_CLIENT | Browser ad blocker (uBlock, Brave Shields, Privacy Badger, etc.) blocks onelinksmartscript.appsflyer.com, or your CSP does | For testing, disable extensions or use a clean profile. End-users on mobile rarely run ad blockers; the component falls back to a direct URL with the same params either way |
OneLink param {{fbclid}} resolves empty | The funnel landing page didn't have ?fbclid=... | Confirm the original ad-network click landed on a URL with fbclid and that the user hasn't navigated away to a clean URL |
pid overridden unexpectedly | A OneLink Parameter row is using key pid | Remove it, or put the value on the destination URL instead |