ESC
Type to search guides, tutorials, and reference documentation.
Verified by Garnet Grid

Mobile App Deep Linking

Implement deep linking that navigates users to specific content within your mobile app. Covers URI schemes, Universal Links, App Links, deferred deep links, attribution, and the patterns that create seamless navigation between web and native app.

Deep linking takes users directly to specific content inside your app instead of the home screen. A link like myapp://orders/123 or https://myapp.com/orders/123 opens the order detail screen, not the login page. Done well, deep links create seamless transitions between web, email, push notifications, and the app itself.


URI Scheme (Custom):
  myapp://orders/123
  - Works only if app is installed
  - Cannot verify ownership
  - Falls back to nothing (error in browser)
  - ⚠ Deprecated for most use cases

Universal Links (iOS):
  https://myapp.com/orders/123
  - Opens app if installed, website if not
  - Verified ownership (apple-app-site-association)
  - Seamless web-to-app transition

App Links (Android):
  https://myapp.com/orders/123
  - Opens app if installed, website if not
  - Verified ownership (assetlinks.json)
  - Same URL works on both platforms

Deferred Deep Links:
  User clicks link → App not installed → App Store → Install → 
  App opens to SPECIFIC content from original link
  - Requires deep link service (Branch, Firebase Dynamic Links)

// apple-app-site-association (AASA)
// Hosted at: https://myapp.com/.well-known/apple-app-site-association
{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "TEAM_ID.com.company.myapp",
                "paths": [
                    "/orders/*",
                    "/products/*",
                    "/profile/*",
                    "NOT /api/*",
                    "NOT /static/*"
                ]
            }
        ]
    }
}
// Handle Universal Links in iOS
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
              let url = userActivity.webpageURL else { return }
        
        handleDeepLink(url)
    }
    
    func handleDeepLink(_ url: URL) {
        let pathComponents = url.pathComponents
        
        switch pathComponents.first {
        case "orders":
            if let orderId = pathComponents.last {
                navigator.navigate(to: .orderDetail(id: orderId))
            }
        case "products":
            if let productId = pathComponents.last {
                navigator.navigate(to: .productDetail(id: productId))
            }
        default:
            navigator.navigate(to: .home)
        }
    }
}

// assetlinks.json
// Hosted at: https://myapp.com/.well-known/assetlinks.json
[{
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
        "namespace": "android_app",
        "package_name": "com.company.myapp",
        "sha256_cert_fingerprints": [
            "AB:CD:EF:12:34:56:..."
        ]
    }
}]
// Handle App Links in Android
class DeepLinkActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        intent?.data?.let { uri ->
            handleDeepLink(uri)
        }
    }
    
    private fun handleDeepLink(uri: Uri) {
        when {
            uri.path?.startsWith("/orders/") == true -> {
                val orderId = uri.lastPathSegment
                navigator.navigateTo(OrderDetailScreen(orderId))
            }
            uri.path?.startsWith("/products/") == true -> {
                val productId = uri.lastPathSegment
                navigator.navigateTo(ProductDetailScreen(productId))
            }
            else -> navigator.navigateTo(HomeScreen)
        }
    }
}

Anti-Patterns

Anti-PatternConsequenceFix
Only URI schemesNo fallback if app not installedUniversal Links / App Links
No deferred deep linksPost-install loses original intentBranch, Firebase Dynamic Links
Auth wall on deep linkUser logs in, loses contextQueue deep link, resume after auth
No deep link validationBroken links in productionAutomated deep link testing
Different URLs per platformFragmented link managementSingle URL, platform-handled routing

Deep linking is the connective tissue between every channel that reaches your users — web, email, push, ads, social, and QR codes. Every entry point should land the user exactly where they intended to go.

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →