When a user with your app installed clicks an Adjust link, direct deep linking ensures they’re taken directly to specific content within the app.
Setup
iOS provides several methods for receiving direct deep links depending on your app’s implementation.
Within these methods, you’ll pass the deep link to the Adjust SDK using one of the following methods:
Process and resolve deep link (recommended)
Use the processDeeplink(_:completionHandler:) method, which does the following:
Records attribution from deep link clicks
Resolves short branded links to their long branded link equivalent
Passes through all other links as is
Your app can then handle the resolved link by parsing it and navigating to the appropriate screen. You can use this method for all deep links, including Adjust long branded links, other universal links, and app scheme deep links.
+ ( void )processDeeplink:(nonnull NSURL * )deeplink
completionHandler:( void ( ^ _Nonnull)( NSString * _Nonnull resolvedLink))completionHandler;
Process deep link (legacy)
The appWillOpen(_:) method records attribution from deep link clicks if you’re not using short branded links .
+ ( void )appWillOpenUrl:(nonnull NSURL * )url;
The processDeeplink(_:completionHandler:) method supersedes this legacy method.
Implementation
Use the implementation that aligns with your app’s structure:
UIKit apps using AppDelegate lifecycle
Update your AppDelegate to implement iOS direct deep linking methods.
// Receive universal link when app is installed
// and link opens app from "Not Running"
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler : @escaping ([UIUserActivityRestoring] ? ) -> Void
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let incomingLink = userActivity.webpageURL
print ( "[IncomingLink] application:continueUserActivity: url= \(incomingLink. absoluteString ) " )
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
Adjust. processDeeplink (incomingLink) { resolvedLink in
// Handle failure if resolvedLink is nil
guard let resolvedLink = resolvedLink else { return }
Possible resolvedLink formats:
1. https://brandname.go.link/?adj_t=def456&
adj_link=https%3A%2F%2Fexample.com%2Fsummer-clothes%3Fpromo%3Dbeach
- Extract and decode the deep link from the 'adj_link' query parameter.
2. https://brandname.go.link/summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive app scheme deep link when app is installed
// and link opens app from "Not Running",
// Background, or Foreground state.
_ application: UIApplication,
options : [UIApplication.OpenURLOptionsKey: Any ] = [ : ]
print ( "[IncomingLink] application:openURL: url= \(incomingLink) " )
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
Adjust. processDeeplink (incomingLink) { resolvedLink in
// Handle failure if resolvedLink is nil
guard let resolvedLink = resolvedLink else { return }
example://summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive universal link when app is installed
// and link opens app from "Not Running"
- ( BOOL )application:(UIApplication * )application
continueUserActivity:(NSUserActivity * )userActivity
( void ( ^ )( NSArray <id <UIUserActivityRestoring> > * _Nullable))
// Check if it's a web browsing activity
if ( ! [userActivity.activityType
isEqualToString:NSUserActivityTypeBrowsingWeb])
// Check if there's a valid URL
NSURL * incomingLink = userActivity.webpageURL;
if ( ! incomingLink) return YES ;
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
[Adjust processDeeplink: incomingLink
completionHandler: ^ ( NSString * resolvedLink){
if ( ! resolvedLink) return ;
Possible resolvedLink formats:
1. https://brandname.go.link/?adj_t=def456&
adj_link=https%3A%2F%2Fexample.com%2Fsummer-clothes%3Fpromo%3Dbeach
- Extract and decode the deep link from the 'adj_link' query parameter.
2. https://brandname.go.link/summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive app scheme deep link when app is installed
// and link opens app from "Not Running",
// Background, or Foreground state.
- ( BOOL )application:(UIApplication * )application
openURL:( NSURL * )incomingLink
( NSDictionary < UIApplicationOpenURLOptionsKey, id> * )options {
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
[Adjust processDeeplink: incomingLink
completionHandler: ^ ( NSString * resolvedLink){
if ( ! resolvedLink) return ;
example://summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
UIKit apps using SceneDelegate lifecycle
Update your SceneDelegate to implement iOS direct deep linking methods.
// Receive universal link or app scheme deep link when app is installed
// and link opens app from "Not Running" state.
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
// Receive incoming universal link
if let userActivity = connectionOptions.userActivities. first ,
userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let incomingLink = userActivity.webpageURL
print ( "[IncomingLink] scene:willConnectToSession:options: url= \(incomingLink. absoluteString ) " )
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
Adjust. processDeeplink (incomingLink) { resolvedLink in
// Handle failure if resolvedLink is nil
guard let resolvedLink = resolvedLink else { return }
Possible resolvedLink formats:
1. https://brandname.go.link/?adj_t=def456&
adj_link=https%3A%2F%2Fexample.com%2Fsummer-clothes%3Fpromo%3Dbeach
- Extract and decode the deep link from the 'adj_link' query parameter.
2. https://brandname.go.link/summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive incoming app scheme deep link
guard let incomingLink = connectionOptions.urlContexts. first ? . url else { return }
print ( "[IncomingLink] scene:willConnectToSession:options: url= \(incomingLink. absoluteString ) " )
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
Adjust. processDeeplink (incomingLink) { resolvedLink in
// Handle failure if resolvedLink is nil
guard let resolvedLink = resolvedLink else { return }
example://summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive universal link when app is installed
// and link opens app from Background state.
func scene ( _ scene: UIScene, continue userActivity: NSUserActivity) {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let incomingLink = userActivity.webpageURL
print ( "[IncomingLink] scene:continueUserActivity: url= \(incomingLink. absoluteString ) " )
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
Adjust. processDeeplink (incomingLink) { resolvedLink in
// Handle failure if resolvedLink is nil
guard let resolvedLink = resolvedLink else { return }
Possible resolvedLink formats:
1. https://brandname.go.link/?adj_t=def456&
adj_link=https%3A%2F%2Fexample.com%2Fsummer-clothes%3Fpromo%3Dbeach
- Extract and decode the deep link from the 'adj_link' query parameter.
2. https://brandname.go.link/summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive app scheme deep link when app is installed
// and link opens app from Background
openURLContexts URLContexts: Set <UIOpenURLContext>
guard let incomingLink = URLContexts. first ? . url else { return }
print ( "[IncomingLink] scene:openURLContexts: url= \(incomingLink. absoluteString ) " )
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
Adjust. processDeeplink (incomingLink) { resolvedLink in
// Handle failure if resolvedLink is nil
guard let resolvedLink = resolvedLink else { return }
example://summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive universal link or app scheme deep link when app is installed
// and link opens app from "Not Running" state.
- ( void )scene:(UIScene * )scene
willConnectToSession:(UISceneSession * )session
options:(UISceneConnectionOptions * )connectionOptions {
// Receive universal link
if (connectionOptions.userActivities.count > 0 ) {
NSUserActivity * userActivity =
connectionOptions.userActivities.allObjects.firstObject;
if ([userActivity.activityType
isEqualToString:NSUserActivityTypeBrowsingWeb] &&
userActivity.webpageURL) {
NSURL * incomingLink = userActivity.webpageURL;
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
[Adjust processDeeplink: incomingLink
completionHandler: ^ ( NSString * resolvedLink){
if ( ! resolvedLink) return ;
Possible resolvedLink formats:
1. https://brandname.go.link/?adj_t=def456&
adj_link=https%3A%2F%2Fexample.com%2Fsummer-clothes%3Fpromo%3Dbeach
- Extract and decode the deep link from the 'adj_link' query parameter.
2. https://brandname.go.link/summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive app scheme deep link
if (connectionOptions.URLContexts.count == 0 ) return ;
UIOpenURLContext * urlContext =
connectionOptions.URLContexts.allObjects.firstObject;
NSURL * incomingLink = urlContext.URL;
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
[Adjust processDeeplink: incomingLink
completionHandler: ^ ( NSString * resolvedLink){
if ( ! resolvedLink) return ;
example://summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive universal link when app is installed
// and link opens app from Background state.
- ( void )scene:(UIScene * )scene
continueUserActivity:(NSUserActivity * )userActivity {
// Check if it's a web browsing activity
if ( ! [userActivity.activityType
isEqualToString:NSUserActivityTypeBrowsingWeb])
// Check if there's a valid URL
NSURL * incomingLink = userActivity.webpageURL;
if ( ! incomingLink) return ;
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
[Adjust processDeeplink: incomingLink
completionHandler: ^ ( NSString * resolvedLink){
if ( ! resolvedLink) return ;
Possible resolvedLink formats:
1. https://brandname.go.link/?adj_t=def456&
adj_link=https%3A%2F%2Fexample.com%2Fsummer-clothes%3Fpromo%3Dbeach
- Extract and decode the deep link from the 'adj_link' query parameter.
2. https://brandname.go.link/summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
// Receive app scheme deep link when app is installed
// and link opens app from Background
- ( void )scene:(UIScene * )scene
openURLContexts:( NSSet < UIOpenURLContext *> * )URLContexts {
// Check if we have any URL contexts
UIOpenURLContext * urlContext = URLContexts.allObjects.firstObject;
// Check if the URL is valid
NSURL * incomingLink = urlContext.URL;
if ( ! incomingLink) return ;
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
[Adjust processDeeplink: incomingLink
completionHandler: ^ ( NSString * resolvedLink){
if ( ! resolvedLink) return ;
example://summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
SwiftUI apps using AppDelegate lifecycle
If you haven’t already done so, create an AppDelegate.swift file in your project’s main directory and reference it in your main application file, as shown in the example App.swift file below. This is required to handle app lifecycle events and Adjust SDK integration. Also, implement the onOpenURL SwiftUI modifier, which receives universal links and app scheme deep links when the app is installed.
@UIApplicationDelegateAdaptor (AppDelegate. self ) var appDelegate
// Receive universal link or app scheme deep link when app is installed
// and link opens app from "Not Running",
// Background, or Foreground state.
. onOpenURL { incomingLink in
print ( "[IncomingLink] onOpenURL: url= \(incomingLink. absoluteString ) " )
// Send deep link to Adjust's servers for attribution.
// If short branded link, receive long link.
// Otherwise, receive original link.
Adjust. processDeeplink (incomingLink) { resolvedLink in
// Handle failure if resolvedLink is nil
guard let resolvedLink = resolvedLink else { return }
Possible resolvedLink formats:
1. https://brandname.go.link/?adj_t=def456&
adj_link=https%3A%2F%2Fexample.com%2Fsummer-clothes%3Fpromo%3Dbeach
- Extract and decode the deep link from the 'adj_link' query parameter.
2. https://brandname.go.link/summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
3. example://summer-clothes?promo=beach&adj_t=def456
- Extract the path and relevant query parameters directly from the URL.
TODO: Handle the deep link and navigate to the appropriate screen.
SwiftUI apps using SceneDelegate lifecycle
Follow the instructions in the SwiftUI apps using AppDelegate lifecycle section. The onOpenURL SwiftUI modifier receives universal links and app scheme deep links when the app is installed and the link opens the app from a Background or Foreground state.
In addition, implement the scene(_:willConnectTo:options:) method from the UIKit apps using SceneDelegate lifecycle section. This method receives universal links and app scheme deep links when the app is installed and the link opens the app from a “Not Running” state.
Foreground navigation
If you place an Adjust deep link inside your own app, such as in a promotional banner or product recommendation, don’t call UIApplication.open(_:options:completionHandler:) or SwiftUI’s openURL on it. iOS opens your app’s own universal links in Safari instead of routing them within the app. Instead, pass the link through processDeeplink and then route the resolved deep link using the same handling path described on this page.