Skip to content

React Native

Integrate Branch

Inconsistent Universal links behavior on iOS 11.2

After updating a device to iOS 11.2, we found that the app's AASA file is no longer downloaded reliably onto your user’s device after an app install. As a result, clicking on Universal links will no longer open the app consistenly. You can set forced uri redirect mode on your Branch links to open the app with URI schemes. View details of the issue on the Apple Bug report.

Google Play Services version 17+

If you reference Google Play Services version 17 or higher, you MUST complete Google's update instructions here.

Due to a major Google Play Services change made in June 2019, not completing the update steps will cause Branch's Android SDK (and various other cross-platform SDKs, e.g. Unity) to stop collecting Android AID which we use to ensure accurate deep linking and attribution.

If you are running Google Play Services versions below 17, no update is necessary.

  • Configure Branch

  • Install Branch

    • Option 1: Pure React Native App

      • Install the module

        • Yarn

          yarn add react-native-branch

        • NPM

          npm install --save react-native-branch

      • (Optional) Add a branch.json file to the root of your app (next to package.json). You can configure the contents at any time, but it must be present when you run react-native link in order to be automatically included in your native projects. This allows you to configure certain behaviors that otherwise require native code changes. See for full details on the branch.json file.

      • Run react-native link react-native-branch

    • Option 2: Native iOS app with CocoaPods

      • Add these lines to your Podfile

        pod 'react-native-branch', path: '../node_modules/react-native-branch'
        pod 'Branch-SDK', path: '../node_modules/react-native-branch/ios'
      • Run pod install to regenerate the Pods project with the new dependencies. Note that the location of node_modules relative to your Podfile may vary.

      • (Optional) Add a branch.json file to the root of your app (next to package.json). See

Updating from an earlier version or starting with v3.0.0

To fix a longstanding build issue with Android, it is necessary to take the native Branch Android SDK from Maven rather than from the react-native-branch module, starting with version 3.0.0.

Open the android/app/build.gradle file in your project.

Remove this line:

implementation fileTree(dir: 'libs', include: ['*.jar'])

Add this line:

implementation ""

The result should be something like

