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.
On This Page
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
continueUserActivityentry point - • Android
intent-filterstructure 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_keyand Branch keys in Info.plist / manifest - •
initSession/sessionBuildercalls - •
app.linkdomains in entitlements and filters - • Branch parameter reads (
$deeplink_path,+clicked_branch_link)
Migration Steps
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.
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.
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.
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 →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
BranchSDKpackage or pod - • Remove
branch_keyandbranch_universal_link_domainsfrom Info.plist - • Remove
applinks:*.app.linkentries 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
- Point all newly generated links at your DeepTap domain, and stop creating Branch links.
- Leave both domains associated in the shipped app so old and new links both resolve.
- 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.
- 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.
- 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.