DeepLinkNow iOS SDK Documentation

Overview

DeepLinkNow (DLN) is a lightweight, powerful deep linking and attribution SDK for iOS applications. It enables you to handle deep links, deferred deep links, and track user attribution seamlessly. This document covers all the essential features and how to implement them in your iOS application.

Table of Contents

Requirements

  • iOS 13.0+
  • Swift 5.0+
  • Xcode 13.0+

Installation

CocoaPods

Add this to your

Podfile
:

pod 'DeepLinkNow', '~> 0.4'

Then run:

pod install

Getting Started

Initializing the SDK

Before using any features of the SDK, you must initialize it with your API key. The API key can be obtained from your DeepLinkNow dashboard.

// Using async/await (recommended)
Task {
    let config = DLNConfig(
        apiKey: "your-api-key-here",
        enableLogs: true  // Set to true during development, false in production
    )
    await DeepLinkNow.initialize(config: config)

    // Now the SDK is ready to use
}

Configuration Options

The SDK can be initialized with several configuration options:

let config = DLNConfig(
    apiKey: "your-api-key-here",
    enableLogs: true,           // Enable debug logging (optional)
    baseUrl: "custom-url.com",  // Custom API endpoint (optional)
    timeout: 30.0,              // Custom timeout in seconds (optional)
    retryAttempts: 3            // Number of retry attempts (optional)
)

Deep Linking Features

Deferred Deep Linking

Deferred deep linking allows you to route users to specific content even if they didn't have your app installed when they clicked on a link. The SDK can match users across installations using device fingerprinting.

Finding Fingerprinted Users

The most common use case is to check for deferred deep links when a user first opens your app. This should be done after initializing the SDK:

Task {
    // First, initialize the SDK
    let config = DLNConfig(apiKey: "your-api-key-here")
    await DeepLinkNow.initialize(config: config)

    // Then check for deferred users
    if let matchResponse = await DeepLinkNow.findDeferredUser() {
        // The SDK returns up to 5 potential matches with confidence scores
        for match in matchResponse.matches {
            // Check the confidence score to determine if the match is reliable
            let confidenceScore = match.confidenceScore

            // You can examine what parameters matched
            if let deviceMatch = match.matchDetails.deviceMatch {
                let deviceMatchScore = deviceMatch.score
                let platformMatched = deviceMatch.components.platform
                let osVersionMatched = deviceMatch.components.osVersion
                let deviceModelMatched = deviceMatch.components.deviceModel
            }

            // Check IP address match
            let ipMatch = match.matchDetails.ipMatch.matched
            let ipMatchScore = match.matchDetails.ipMatch.score

            // Check locale match (language, timezone)
            let localeMatchScore = match.matchDetails.localeMatch.score

            // Access the deep link if available
            if let deeplink = match.deeplink {
                // Get the target URL to route the user
                let targetUrl = deeplink.targetUrl

                // Access custom metadata
                let metadata = deeplink.metadata

                // Access campaign information if available
                let campaignId = deeplink.campaignId

                // Check expiration
                let expiresAt = deeplink.expiresAt

                // Use this information to route the user to the right place in your app
                navigateToContent(targetUrl, metadata)
            }
        }
    } else {
        // No deferred deep link found
        // Proceed with normal app flow
    }
}

If you don't find a fingerprinted user, you can optionally check the clipboard for a deep link. The SDK provides helper methods for this:

// First, check if the clipboard contains a potential deep link token
if DeepLinkNow.hasDeepLinkToken() {
    // The clipboard contains a potential deep link
    // Request permission from the user to access clipboard

    // After obtaining permission, check the clipboard
    if let clipboardUrl = DeepLinkNow.checkClipboard() {
        // Found a valid deep link in clipboard
        // Parse and handle it
        if let (path, parameters) = DeepLinkNow.parseDeepLink(URL(string: clipboardUrl)!) {
            // Use path and parameters to navigate
            navigateBasedOnPath(path, parameters)
        }
    }
}

Note: On iOS, you need to request permission to access the clipboard. Add the following to your

Info.plist
:

<key>NSPasteboardUsageDescription</key>
<string>We need access to the clipboard to check for deep links</string>

You can create deep links programmatically to share with users:

// Create custom parameters
let customParams = DLNCustomParameters([
    "referrer": "social_share",
    "campaign": "summer_sale",
    "is_promo": "true",
    "discount": "20"
])

// Create the deep link
if let url = DeepLinkNow.createDeepLink(
    path: "/product/123",
    customParameters: customParams
) {
    // Use the generated deep link
    shareDeepLink(url)
}

When receiving deep links (via Universal Links, custom URL schemes, or clipboard), parse them with:

if let parsed = DeepLinkNow.parseDeepLink(url) {
    let path = parsed.path
    let parameters = parsed.parameters

    // Route the user based on path and parameters
    switch path {
    case "/product":
        if let productId = parameters["id"] as? String {
            navigateToProduct(productId)
        }
    case "/category":
        if let categoryId = parameters["id"] as? String {
            navigateToCategory(categoryId)
        }
    default:
        navigateToHome()
    }
}

Integration Examples

SwiftUI Implementation

Here's how to implement deep linking in a SwiftUI app:

struct ContentView: View {
    @State private var isInitialized = false
    @State private var lastReceivedDeepLink: URL? = nil

    var body: some View {
        VStack {
            if let deepLink = lastReceivedDeepLink {
                Text("Last Received Deep Link:")
                    .font(.headline)
                Text(deepLink.absoluteString)
                    .foregroundColor(.blue)
            }

            Button(action: initDln) {
                Text(!isInitialized ? "Initialize SDK" : "Initialized!")
            }
        }
        .onAppear {
            setupDeepLinkObserver()
            checkForDeferredDeepLinks()
        }
    }