dependencies {
    implementation project(':react-native-branch')
    implementation ""
    implementation ""
    implementation "com.facebook.react:react-native:+"  // From node_modules

If you're using an older version of Gradle, you may need compile instead of implementation.

It is recommended to replace Branch.getAutoInstance in your Application.onCreate method with RNBranchModule.getAutoInstance. This is required in order to set Branch keys in the branch.json file.

public void onCreate() {
  SoLoader.init(this, /* native exopackage */ false);
  // Replace Branch.getAutoInstance(this); with:
  • Update from < 2.0.0

    • If also upgrading React Native, use react-native-git-upgrade to upgrade your React Native app to the latest version of React Native, if possible.

      npm install -g react-native-git-upgrade
      cd /path/to/myapp
    • Version 2.x includes the native SDKs in the NPM module. Please remove any installation of the native Branch SDK from Maven, CocoaPods, Carthage or by manually adding the framework (iOS).

    • Android:

      • In android/app/build.gradle:

      • Remove

      compile ''
    • iOS

      • Remove the Branch SDK depending on how you originally installed it.

      • Originally installed using CocoaPods:

        • Remove pod "Branch" from your Podfile.

        • If using the React pod from node_modules, add pod "Branch-SDK", path: "../node_modules/react-native-branch/ios". (Note the different pod name.)

          pod "react-native-branch", path: "../node_modules/react-native-branch"
          pod "Branch-SDK", path: "../node_modules/react-native-branch/ios"
        • pod install

        • To remove CocoaPods entirely from your project, in case you were only using it for Branch:

          pod deintegrate
      • Originally installed using Carthage:

        • Remove the Branch.framework from your project's dependencies.

        • Remove Branch.framework from the input and output paths of your carthage copy-frameworks build phase.

      • Originally installed manually:

        • Remove the Branch.framework from your project's dependencies.
      • If also updating from react-native < 0.40 (react-native-branch 0.9), replace #import "RNBranch.h" with:

        #import <React/RCTRootView.h>
        #import <react-native-branch/RNBranch.h>
  • Configure app

    • iOS

      • Configure bundle identifier

      • Configure associated domains

        • Add your link domains from your Branch Dashboard
        • -alternate is needed for Universal Linking with the Web SDK inside your Website
        • test- is needed if you need use a test key
        • If you use a custom link domain, you will need to include your old link domain, your -alternate link domain, and your new link domain


      • Configure entitlements

        • Confirm entitlements are within target


      • Configure Info.plist

        • Add Branch Dashboard values

          • Add branch_app_domain with your live key domain
          • Add branch_key with your current Branch key
          • Add your URI scheme as URL Types -> Item 0 -> URL Schemes


      • Confirm app prefix

    • Android

      • AndroidManifest.xml

        <?xml version="1.0" encoding="utf-8"?>
        <manifest xmlns:android=""
            <uses-permission android:name="android.permission.INTERNET" />
                        <action android:name="android.intent.action.MAIN" />
                        <category android:name="android.intent.category.LAUNCHER" />
                    <!-- Branch URI Scheme -->
                        <data android:scheme="branchandroid" />
                        <action android:name="android.intent.action.VIEW" />
                        <category android:name="android.intent.category.DEFAULT" />
                        <category android:name="android.intent.category.BROWSABLE" />
                    <!-- Branch App Links (optional) -->
                    <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="" />
                <!-- Branch init -->
                <meta-data android:name="io.branch.sdk.BranchKey" android:value="key_live_gdzsepIaUf7wG3dEWb3aBkmcutm0PwJa" />
                <meta-data android:name="io.branch.sdk.BranchKey.test" android:value="key_test_edwDakKcMeWzJ3hC3aZs9kniyuaWGCTa" />
                <meta-data android:name="io.branch.sdk.TestMode" android:value="false" />
                <!-- Branch install referrer tracking (optional) -->
                <receiver android:name="io.branch.referral.InstallListener" android:exported="true">
                        <action android:name="" />
      • Replace the following with values from your Branch Dashboard

        • branchandroid
        • key_live_gdzsepIaUf7wG3dEWb3aBkmcutm0PwJa
        • key_test_edwDakKcMeWzJ3hC3aZs9kniyuaWGCTa
    • android/app/

      -dontwarn io.branch.**

  • Initialize Branch

    • iOS

      If you are using Swift, add #import <react-native-branch/RNBranch.h> to your Bridging header if you have one.

      If you are using the React pod in a native app with use_frameworks!, you may simply use a Swift import in the AppDelegate.swift: import react_native_branch.

      • Swift 3 & 4- AppDelegate.swift

        // Initialize the Branch Session at the top of existing application:didFinishLaunchingWithOptions:
        func application(_ application: UIApplication, didFinishLaunchingWithOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
          // Uncomment this line to use the test key instead of the live one.
          // RNBranch.useTestInstance()
          RNBranch.initSession(launchOptions: launchOptions, isReferrable: true) // <-- add this
        // Add the openURL and continueUserActivity functions
        func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
          return RNBranch.branch.application(app, open: url, options: options)
        func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
          return RNBranch.continue(userActivity)
      • Objective-C - AppDelegate.m

        #import <react-native-branch/RNBranch.h> // at the top
        // Initialize the Branch Session at the top of existing application:didFinishLaunchingWithOptions:
        - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
            // Uncomment this line to use the test key instead of the live one.
            // [RNBranch useTestInstance];
            [RNBranch initSessionWithLaunchOptions:launchOptions isReferrable:YES]; // <-- add this
            NSURL *jsCodeLocation;
        - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
            if (![RNBranch.branch application:app openURL:url options:options]) {
                // do other deep link routing for the Facebook SDK, Pinterest SDK, etc
            return YES;
        - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
            return [RNBranch continueUserActivity:userActivity];
    • Android


        // ...
        // import Branch and RNBranch
        import io.branch.rnbranch.RNBranchPackage;
        import io.branch.referral.Branch;
        // add RNBranchPackage to react-native package list
          protected List<ReactPackage> getPackages() {
            return Arrays.<ReactPackage>asList(
                    new MainReactPackage(),
                    new RNBranchPackage(), // <-- add this
        // ...
        // add onCreate() override
        public void onCreate() {

        import io.branch.rnbranch.*; // <-- add this
        import android.content.Intent; // <-- and this
        public class MainActivity extends ReactActivity {
              protected String getMainComponentName() {
                  return "base";
              // Override onStart, onNewIntent:
              protected void onStart() {
                  RNBranchModule.initSession(getIntent().getData(), this);
              public void onNewIntent(Intent intent) {
              // ...
    • Create a deep link from the Branch Marketing Dashboard

    • Delete your app from the device

    • Compile your app with Xcode

    • Paste deep link in Apple Notes

    • Long press on the deep link (not 3D Touch)

    • Click Open in "APP_NAME" to open your app (example)

    • Create a deep link from the Branch Marketing Dashboard

    • Delete your app from the device

    • Compile your app with Android Studio

    • Paste deep link in Google Hangouts

    • Click on the deep link to open your app

Implement features

  • Import Branch

    • In any React Native source file that uses the Branch SDK.

      import branch, { BranchEvent } from 'react-native-branch'
  • Create content reference

    // only canonicalIdentifier is required
    let branchUniversalObject = await branch.createBranchUniversalObject('canonicalIdentifier', {
      locallyIndex: true,
      title: 'Cool Content!',
      contentDescription: 'Cool Content Description',
      contentMetadata: {
        ratingAverage: 4.2,
        customMetadata: {
          prop1: 'test',
          prop2: 'abc'
  • let linkProperties = {
        feature: 'share',
        channel: 'facebook'
    let controlParams = {
         $desktop_url: ''
    let {url} = await branchUniversalObject.generateShortUrl(linkProperties, controlParams)
  • let shareOptions = { messageHeader: 'Check this out', messageBody: 'No really, check this out!' }
    let linkProperties = { feature: 'share', channel: 'RNApp' }
    let controlParams = { $desktop_url: '', $ios_url: '' }
    let {channel, completed, error} = await branchUniversalObject.showShareSheet(shareOptions, linkProperties, controlParams)
    • Retrieve Branch data from a deep link

    • Best practice to receive data from the listener (to prevent a race condition)

    • Returns deep link properties

    • Listener

    branch.subscribe(({ error, params }) => {
      if (error) {
        console.error('Error from Branch: ' + error)
      // params will never be null if error is null
    let lastParams = await branch.getLatestReferringParams() // params from last open
    let installParams = await branch.getFirstReferringParams() // params from original install
  • branch.subscribe(({ error, params }) => {
      if (error) {
        console.error('Error from Branch: ' + error)
      // params will never be null if error is null
      if (params['+non_branch_link']) {
        const nonBranchUrl = params['+non_branch_link']
        // Route non-Branch URL if appropriate.
      if (!params['+clicked_branch_link']) {
        // Indicates initialization success and some other conditions.
        // No link was opened.
      // A Branch link was opened.
      // Route link based on data in params, e.g.
      // Get title and url for route
      const title = params.$og_title
      const url = params.$canonical_url
      const image = params.$og_image_url
      // Now push the view for this URL
      this.navigator.push({ title: title, url: url, image: image })
    • Any link that launched the app is cached by the native layers and returned to the branch.subscribe listener after JavaScript finishes loading.

    • By default, the initial link is cached for 5 seconds. This allows you to unsubscribe and resubscribe later without receiving the initial link.

    • If your app takes longer than this to load, you can adjust the TTL for the initial link by adjusting branch.initSessionTtl to a value in milliseconds.

    branch.initSessionTtl = 10000 // Set to 10 seconds
    branch.subscribe({ error, params } => {
      // ...
  • Display content

    • List content on iOS Spotlight

    • Needs a Branch Universal Object

    • Listing on Spotlight requires adding CoreSpotlight.framework to your Xcode project.

    import branch, { BranchEvent } from 'react-native-branch'
    let branchUniversalObject = await branch.createBranchUniversalObject('canonicalIdentifier', {
      locallyIndex: true,
      // other properties
  • Track content

    import { BranchEvent } from 'react-native-branch'
  • Track users

    • Sets the identity of a user (email, ID, UUID, etc) for events, deep links, and referrals

    • Validate with the Branch Dashboard

  • Track events

    • Track standard and custom events

    • Events named open, close, install, and referred session are Branch restricted

    • 63 max event name length

    • Best to Track users before Track events to associate a custom event to a user

    • Validate with the Branch Dashboard

    import { BranchEvent } from 'react-native-branch'
    // Associate one or more content items with an event
    new BranchEvent(BranchEvent.ViewItems, [buo1, buo2]).logEvent()
    // Log a standard event with parameters
    new BranchEvent(BranchEvent.Purchase, buo, {
      revenue: 20,
      shipping: 2,
      tax: 1.6,
      currency: 'USD'
    // Set parameters after initialization
    let event = new BranchEvent(BranchEvent.Search)
    event.searchQuery = "tennis rackets"
    // Log a custom event
    new BranchEvent("UserScannedItem", buo).logEvent()
    • When logging an event with a single Branch Universal Object, use the convenient logEvent method
    buo.logEvent(BranchEvent.Purchase, { revenue: 20 })
  • Standard events

Event constant Description
BranchEvent.AddToCart Standard Add to Cart event
BranchEvent.AddToWishlist Standard Add to Wishlist event
BranchEvent.ViewCart Standard View Cart event
BranchEvent.InitiatePurchase Standard Initiate Purchase event
BranchEvent.AddPaymentInfo Standard Add Payment Info event
BranchEvent.Purchase Standard Purchase event
BranchEvent.SpendCredits Standard Spend Credits event
BranchEvent.Search Standard Search event
BranchEvent.ViewItem Standard View Item event for a single Branch Universal Object
BranchEvent.ViewItems Standard View Items event for multiple Branch Universal Objects
BranchEvent.Rate Standard Rate event
BranchEvent.Share Standard Share event
BranchEvent.CompleteRegistration Standard Complete Registration event
BranchEvent.CompleteTutorial Standard Complete Tutorial event
BranchEvent.AchieveLevel Standard Achieve Level event
BranchEvent.AchievementUnlocked Standard Unlock Achievement event
  • Handle referrals

    • Referral points are obtained from referral rules on the Branch Dashboard

    • Validate on the Branch Dashboard

    • Reward credits

    • Redeem rewards

      let redeemResult = await branch.redeemRewards(amount, bucket)
    • Load rewards

      let rewards = await branch.loadRewards()
    • Load history

      let creditHistory = await branch.getCreditHistory()
    • Allows you to deep link into your own from your app itself

      branch.openURL("", {newActivity: true}) // Finish the Android current activity before opening the link. Results in a new activity window. Ignored on iOS.


If you aren't using the newActivity option, it is necessary to move the call to the RNBranch.initSession method to the main activity's onResume method instead of onStart.


Handling a new deep link in your app will clear the current session data and a new referred "open" will be attributed.

  • Handle push notifications

    • Allows you to track Branch deep links in your push notifications

    • Use openURL to handle the deep links

  • Track Apple Search Ads

    • Allows Branch to track Apple Search Ads deep linking analytics

    • Analytics from Apple's API have been slow which will make our analytics lower. Additionally, Apple's API does not send us all the data of an ad every time which will make ads tracked by us to show a generic campaign sometimes.

    • This requires an option to be set before the native SDK initializes, which happens before JS finishes loading. There are two options:

      1. Add "delayInitToCheckForSearchAds": true to your branch.json file:

            "delayInitToCheckForSearchAds": true
      2. Modify your AppDelegate in Xcode. Insert the following before the call to [RNBranch initSessionWithLaunchOptions:isReferrable:].

        • Swift 3 & 4

        • Objective-C

          [[Branch getInstance] delayInitToCheckForSearchAds];
    • Test with fake campaign params (do not test in production)

      1. Add "appleSearchAdsDebugMode": true to branch.debug.json. Do not set this parameter in branch.json, or it will be enabled in release builds.

            "delayInitToCheckForSearchAds": true,
            "appleSearchAdsDebugMode": true
      2. Add the following call to your AppDelegate (before the initSession) call. Use conditional compilation or remove before releasing to production.

        • Swift 3 & 4

          #if DEBUG
        • Objective-C

          #ifdef DEBUG
              [[Branch getInstance] setAppleSearchAdsDebugMode];
  • Enable 100% matching

    • Android

      • Uses Chrome Tabs to increase attribute matching success

      • Add compile '' to your build.gradle

    • iOS

      • Use the SFSafariViewController to increase the attribution matching success

      • The 100% match is a bit of a misnomer, as it is only 100% match from when a user clicks from the Safari browser. According to our analysis, clicking through Safari happens about 50-75% of the time depending on the use case. For example, clicking from Facebook, Gmail or Chrome won’t trigger a 100% match here. However, it’s still beneficial to the matching accuracy, so we recommend employing it.

      • When using a custom domain, add a branch_app_domain string key in your Info.plist with your custom domain to enable 100% matching.

      • By default, cookie-based matching is enabled on iOS 9 and 10 if the SafariServices.framework is included in an app's dependencies, and the app uses an subdomain or sets the branch_app_domain in the Info.plist. It can be disabled with a call to the SDK.

      • Add before initSession Initialize Branch

      • Swift 3 & 4

      • Objective C

        [[Branch getInstance] disableCookieBasedMatching];
  • Append metadata to Branch network call

    • Functions to append additional metadata, for use cases like inserting user ID's to enable third-party Data Integrations

      • Swift 3 & 4

        RNBranch.setRequestMetadataKey("insert_user_id", "value")
      • Android

        RNBranchModule.setRequestMetadata("userID", "value");

Troubleshoot issues

  • Use test key

    • Use the Branch test key instead of the live key.

    • In iOS, add before initSession Initialize Branch.

    • In iOS, update branch_key in your Info.plist to a dictionary (example).

    • In Android, set test mode to true.

    • The test key of your app must match the test key of your deep link.

    • Use conditional compilation or remove before releasing to production.

      • Swift 3 & 4

        #if DEBUG
      • Objective-C

        #ifdef DEBUG
            [RNBranch useTestInstance];
    • Android: Use this in a build type or product flavor or be sure to remove before releasing to production.

      <meta-data android:name="io.branch.sdk.TestMode" android:value="true" />

  • Simulate an install

    Do not test in production.

    This requires a native method call that must be made before JS has loaded. There are two options.

    1. Use a branch.json file with your project. See for full details. Add "debugMode": true to branch.debug.json:

          "appleSearchAdsDebugMode": true,
          "debugMode": true,
          "delayInitToCheckForSearchAds": true

      Do not add this setting to branch.json, or it will be enabled for release builds.

    2. Modify your native app code.


      Simulated installs may be enabled on Android by adding <meta-data android:name="io.branch.sdk.TestMode" android:value="true"/> to the application element of your Android manifest. Use this in a build type such as debug or a product flavor, or be sure to remove it from your manifest before releasing to prod. Click here for more details.

      Alternately, add RNBranchModule.setDebug(); in your MainActivity before the call to initSession. Be sure to remove it before releasing to prod.

          // Remove before prod release
          RNBranchModule.initSession(getIntent().getData(), this);


      Add [RNBranch setDebug]; or RNBranch.setDebug() in your AppDelegate before the call to initSession. Use conditional compilation or remove before releasing to prod.

      • Swift 3 & 4

        #if DEBUG
        RNBranch.initSession(launchOptions: launchOptions, isReferrable: true)
      • Objective-C

        #ifdef DEBUG
            [RNBranch setDebug];
        [RNBranch initSessionWithLaunchOptions:launchOptions isReferrable:YES];
  • The getLatestReferringParams method is essentially a synchronous method that retrieves the latest referring link parameters stored by the native SDK. However, React Native does not support synchronous calls to native code from JavaScript, so the method returns a promise. You must await the response or use then to receive the result. The same remarks apply to the getFirstReferringParams method. However, this is only a restriction of React Native. The purpose of getLatestReferringParams is to retrieve those parameters one time. The promise will only return one result. It will not continue to return results when links are opened or wait for a link to be opened. This method is not intended to notify the app when a link has been opened.

    To receive notification whenever a link is opened, including at app launch, call branch.subscribe. The callback to this method will return any initial link that launched the app and all subsequent link opens. There is no need to call getLatestReferringParams at app launch to check for an initial link. Use branch.subscribe to handle all link opens.

  • Common build problems

    • Be sure to follow the instructions to Update from < 2.0.0 if your app used an earlier version of react-native-branch. In version 2.x, the native SDKs are embedded in the NPM module and must not also be added from elsewhere (Gradle, CocoaPods, etc.).

    • Note that when using the React pod in a native app, the name of the native SDK pod is Branch-SDK, not Branch, and it comes from node_modules, not the CocoaPods repo.

    • Starting with React Native 0.40, all external iOS headers in Objective-C must be imported as #import <PackageName/Header.h>. This applies to React Native headers as well as the <react-native-branch/RNBranch.h> header from this SDK.

    • If you upgraded from RN < 0.40 manually, without adjusting your Xcode project settings, you may still be importing headers with double quotes. This probably indicates a problem with your settings.

    • The react-native-git-upgrade tool from NPM may be used to update dependencies as well as project settings.

    • On Android, when using Proguard in release builds, depending on your build settings, it may be necessary to add one or both of these lines to your android/app/ file:

  • General troubleshooting

    See the troubleshooting guide for each native SDK:

  • Sample apps