Unified deep linking (UDL)
This page has a newer version
At a glance: Unified deep linking (UDL) enables you to send new and existing users to a specific in-app activity (for example, a specific page in the app) as soon as the app is opened.
UDL privacy protection
For new users, the UDL method only returns parameters relevant to deferred deep linking:
deep_link_value
anddeep_link_sub1-10
. If you try to get any other parameters (media_source
,campaign
,af_sub1-5
, etc.), they returnnull
.
Flow

UDL routes mobile users into a specific activity or content in an app.
The flow works as follows:
- User clicks a OneLink link.
- If the user has the app installed, the Universal Links or URI scheme opens the app.
- If the user doesn’t have the app installed, they are redirected to the app store, and after downloading, the user opens the app.
- The app open triggers the AppsFlyer SDK.
- The AppsFlyer SDK runs the UDL API.
- The UDL API retrieves OneLink data from AppsFlyer servers.
- The UDL API calls back the
didResolveDeepLink()
in theDeepLinkDelegate
. - The
didResolveDeepLink()
method gets aDeepLinkResult
object. - The
DeepLinkResult
object includes:- Status (Found/Not found/Failure)
- A
DeepLink
object that carries thedeep_link_value
anddeep_link_sub1-10
parameters that the developer uses to route the user to a specific in-app activity, which is the main goal of OneLink.
Prerequisites
- UDL requires AppsFlyer iOS SDK V6.1+.
Planning
When setting up OneLinks, the marketer uses parameters to create the links, and the developer customizes the behavior of the app based on the values received. It is the developer's responsibility to make sure the parameters are handled correctly in the app, for both in-app routing, and personalizing data in the link.
To plan the OneLink:
- Get from the marketer the desired behavior and personal experience a user gets when they click the URL.
- Based on the desired behavior, plan the
deep_link_value
and other parameters that are needed to give the user the desired personal experience.- The
deep_link_value
is set by the marketer in the URL and used by the developer to redirect the user to a specific place inside the app. For example, if you have a fruit store and want to direct users to apples, the value ofdeep_link_value
can beapples
. - The
deep_link_sub1-10
parameters can also be added to the URL to help personalize the user experience. For example, to give a 10% discount, the value ofdeep_link_sub1
can be10
.
- The
Implementation
Implement the UDL API logic based on the chosen parameters and values.
- Assign the
AppDelegate
usingself
toAppsFlyerLib.shared().deepLinkDelegate
. - Implement application function to allow:
- Universal Links support with
continue
- URI scheme support with
handleOpen
- Universal Links support with
- Create
DeepLinkDelegate
as an extension ofAppDelegate
. - Add
application
functions to support Universal Links and URI schemes. - In
DeepLinkDelegate
, make sure you override the callback function,didResolveDeepLink()
.
didResolveDeepLink()
accepts aDeepLinkResult
object as an argument. - Use
DeepLinkResult.status
to query whether the deep linking match is found. - For when the status is an error, call
DeepLinkResult.error
and run your error flow. - For when the status is found, use
DeepLinkResult.deepLink
to retrieve theDeepLink
object.
TheDeepLink
object contains the deep linking information arranged in public variables to retrieve the values from well-known OneLink keys, for example,DeepLink.deeplinkValue
fordeep_link_value
. - Use
deepLinkObj.clickEvent["deep_link_sub1"]
to retrievedeep_link_sub1
. Do the same fordeep_link_sub2-10
parameters, changing the string value as required. - Once
deep_link_value
anddeep_link_sub1-10
are retrieved, pass them to an in-app router and use them to personalize the user experience.
Code example
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
AppsFlyerLib.shared().deepLinkDelegate = self
...
}
// For Swift version < 4.2 replace function signature with the commented out code
// func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool { // this line for Swift < 4.2
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
AppsFlyerLib.shared().continue(userActivity, restorationHandler: nil)
return true
}
// Open URI-scheme for iOS 9 and above
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
AppsFlyerLib.shared().handleOpen(url, options: options)
return true
}
extension AppDelegate: DeepLinkDelegate {
func didResolveDeepLink(_ result: DeepLinkResult) {
var fruitNameStr: String?
switch result.status {
case .notFound:
NSLog("[AFSDK] Deep link not found")
return
case .failure:
print("Error %@", result.error!)
return
case .found:
NSLog("[AFSDK] Deep link found")
}
guard let deepLinkObj:DeepLink = result.deepLink else {
NSLog("[AFSDK] Could not extract deep link object")
return
}
if deepLinkObj.clickEvent.keys.contains("deep_link_sub2") {
let ReferrerId:String = deepLinkObj.clickEvent["deep_link_sub2"] as! String
NSLog("[AFSDK] AppsFlyer: Referrer ID: \(ReferrerId)")
} else {
NSLog("[AFSDK] Could not extract referrerId")
}
let deepLinkStr:String = deepLinkObj.toString()
NSLog("[AFSDK] DeepLink data is: \(deepLinkStr)")
if( deepLinkObj.isDeferred == true) {
NSLog("[AFSDK] This is a deferred deep link")
}
else {
NSLog("[AFSDK] This is a direct deep link")
}
fruitNameStr = deepLinkObj.deeplinkValue
walkToSceneWithParams(fruitName: fruitNameStr!, deepLinkData: deepLinkObj.clickEvent)
}
}
// User logic
fileprivate func walkToSceneWithParams(deepLinkObj: DeepLink) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: true, completion: nil)
guard let fruitNameStr = deepLinkObj.clickEvent["deep_link_value"] as? String else {
print("Could not extract query params from link")
return
}
let destVC = fruitNameStr + "_vc"
if let newVC = storyBoard.instantiateVC(withIdentifier: destVC) {
print("AppsFlyer routing to section: \(destVC)")
newVC.deepLinkData = deepLinkObj
UIApplication.shared.windows.first?.rootViewController?.present(newVC, animated: true, completion: nil)
} else {
print("AppsFlyer: could not find section: \(destVC)")
}
}
⇲ Github links: Swift
Updated 2 months ago