Tracking deep links (iOS)

If your application handles deep links, getting this data into Heap is important for measuring campaign performance and tracking navigation patterns in your app.

When a deep link is used to open your application, it will come through via an NSUserActivity object. You can parse the deep link URL and pass relevant pieces of information to Heap to use in future analysis.

There is no built-in deep link event type at this time, but this data can be tracked using Heap’s custom event tracking API. An example of what this looks like is illustrated below.

// 1. macOS app delegate
func application(_ application: NSApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([NSUserActivityRestoring]) -> Void) -> Bool {
    handleDeepLink(userActivity: userActivity)
    return true
}

// 2. iOS and tvOS app delegate
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    handleDeepLink(userActivity: userActivity)
    return true
}

// 3. iOS and TVOS scene delegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    for userActivity in connectionOptions.userActivities {
        handleDeepLink(userActivity: userActivity)
    }
}

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
  	handleDeepLink(userActivity: userActivity)
}

// 4. watchOS extension delegate
func handle(_ userActivity: NSUserActivity) {
    handleDeepLink(userActivity: userActivity)
}

func handleDeepLink(userActivity: NSUserActivity) {
    guard let url = userActivity.webpageURL else { return }
    
    var properties = [
      "deep_link_full": url.absoluteString,
      "deep_link_path": url.path,
    ]

    properties["deep_link_scheme"] = url.scheme
    properties["deep_link_domain"] = url.host
    
    if let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems {
        for queryItem in queryItems {
            properties["deep_link_param_\(queryItem.name)"] = queryItem.value
        }
    }
    
    Heap.shared.track("deep_link_received", properties: properties)
}
// 1. macOS app delegate
- (BOOL)application:(NSApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>> *restorableObjects))restorationHandler
{
    [self handleDeepLinkWithUserActivity:userActivity];
    return YES;
}

// 2. iOS and tvOS app delegate
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler
{
    [self handleDeepLinkWithUserActivity:userActivity];
    return YES;
}

// 3. iOS and TVOS scene delegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
{
    for (NSUserActivity * in connectionOptions.userActivities) {
        [self handleDeepLinkWithUserActivity:userActivity];
    }
}

- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity
{
    [self handleDeepLinkWithUserActivity:userActivity];
}

// 4. watchOS extension delegate
- (void)handleActivity:(NSUserActivity *)userActivity
{
    [self handleDeepLinkWithUserActivity:userActivity];
}

// Function to handle deep link
- (void)handleDeepLinkWithUserActivity:(NSUserActivity *)userActivity
{
    NSURL *url = userActivity.webpageURL;
    if (!url) return;

    NSMutableDictionary<NSString *, NSString *> *properties = [NSMutableDictionary dictionary];
    
    properties[@"deep_link_full"] = url.absoluteString;
    properties[@"deep_link_scheme"] = url.scheme;
    properties[@"deep_link_domain"] = url.host;
    properties[@"deep_link_path"] = url.path;

    NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
    for (NSURLQueryItem *item in components.queryItems) {
        properties[[NSString stringWithFormat:@"deep_link_param_%@", item.name]] = item.value;
    }

    [Heap.sharedInstance track:@"deep_link_received" properties:properties];
}