
Table of Contents
ToggleBranch deep links setup is essential for any mobile app that wants to send users to the exact right screen – whether they’re coming from an ad, email, SMS, or social post.If you want users to land on the exact right screen inside your app — whether they’re coming from an ad, email, SMS, or social post — you need deep linking. And Branch is the most powerful deep linking platform available for mobile apps.
But setting up Branch correctly requires configuring multiple systems across iOS, Android, your dashboard, and your marketing tools. One wrong setting and your deep links silently fail.
This complete Branch deep link setup guide walks you through everything — from account creation to universal links, app links, deferred deep linking, and attribution tracking.
In this guide:
Branch is a mobile deep linking and attribution platform. It connects users to the exact right content inside your app — regardless of where they came from or whether they have the app installed.
What Branch does:
Why use Branch:
Branch vs AppsFlyer OneLink:
| Feature | Branch | AppsFlyer OneLink |
|---|---|---|
| Deep linking | Best-in-class | Strong |
| Attribution | Good | Industry-leading |
| Smart Banners | ✅ Built-in | ✅ Available |
| Web-to-app | Excellent | Strong |
| Fraud protection | Basic | Protect360 |
| Pricing | Freemium | Premium |
| Setup complexity | Medium | Medium |
When to use Branch:
When to use AppsFlyer OneLink instead:
Add your app:
Branch uses a custom link domain for your deep links. You can use Branch’s default domain or a custom domain.
Default domain: yourapp.app.link
Custom domain (recommended):
links.yourapp.com)A custom domain looks more professional and improves click-through rates.
Universal Links allow Branch deep links to open your app directly — without going through Safari first.
applinks:yourapp.app.link
applinks:yourapp-alternate.app.linkIf using a custom domain:
applinks:links.yourapp.comInfo.plist:<key>branch_key</key>
<string>key_live_YOUR_BRANCH_KEY</string>
<key>branch_universal_link_domains</key>
<array>
<string>yourapp.app.link</string>
<string>yourapp-alternate.app.link</string>
</array>CocoaPods:
pod 'Branch'Swift Package Manager:
https://github.com/BranchMetrics/ios-branch-sdk-spmimport Branch
@main
struct MyApp: App {
init() {
Branch.getInstance().initSession(launchOptions: nil) { params, error in
if let params = params as? [String: Any] {
// Handle deep link data
if let screenName = params["screen"] as? String {
// Navigate to the correct screen
print("Deep link to: \(screenName)")
}
}
}
}
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
Branch.getInstance().handleDeepLink(url)
}
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in
Branch.getInstance().continue(activity)
}
}
}
}App Links allow Branch deep links to open your Android app directly.
App-level build.gradle:
dependencies {
implementation 'io.branch.sdk.android:library:5.+'
}AndroidManifest.xml:<application>
<meta-data
android:name="io.branch.sdk.BranchKey"
android:value="key_live_YOUR_BRANCH_KEY" />
<activity android:name=".MainActivity">
<!-- App Links intent filter -->
<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="yourapp.app.link" />
</intent-filter>
<!-- URI scheme fallback -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="yourapp"
android:host="open" />
</intent-filter>
</activity>
</application>import io.branch.referral.Branch
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Branch.getAutoInstance(this)
}
}
class MainActivity : AppCompatActivity() {
override fun onStart() {
super.onStart()
Branch.sessionBuilder(this)
.withCallback { referringParams, error ->
if (error == null && referringParams != null) {
// Handle deep link data
val screenName = referringParams.getString("screen")
if (screenName != null) {
// Navigate to the correct screen
}
}
}
.withData(intent.data)
.init()
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
Branch.sessionBuilder(this).reInit()
}
}For App Links to work on Android, you need to host a assetlinks.json file on your domain.
File location: https://yourapp.com/.well-known/assetlinks.json
File content:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.yourcompany.appname",
"sha256_cert_fingerprints": [
"YOUR_SHA256_FINGERPRINT"
]
}
}]Get your SHA256 fingerprint:
keytool -list -v -keystore your-release-key.jks -alias your-key-aliasBranch also provides its own assetlinks.json hosting — you can add your app’s fingerprint in the Branch dashboard under Link Settings.
Basic settings:
Deep link data: Add key-value pairs that your app will read:
screen: product_detail
product_id: 12345
campaign: summer_saleOG tags (for social sharing):
Your link will look like: https://yourapp.app.link/summer-campaign
Deferred deep linking is Branch’s most powerful feature. When a user clicks a Branch link but doesn’t have the app installed:
This works automatically with Branch SDK initialized correctly. The key is reading the params in your session callback:
// iOS — read deferred deep link data
Branch.getInstance().initSession(launchOptions: nil) { params, error in
guard let params = params as? [String: Any], error == nil else { return }
// These params come from the original link — even after fresh install
let screen = params["screen"] as? String
let productId = params["product_id"] as? String
let campaign = params["campaign"] as? String
// Navigate based on deep link data
if let screen = screen {
NavigationManager.navigate(to: screen, productId: productId)
}
}// Android — read deferred deep link data
Branch.sessionBuilder(this)
.withCallback { referringParams, error ->
if (error == null && referringParams != null) {
val screen = referringParams.optString("screen")
val productId = referringParams.optString("product_id")
// Navigate based on deep link data
if (screen.isNotEmpty()) {
NavigationManager.navigate(screen, productId)
}
}
}
.withData(intent?.data)
.init()Branch Smart Banners show a banner on your mobile website that encourages users to open the app or install it.
<script>
(function(b,r,a,n,c,h,_,s,d,k){
if(!b[n]||!b[n]._q){
for(;s<_.length;)c(h,_[s++]);
d=r.createElement(a);
d.async=1;
d.src="https://cdn.branch.io/branch-latest.min.js";
k=r.getElementsByTagName(a)[0];
k.parentNode.insertBefore(d,k);
b[n]=h
}
})(window,document,"script","branch",function(b,r){
b[r]=function(){b._q.push([r,arguments])}
},{"_q":[],"_v":1},"addListener applyCode autoAppIndex banner closeBanner closeJourney creditHistory credits data deepview deepviewCta first getCode init link logout redeem referrals removeListener sendSMS setBranchViewData setIdentity track validateCode trackCommerceEvent logEvent disableTracking".split(" "), 0);
branch.init('YOUR_BRANCH_KEY');
</script>Branch tracks attribution automatically for all links created in the dashboard.
View attribution data:
Track custom events:
// iOS
BranchEvent.customEvent(withName: "purchase")
.addCustomProperty("revenue", value: "29.99")
.addCustomProperty("currency", value: "USD")
.logEvent()// Android
BranchEvent("purchase")
.addCustomProperty("revenue", "29.99")
.addCustomProperty("currency", "USD")
.logEvent(context)Connect Branch with your MMP:
If you’re using AppsFlyer or Adjust alongside Branch, you can pass attribution data between them:
// Pass AppsFlyer attribution to Branch
let branchEvent = BranchEvent.customEvent(withName: "install")
branchEvent.addCustomProperty("af_channel", value: appsFlyer_channel)
branchEvent.logEvent()Branch requires both the primary and alternate domains in Associated Domains:
applinks:yourapp.app.link
applinks:yourapp-alternate.app.linkMissing the alternate domain breaks Universal Links on iOS.
assetlinks.json FingerprintUsing a debug keystore fingerprint in production breaks Android App Links. Always use your release keystore fingerprint.
onNewIntentOn Android, if your app is already running when a deep link is clicked, the link data comes through onNewIntent — not onCreate. Always implement both.
Most teams only test direct deep links. Always test the deferred scenario — uninstall the app, click a Branch link, install the app, and verify the correct screen opens.
Universal Links and App Links can fail in some scenarios (email clients, certain browsers). Always include a URI scheme as fallback:
yourapp://open?screen=product&id=12345Test Universal Links (iOS):
Test App Links (Android):
adb shell am start -W -a android.intent.action.VIEW -d "https://yourapp.app.link/test-link" com.yourpackage.nameValidation Checklist:
What is deferred deep linking? Deferred deep linking sends users to the correct screen inside an app even if they don’t have the app installed. The user clicks a link, gets redirected to the app store, installs the app, and on first launch the app reads the original link data and navigates to the correct screen.
Do I need Branch if I already use AppsFlyer? Not necessarily. AppsFlyer OneLink provides deep linking alongside attribution. Branch is a better choice if deep linking is your primary need and you want more advanced web-to-app journey features. If you’re already set up with AppsFlyer, OneLink may be sufficient.
Is Branch free? Branch offers a free tier with core deep linking features. Paid plans unlock advanced analytics, custom domains, and higher link volumes. For most early-stage apps, the free tier is sufficient.
How do Branch links work without the app installed? Branch detects whether the app is installed. If not, it redirects to the App Store or Google Play. After install, Branch retrieves the original link parameters on first launch — this is deferred deep linking.
Can Branch track attribution like AppsFlyer or Adjust? Branch has built-in attribution, but it’s not as comprehensive as dedicated MMPs like AppsFlyer or Adjust. Branch is best used for deep linking with basic attribution. For advanced attribution, use Branch alongside AppsFlyer or Adjust.
What is the difference between Universal Links and deep links? A deep link is any link that opens a specific screen inside an app. Universal Links is Apple’s implementation that allows HTTPS links to open apps directly — without going through Safari. Branch uses Universal Links on iOS and App Links on Android for the best user experience.
How do I test Branch deep links? Use Branch’s Live View in the dashboard to see real-time link activity, use the Deep Link Tester tool in the Branch dashboard, or manually test by clicking links on a physical device.
For full setup details, visit the official Branch documentation.