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).

Funnel builder with the component library open on the left; the AppsFlyer OneLink row is highlighted in the Others category and a preview card to its right shows the component on a sample page with a Download App button.

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

The placed AppsFlyer OneLink rendered on the funnel page with an Open App label, and the right-side configuration panel showing Content (Button Type, Button Text, Destination URL), Store Links, and the Built-in Parameters toggle list.

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.

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.

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 resolve paramName from the funnel landing page's window.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>.

Don't swap Label and Description: This is the most common cause of "AppsFlyer attribution didn't work" reports. The AppsFlyer key always goes on the left (Label); the value or {{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 to mediaSource.defaultValue (defaults to whatever's in the destination URL, then "organic" if absent)
  • c → maps to campaign.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:

Code
placement={{placement}}&campaign_name={{campaign.name}}&campaign_id={{campaign.id}}&adset_name={{adset.name}}&adset_id={{adset.id}}&ad_name={{ad.name}}&ad_id={{ad.id}}&site_source_name={{site_source_name}}

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:

  • pid and af_click_lookback belong on the destination URL, e.g. https://yourapp.onelink.me/abc1?pid=metaweb_int&af_click_lookback=7d.
  • _fbp and _fbc are read automatically from cookies via Built-in Parameters.
  • lpurl is handled by AppsFlyer's Smart Script.
Verify Meta's macros are landing: Open the funnel from a real ad click and run 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:

SituationWhat happens
Smart Script still loadingButton uses direct URL fallback (params appended to destination)
Smart Script fails to loadSame — direct URL fallback
generateOneLinkURL() returns nullConsole warning + direct URL fallback
generateOneLinkURL() returns invalid URLConsole 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#

  1. Open the funnel in Live mode (the URL builder is no-op in editor preview).
  2. Open the browser DevTools console.
  3. Tap the button. You should see [DeepLinkButton] AF Smart Script loaded followed by [DeepLinkButton] URL: https://yourapp.onelink.me/...?....
  4. Inspect the URL — confirm your enabled built-in params are present with the expected keys, and your OneLink params are resolved.
  5. On a real device with AppsFlyer SDK installed, tap the live link and confirm onConversionDataSuccess receives the params.

Troubleshooting#

SymptomLikely causeFix
Click does nothingFunnel is in preview/editor modeOpen the live funnel URL, not the builder
Params missing from final URLField is disabled, or source value is emptyToggle 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_FeedLabel and Description are swappedPut the AppsFlyer key on the left (Label) and {{landing_param}} on the right (Description). See Common mistake: swapped columns
All {{...}} rows resolve to empty valuesMeta's URL parameters field isn't passing macros into the landing URLAdd the macros in Meta Ads Manager (see Forwarding Meta ad data)
Garbled non-ASCII characters in paramsAd network injected unicode into the source valueAlready sanitized — verify in the console output that the cleaned value looks right
[DeepLinkButton] AF Smart Script failed to load or ERR_BLOCKED_BY_CLIENTBrowser ad blocker (uBlock, Brave Shields, Privacy Badger, etc.) blocks onelinksmartscript.appsflyer.com, or your CSP doesFor 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 emptyThe 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 unexpectedlyA OneLink Parameter row is using key pidRemove it, or put the value on the destination URL instead
Deep Link Button
The standard, non-AppsFlyer button.
Deep linking overview
Adjust, Branch, and other providers.
app_user_id
What the App User ID conversion param resolves to.
Mobile app with RevenueCat
End-to-end install → onboarding flow.