Cordova SDK - Supporting Deep Links

Adding Deep Linking Support

Deep links direct users to specific content within your app. When users tap a deep link on a device with your app installed, the app opens directly to the intended content, such as a product page or specific experience.

Singular tracking links support both standard deep linking (for installed apps) and deferred deep linking (for new installs). For comprehensive information, see the Deep Linking FAQ and Singular Links FAQ.


Requirements

Prerequisites

Complete the Singular Links Prerequisites to enable deep linking for your app.

Notes:


Implement Singular Links Handler

The SingularLink handler provides a callback mechanism to retrieve deep link, deferred deep link, and passthrough parameters from Singular tracking links when the app opens.

Available Parameters:

  • Deep Link (_dl): The destination URL within your app for users clicking the link
  • Deferred Deep Link (_ddl): The destination URL for users who install the app after clicking the link
  • Passthrough (_p): Custom data passed through the tracking link for additional context

Platform Configuration

Configure native platform code to pass deep link data to the Singular SDK for attribution tracking and navigation.

Android Configuration

Update MainActivity

Enable the Singular SDK to process launch-related data and handle deep links by modifying the MainActivity file to pass the Intent object to the Singular SDK.

Java
import singular_cordova_sdk.SingularCordovaSdk;

@Override
public void onNewIntent(Intent intent) {
    SingularCordovaSdk.handleNewIntent(intent);
}

The Intent object contains information about how and why your app was launched, which Singular uses for attribution tracking and deep link navigation.

Location: Add this code to your main activity file, typically located at platforms/android/app/src/main/java/[your-package]/MainActivity.java


iOS Configuration

Update AppDelegate

Enable the Singular SDK to process launch-related data and handle deep links by passing the launchOptions and userActivity objects to the Singular SDK in your AppDelegate file.

Swift
import UIKit
import SingularCordovaSdk

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    var viewController: MainViewController?
    
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Initialize window
        window = UIWindow(frame: UIScreen.main.bounds)
        
        // Configure view controller
        viewController = MainViewController()
        window?.rootViewController = viewController
        
        // Initialize Singular SDK with launch options
        SingularCordovaSdk.setLaunchOptions(launchOptions)
        
        // Make window visible
        window?.makeKeyAndVisible()
        
        return true
    }
    
    func application(
        _ application: UIApplication,
        continue userActivity: NSUserActivity,
        restorationHandler: @escaping ([Any]?) -> Void
    ) -> Bool {
        return SingularCordovaSdk.startSession(with: userActivity)
    }
}

These methods ensure the Singular SDK receives critical information about how and why your app was launched, which Singular uses for attribution tracking and deep link navigation.

Location: Modify your AppDelegate file located at platforms/ios/[YourAppName]/Classes/AppDelegate.swift or AppDelegate.m for Objective-C projects


SDK Configuration

Configure the Singular SDK to handle deep links and deferred deep links by implementing the withSingularLink callback during initialization.

Add withSingularLink Callback

Basic Implementation

Configure the withSingularLink callback to handle incoming deep link and deferred deep link data during SDK initialization.

JavaScript
// Create configuration
var singularConfig = new cordova.plugins.SingularCordovaSdk.SingularConfig(
  'YOUR_SDK_KEY',
  'YOUR_SDK_SECRET'
);

// Define link handler function
var linkHandler = function(data) {
  var deeplink = data.deeplink;
  var passthrough = data.passthrough;
  var isDeferred = data.isDeferred;
  
  console.log('Deep link:', deeplink);
  console.log('Passthrough:', passthrough);
  console.log('Is deferred:', isDeferred);
  
  // Add link handling logic here
  if (deeplink) {
    handleDeepLink(deeplink, isDeferred);
  }
};

// Attach link handler to configuration
singularConfig.withSingularLink(linkHandler);

// Initialize SDK
cordova.plugins.SingularCordovaSdk.init(singularConfig);

Note: The withSingularLink callback is triggered only when the app opens through a Singular Link. For more information, see the Singular Links FAQ.