    private func setupDeepLinkObserver() {
        NotificationCenter.default.addObserver(
            forName: .init("DeepLinkReceived"),
            object: nil,
            queue: .main
        ) { notification in
            if let url = notification.object as? URL {
                self.lastReceivedDeepLink = url
                handleDeepLink(url)
            }
        }
    }

    private func initDln() {
        Task {
            let config = DLNConfig(apiKey: "your-api-key", enableLogs: true)
            await DeepLinkNow.initialize(config: config)
            isInitialized = true
        }
    }

    private func checkForDeferredDeepLinks() {
        Task {
            if let matchResponse = await DeepLinkNow.findDeferredUser() {
                // Process matches based on confidence scores
                // For this example, just take the highest confidence match
                if let bestMatch = matchResponse.matches.max(by: { $0.confidenceScore < $1.confidenceScore }),
                   let deeplink = bestMatch.deeplink {

                    // Check if confidence score meets your threshold
                    if bestMatch.confidenceScore >= 75 { // High confidence
                        if let url = URL(string: deeplink.targetUrl) {
                            self.lastReceivedDeepLink = url
                            handleDeepLink(url)
                        }
                    }
                }
            } else {
                // Check clipboard as fallback
                if DeepLinkNow.hasDeepLinkToken() {
                    if let clipboardUrl = DeepLinkNow.checkClipboard(),
                       let url = URL(string: clipboardUrl) {
                        self.lastReceivedDeepLink = url
                        handleDeepLink(url)
                    }
                }
            }
        }
    }

    private func handleDeepLink(_ url: URL) {
        if let (path, parameters) = DeepLinkNow.parseDeepLink(url) {
            // Route based on path and parameters
            print("Routing to path: \(path) with parameters: \(parameters)")

            // Implement your navigation logic here
        }
    }
}

UIKit Implementation

For UIKit apps, implement in your AppDelegate:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize the SDK
        Task {
            let config = DLNConfig(apiKey: "your-api-key")
            await DeepLinkNow.initialize(config: config)

            // Check for deferred deep links
            checkForDeferredDeepLinks()
        }

        return true
    }

    // Handle Universal Links
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
           let url = userActivity.webpageURL {
            handleDeepLink(url)
            return true
        }
        return false
    }

    // Handle custom URL schemes
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        handleDeepLink(url)
        return true
    }

    private func checkForDeferredDeepLinks() {
        Task {
            if let matchResponse = await DeepLinkNow.findDeferredUser() {
                // Process matches based on confidence scores
                for match in matchResponse.matches {
                    if match.confidenceScore >= 75, // High confidence threshold
                       let deeplink = match.deeplink,
                       let url = URL(string: deeplink.targetUrl) {
                        DispatchQueue.main.async {
                            self.handleDeepLink(url)
                        }
                        break
                    }
                }
            } else {
                // Check clipboard as fallback
                if DeepLinkNow.hasDeepLinkToken() {
                    if let clipboardUrl = DeepLinkNow.checkClipboard(),
                       let url = URL(string: clipboardUrl) {
                        DispatchQueue.main.async {
                            self.handleDeepLink(url)
                        }
                    }
                }
            }
        }
    }

    private func handleDeepLink(_ url: URL) {
        if let parsed = DeepLinkNow.parseDeepLink(url) {
            // Implement your navigation logic here
            // For example:
            let navigationController = window?.rootViewController as? UINavigationController

            switch parsed.path {
            case "/product":
                if let productId = parsed.parameters["id"] as? String {
                    let productVC = ProductViewController(productId: productId)
                    navigationController?.pushViewController(productVC, animated: true)
                }
            case "/category":
                if let categoryId = parsed.parameters["id"] as? String {
                    let categoryVC = CategoryViewController(categoryId: categoryId)
                    navigationController?.pushViewController(categoryVC, animated: true)
                }
            default:
                // Default handling
                break
            }
        }
    }
}

Advanced Features

Domain Validation

The SDK automatically validates deep links against allowed domains:

  • deeplinknow.com
  • deeplink.now
  • Your app's verified custom domains (configured in your dashboard)

These domains are automatically loaded during SDK initialization. You can check if a domain is valid with:

let isValid = DeepLinkNow.isValidDomain("yourdomain.com")

Rate Limits and Account Status

The SDK includes built-in monitoring for:

  • Matches per second limit
  • Matches per day limit
  • Account status tracking (active/suspended/expired)
  • Remaining credits monitoring

These limits are returned in the initialization response and can be accessed for advanced implementations.

Custom Parameters

The SDK supports rich custom parameters for deep links:

// Creating custom parameters with different value types
var customParams = DLNCustomParameters([
    "referrer": "social_share",
    "campaign": "summer_sale",
    "is_promo": true,      // Boolean values
    "discount": 20,        // Numeric values
    "source_id": "fb_123"  // String values
])

// Create deep link with parameters
let deepLink = DeepLinkNow.createDeepLink(
    path: "/product/123",
    customParameters: customParams
)

When parsing deep links, you can access these parameters in a type-safe way:

if let parsed = DeepLinkNow.parseDeepLink(url) {
    let parameters = parsed.parameters

    // String values
    let referrer = parameters["referrer"] as? String

    // Boolean values (converted to strings in URL)
    let isPromoString = parameters["is_promo"] as? String
    let isPromo = isPromoString == "true"

    // Numeric values (converted to strings in URL)
    let discountString = parameters["discount"] as? String
    let discount = Int(discountString ?? "0") ?? 0
}

Support

  • 📧 Email: support@deeplinknow.com
  • 💬 Discord: Join our community
  • 📚 Documentation: docs.deeplinknow.com

License

DeepLinkNow is available under the MIT license. See the LICENSE file for more info.