← Back to Documentation
Migration Guide

How to Migrate from Branch to DeepTap

Replace the Branch SDK with native iOS Universal Links and Android App Links. Your associated domains and intent filters stay; the SDK and its initialisation code go.

Deciding whether to switch at all? Start with DeepTap vs Branch, which covers the cases where staying on Branch is the right call.

Read this before you start

DeepTap replaces Branch deep linking, not Branch attribution. If you use Branch to attribute paid installs and in-app events to ad campaigns, that functionality has no SDK-free equivalent and this migration will lose it. Migrate only the link layer, or keep an attribution platform alongside.

What Carries Over

Branch routes links through the same operating-system mechanism DeepTap uses: iOS Universal Links and Android App Links. That means most of your native configuration is already correct and does not need to be rebuilt — you are changing which domain the OS associates with your app, not how association works.

Stays as-is

  • • The Associated Domains capability in Xcode
  • • Your continueUserActivity entry point
  • • Android intent-filter structure with autoVerify
  • • Your in-app routing logic that maps a path to a screen
  • • Your destination paths and query parameters

Gets removed or replaced

  • • The Branch SDK dependency (SPM, CocoaPods, Gradle)
  • branch_key and Branch keys in Info.plist / manifest
  • initSession / sessionBuilder calls
  • app.link domains in entitlements and filters
  • • Branch parameter reads ($deeplink_path, +clicked_branch_link)

Migration Steps

1

Create your DeepTap domain

Pick a subdomain such as myapp.deeptap.io. DeepTap generates and serves your association files immediately. Or let your coding agent do it over MCP.

2

Enter your app credentials

Bundle ID and Team ID for iOS, package name and SHA-256 release signing fingerprints for Android. These are the same values Branch holds, so copy them across rather than looking them up again.

3

Add the domain alongside Branch

Add applinks:myapp.deeptap.io to your entitlements and a matching intent filter to your manifest, keeping the Branch entries in place for now. Both can be associated at once, which lets you verify DeepTap works before you remove anything.

4

Verify before removing the SDK

Ship a build with both domains and confirm DeepTap links open the right screens on real devices. Validate your association file first — a wrong content type or a redirect makes Universal Links fail silently.

Run the AASA checker →
5

Remove the Branch SDK

Once DeepTap links are confirmed working in production, drop the dependency, the initialisation code, and the Branch keys. Code for both platforms is below.

iOS Code Changes

Remove: Branch session handling

A typical Branch integration looks roughly like this in your app delegate. All of it goes.

import BranchSDK

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    Branch.getInstance().initSession(launchOptions: launchOptions) { params, error in
        if let path = params?["$deeplink_path"] as? String {
            Router.handle(path: path)
        }
    }
    return true
}

func application(_ application: UIApplication,
                 continue userActivity: NSUserActivity,
                 restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    return Branch.getInstance().continue(userActivity)
}

Replace with: native handling

The OS hands you the URL directly. No initialisation, no callback, no SDK.

func application(_ application: UIApplication,
                 continue userActivity: NSUserActivity,
                 restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
          let url = userActivity.webpageURL else { return false }

    Router.handle(path: url.path, query: URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems)
    return true
}

Also clean up

  • • Remove the BranchSDK package or pod
  • • Remove branch_key and branch_universal_link_domains from Info.plist
  • • Remove applinks:*.app.link entries from Associated Domains once old links are retired

Full setup details are in the iOS Universal Links guide.

Android Code Changes

Remove: Branch initialisation

// Application class
Branch.getAutoInstance(this)

// Activity
override fun onStart() {
    super.onStart()
    Branch.sessionBuilder(this)
        .withCallback { referringParams, error ->
            referringParams?.optString("\$deeplink_path")?.let { Router.handle(it) }
        }
        .withData(intent?.data)
        .init()
}

Replace with: native intent handling

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    intent?.data?.let { Router.handle(it) }
}

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    intent.data?.let { Router.handle(it) }
}

Manifest

Swap the Branch host for your DeepTap domain and drop the Branch key meta-data.

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="myapp.deeptap.io" />
</intent-filter>

Full setup details are in the Android App Links guide.

Deferred Deep Links Without the SDK

This is the one piece of Branch functionality that needs replacement code rather than deletion. Branch resolved deferred links inside initSession. With DeepTap you make one HTTPS request on first launch instead.

GET https://deeptap.io/api/deferred-link?subdomain=myapp.deeptap.io&platform=ios

{
  "success": true,
  "data": {
    "path": "/product/123",
    "queryParams": { "ref": "campaign" },
    "referrer": "https://twitter.com",
    "createdAt": "2026-08-25T10:30:00Z"
  }
}

Call it once, on first launch only, and route on data.path. Matching uses a server-side fingerprint of the client IP and platform within a short window after the click, so it is most reliable when the click and the install happen on the same network, and can miss behind CGNAT, a VPN, or iCloud Private Relay. When it misses, your app still opens — just on the default screen. Design the fallback accordingly rather than assuming a hit.

Ready-to-paste Swift and Kotlin implementations are in the iOS and Android guides.

Cutover and Decommissioning Branch

  1. Point all newly generated links at your DeepTap domain, and stop creating Branch links.
  2. Leave both domains associated in the shipped app so old and new links both resolve.
  3. Watch your DeepTap analytics for routing outcomes — whether each click opened the app or fell through to the store — and watch Branch for residual traffic.
  4. Keep the Branch account until that residual traffic is negligible. Links printed on packaging, sitting in old emails, or baked into app versions users have not updated will outlive your migration plan.
  5. Remove the Branch domains from entitlements and manifest in a later release, then cancel.

Cancelling Branch before old links stop receiving traffic is the one irreversible mistake in this migration — those URLs cannot be reclaimed afterwards.

Ready to migrate?

Create a domain, add it alongside Branch, and verify before you remove anything.