Advanced Implementation

Implement comprehensive deep link handling with navigation logic, passthrough data parsing, and error handling for production apps.

JavaScript
document.addEventListener('deviceready', initializeApp, false);

function initializeApp() {
  // Create configuration
  var config = new cordova.plugins.SingularCordovaSdk.SingularConfig(
    'YOUR_SDK_KEY',
    'YOUR_SDK_SECRET'
  );
  
  // Configure deep link handler
  config.withSingularLink(function(params) {
    console.log('=== Singular Link Resolved ===');
    console.log('Full params:', JSON.stringify(params));
    
    var deeplink = params.deeplink;
    var passthrough = params.passthrough;
    var isDeferred = params.isDeferred;
    
    // Log for debugging
    console.log('Deep link:', deeplink || 'null');
    console.log('Passthrough:', passthrough || 'null');
    console.log('Is deferred:', isDeferred);
    
    // Handle passthrough data
    if (passthrough) {
      handlePassthroughData(passthrough);
    }
    
    // Handle deep link navigation
    if (deeplink) {
      handleDeepLinkNavigation(deeplink, isDeferred);
    }
  });
  
  // Initialize SDK
  cordova.plugins.SingularCordovaSdk.init(config);
}

function handlePassthroughData(passthroughString) {
  try {
    var data = JSON.parse(passthroughString);
    
    // Apply promo code if present
    if (data.promo_code) {
      applyPromoCode(data.promo_code);
    }
    
    // Set user segment
    if (data.segment) {
      setUserSegment(data.segment);
    }
    
    // Track campaign
    if (data.campaign_id) {
      trackCampaign(data.campaign_id);
    }
  } catch (error) {
    console.error('Error parsing passthrough:', error);
  }
}

function handleDeepLinkNavigation(url, isDeferred) {
  // Parse URL to extract route and parameters
  var urlObj = parseDeepLink(url);
  
  console.log('Navigating to: ' + urlObj.route);
  console.log('Parameters:', urlObj.params);
  console.log('Deferred install:', isDeferred);
  
  // Route based on deep link structure
  switch (urlObj.route) {
    case 'product':
      navigateToProduct(urlObj.params.id);
      break;
    case 'promo':
      navigateToPromo(urlObj.params.code);
      break;
    case 'category':
      navigateToCategory(urlObj.params.name);
      break;
    default:
      navigateToHome();
  }
}

function parseDeepLink(url) {
  // Parse myapp://product/123?variant=blue
  var parts = url.split('?');
  var path = parts[0];
  var queryString = parts[1];
  
  var pathParts = path.replace(/^[^:]+:\/\//, '').split('/');
  var route = pathParts[0];
  
  // Parse parameters
  var params = {};
  
  // Add path parameters
  if (pathParts.length > 1) {
    params.id = pathParts[1];
  }
  
  // Add query parameters
  if (queryString) {
    queryString.split('&').forEach(function(pair) {
      var keyValue = pair.split('=');
      params[keyValue[0]] = decodeURIComponent(keyValue[1]);
    });
  }
  
  return { route: route, params: params };
}

// Navigation functions
function navigateToProduct(productId) {
  console.log('Navigating to product:', productId);
  // Your navigation logic
}

function navigateToPromo(promoCode) {
  console.log('Navigating to promo:', promoCode);
  // Your navigation logic
}

function navigateToCategory(categoryName) {
  console.log('Navigating to category:', categoryName);
  // Your navigation logic
}

function navigateToHome() {
  console.log('Navigating to home');
  // Your navigation logic
}

// Utility functions
function applyPromoCode(code) {
  console.log('Applying promo code:', code);
}

function setUserSegment(segment) {
  console.log('Setting user segment:', segment);
}

function trackCampaign(campaignId) {
  console.log('Tracking campaign:', campaignId);
}

Parameter Details

Understanding the parameters provided in the Singular Link callback helps you build robust deep linking logic.

Parameter Type Description
deeplink String The destination URL within your app for users clicking the link (e.g., myapp://product/123)
passthrough String Custom data passed through the tracking link, typically JSON-encoded for additional context
isDeferred Boolean Indicates whether this is a deferred deep link (user installed the app after clicking the link)

Best Practices

  • Parse URLs Safely: Always validate and sanitize deep link URLs before using them for navigation to prevent malicious redirects
  • Handle Missing Data: Check for null or undefined values before accessing deep link parameters
  • Test Deferred Links: Test both immediate and deferred deep link scenarios to ensure proper navigation after fresh installs
  • Log for Debugging: Enable detailed logging during development to verify deep links are received and parsed correctly
  • Use Passthrough for Context: Leverage passthrough parameters to send additional context like campaign IDs, promo codes, or user segments
  • Coordinate with Marketing: Work with your marketing team to define and document your app's deep link URL structure

For complete method documentation, see withSingularLink reference.


Handler Behavior

Understanding Callback Triggers

The withSingularLink callback behavior differs depending on whether the app is freshly installed or already present on the device.

Fresh Install Scenario

On a fresh install, there is no Open URL when the app launches. Singular must complete attribution to the last touchpoint and determine if the tracking link contained a configured Deep Link or Deferred Deep Link (DDL) value.

How It Works:

  • The attribution process occurs when the Singular SDK sends the first session to Singular servers
  • If applicable, the deep link value is returned to the SDK's withSingularLink handler
  • The deep link appears in the deeplink parameter with isDeferred set to true
  • This process may take a few seconds as it requires server communication

Already Installed Scenario

If the app is already installed, clicking a Singular Link opens the app immediately. The operating system provides the full tracking link URL, which the Singular SDK parses during initialization to extract the deeplink and passthrough values.

How It Works:

  • The deep link is available immediately when the handler is triggered
  • The isDeferred parameter is set to false
  • No server communication is required, resulting in faster callback execution

Testing Deep Links

Follow these steps to test deferred deep linking behavior in your development environment.

Testing Requirements:

  1. Uninstall the app from the test device (if currently installed)
  2. Reset your advertising identifier (IDFA on iOS, GAID on Android)
  3. Click the Singular tracking link from the device. Ensure the link is configured with a deep link value
  4. Install and open the app
  5. Verify that attribution completes and the DDL value is passed to your handler

Development Build Testing: When testing with a development version of your app with a different package name (e.g., com.example.dev instead of com.example.prod), ensure the tracking link is configured specifically for the development app's package name. After clicking the test link, install the development build directly onto the test device (via CLI or IDE) rather than downloading from the app store.


Advanced Features

Passthrough Data

If a passthrough (_p) parameter is included in the tracking link, the handler's passthrough parameter contains the corresponding data. Use this for capturing campaign metadata, user segmentation data, or any custom information you need in the app.

JavaScript
// Example tracking link with passthrough:
// https://example.sng.link/A?_dl=myapp://product/123&_p={"campaign":"summer","promo":"SAVE20"}

singularConfig.withSingularLink(function(data) {
  var deeplink = data.deeplink;
  var passthrough = data.passthrough;
  
  if (passthrough) {
    // Parse JSON passthrough data
    var passthroughData = JSON.parse(passthrough);
    console.log('Campaign:', passthroughData.campaign);
    console.log('Promo code:', passthroughData.promo);
  }
});

Query Parameter Forwarding

To capture all query parameters from the tracking link URL, append the _forward_params=2 parameter to your Singular tracking link. All query parameters will be included in the deeplink parameter of the handler.

JavaScript
// Example tracking link with parameter forwarding:
// https://example.sng.link/A?_dl=myapp://product&_forward_params=2&category=electronics&sort=price

singularConfig.withSingularLink(function(data) {
  var deeplink = data.deeplink;
  // deeplink will contain: myapp://product?category=electronics&sort=price
  
  console.log('Deep link with parameters:', deeplink);
  // Parse and use the forwarded parameters
});

Important: The withSingularLink callback is triggered only when the app opens through a Singular Link. Regular app launches without a deep link will not trigger the handler.