Flutter Deep Linking with AppsFlyer Legacy OneLink: A Comprehensive Guide

Flutter Deep Linking with AppsFlyer Legacy OneLink: A Comprehensive Guide

TB

Teqani Blogs

Writer at Teqani

November 17, 20256 min read

This article serves as a comprehensive guide to understanding and implementing deep linking in Flutter applications using AppsFlyer's Legacy OneLink. It addresses common confusions and provides clarity on payload behavior, parameter handling, and domain verification.

Introduction

Deep linking with AppsFlyer in Flutter can be complex, especially when dealing with the legacy OneLink structure. This guide provides practical insights into how legacy OneLink behaves in Flutter, which parameters are delivered in onDeepLinking, and how to correctly handle deep link values.

AppsFlyer's documentation may sometimes mix legacy and new mode behaviors, leading to discrepancies between expected parameters and the actual payload inside Flutter. This article aims to clarify these differences and provide a clear path to successful deep linking.

Legacy OneLink Payload Behavior in Flutter

AppsFlyer's documentation suggests that OneLink parameters like af_sub1 should be included in the payload. However, real-world testing shows a different behavior. When using legacy OneLink, avoid parsing logic for af_sub*.

Instead, focus on using deep_link_value and deep_link_subX. A working OneLink URL should resemble the following:

https://yourbrand.onelink.me/AbCd?pid=invite&c=referral_campaign&deep_link_value=ABC123//referral value&deep_link_sub1=bonus10//optional data

AppsFlyer Flutter SDK Callbacks

The AppsFlyer Flutter SDK provides three primary callbacks:

  • onDeepLinking: Use for direct and deferred deep linking; contains deep link parameters in the payload.
  • onInstallConversionData: Use for attribution data only.
  • onAppOpenAttribution: Use for legacy re-open attribution.

Only onDeepLinking contains the actual deep link parameters in Flutter. The other callbacks are limited to measurement and attribution data.

Here's an example of how to handle deep_link_value and deep_link_sub1:

class AppsflyerUtil {
 const AppsflyerUtil._();
 static AppsflyerSdk? _appsflyerSdk;
 static String? inviteCode;
 static Future<void> init() async {
 final options = AppsFlyerOptions(
 afDevKey: AF_DEV_KEY,
 appId: APP_ID,
 showDebug: kDebugMode,
 appInviteOneLink: null,
 disableAdvertisingIdentifier: false,
 disableCollectASA: false,
 manualStart: true,
 );
 _appsflyerSdk = AppsflyerSdk(options);
 _appsflyerSdk!
 .initSdk(
 registerConversionDataCallback: false,
 registerOnAppOpenAttributionCallback: false,
 registerOnDeepLinkingCallback: true,
 )
 .then((_) {
 _setupCallbacks();
 _appsflyerSdk!.startSDK(
 onSuccess: () {
 debugPrint("Appsflyer INIT Success");
 },
 onError: (errorCode, errorMessage) {
 debugPrint(errorMessage);
 },
 );
 });
 }

 static void _setupCallbacks() {
 _appsflyerSdk!.onDeepLinking(
 (deepLinkResult) {
 debugPrint("onDeepLinking: ${deepLinkResult.toJson()}");
 String? campaignName;
 //* ONELINK DEEPLINK
 if (deepLinkResult.deepLink?.deepLinkValue != null) {
 inviteCode = deepLinkResult.deepLink?.deepLinkValue;
 if (deepLinkResult.deepLink?.clickEvent["deep_link_sub1"] != null) {
 campaignName =
 deepLinkResult.deepLink?.clickEvent["deep_link_sub1"];
 }
 }
 }
 );
 }
}

Android Domain Verification (Digital Asset Links)

For Android deep links to reliably open in your app, you must:

  • Add your host to the Flutter intent filters.
  • Ensure your host appears under Supported Links in Android device settings.
  • Verify your host.

First, add your OneLink domains in your AndroidManifest.xml:

<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
<intent-filter android:autoVerify="true">
 <action android:name="android.intent.action.VIEW" />
 <category android:name="android.intent.category.DEFAULT" />
 <category android:name="android.intent.category.BROWSABLE" />
 <data android:scheme="https" android:host="your_domain.onelink.me" />
</intent-filter>

Set flutter_deeplinking_enabled to false to allow the AppsFlyer plugin to correctly handle deep linking. Verify your app domains using the following ADB prompt:

adb shell pm get-app-links YOUR.PACKAGE.NAME

If the host shows as unverified, deep links may open in the browser instead of your app.

To solve host verification problems:

  1. Go to Google Play Console → Your App → Setup → Deep Links → App Links Verification.
  2. Copy the provided JSON block.
  3. Place the block inside https://yourdomain.com/.well-known/assetlinks.json.
  4. Wait a few minutes.
  5. Run the ADB command again; the host should become verified.

The JSON block looks like this:

{
 "relation": ["delegate_permission/common.handle_all_urls"],
 "target": {
 "namespace": "android_app",
 "package_name": "your.package.name",
 "sha256_cert_fingerprints": [
 "AB:CD:EF:...."
 // Google provides another fingerprint value too here especially, we
 // need that also. Dont forget copy too it.
 ]
 }
}

Apple Side Verifications

For iOS, ensure your domains are added to Info.plist:

<key>com.apple.developer.associated-domains</key>
<array>
 <string>applinks:your_domain.onelink.me</string>
</array>

When you modify the Apple asset file (either the branded domain's apple site association file or the auto-generated OneLink file), be aware that Apple caches these files. Changes may not be immediately reflected. Allow time for Apple's server-side cache to expire before testing.

Conclusion

Legacy OneLink behaves differently in Flutter than expected, particularly regarding delivered parameters and crucial callbacks. The onDeepLinking callback is the most reliable source for deep-link payloads, while others primarily provide attribution data. Consistent behavior across direct and deferred flows is achieved by exclusively using deep_link_value and deep_link_subX.

Proper domain verification is essential. Android App Links require correct assetlinks.json configuration and matching SHA-256 fingerprints, while iOS may delay updates due to Apple's caching of association files. With correct configuration, Flutter deep linking with AppsFlyer becomes stable and production-ready.

TB

Teqani Blogs

Verified
Writer at Teqani

Senior Software Engineer with 10 years of experience

November 17, 2025
Teqani Certified

All blogs are certified by our company and reviewed by our specialists
Issue Number: #a11350dc-d750-4b2d-9a0e-2cc237849d22