> For the complete documentation index, see [llms.txt](https://help.branch.io/llms.txt).

# Upgrade to the Branch Android SDK 6.0 (Beta)

> Upgrade your app from the Branch Android SDK 5.x to the 6.0 beta, with a ready-made prompt for AI coding assistants and a BranchConfiguration reference.

To upgrade your app from the Branch Android SDK 5.x to the 6.0 beta, update the SDK in step 1, then follow [Upgrade from 5.x](#upgrade-from-5-x). That section takes you through steps 2 to 4 and every other call that changed.

Version 6.0 starts from one configuration object, and your app gets all deep link data from `requestDeepLinkData`.

> **Beta**
>
> The Android SDK 6.0 is a beta, and its API can still change before the final release. Test it in development and test builds only, and don't ship it to Google Play.
>
> If you find a problem or a gap, email [support@branch.io](mailto:support@branch.io?subject=Testing%20new%20SDK%20Beta) with "Testing new SDK Beta" as the subject.

## Use an AI coding assistant (Optional)

Copy this prompt into a coding assistant like Claude Code or Cursor, and it upgrades the SDK for you.

```text
Upgrade this app to the Branch Android SDK 6.0 beta, version 6.0.0-beta.3.

Read this guide and follow it. Don't rely on what you already know about the
Branch SDK, because 6.0 removes or changes most of the 5.x API:
https://help.branch.io/developer-hub/android-sdk-6-integration.md

1. Find the app's Branch integration. Look for io.branch.sdk.android in the
   Gradle files, for io.branch entries in AndroidManifest.xml, for
   io.branch.sdk string resources, for an assets/branch.json file, and for
   Branch calls in the Application class and activities.
2. Before you change any code, collect what you need. Reuse the Branch keys
   already in the project, and ask me for any that are missing, including
   both the live key and the test key. If the app has product flavors, ask
   me which Branch key each flavor uses. If more than one activity handles
   links, ask me which one should call requestDeepLinkData.
3. Follow step 1 in the guide, then every step in "Upgrade from 5.x",
   including the steps for 5.x code that still builds. Then apply any case
   in "Handle edge cases" that fits this app.
4. Write code in the app's language, Kotlin or Java. Don't change the app's
   intent filters or launch modes.
5. Build the app and fix any errors.
6. Finish with a list of the files you changed, anything you couldn't
   migrate, and the checks from step 4 in the guide for me to run on a
   device.
```

Review the changes before you merge them.

## 1. Update the SDK to the beta version

Change `io.branch.sdk.android:library` to version 6.0.0-beta.3 exactly, so your app doesn't pick up a different build. Version 6.0 needs a `minSdk` of 21 or later.

```kotlin
// App module build.gradle.kts
dependencies {
    implementation("io.branch.sdk.android:library:6.0.0-beta.3")

    // (Optional) Collect the Google Advertising ID
    implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")
}
```

> **If you collect the Google Advertising ID and minify release builds**
>
> Add this rule to your ProGuard rules file.
>
> ```text
> # The SDK finds the Google Advertising ID library by class name,
> # so keep the class in minified builds
> -keep class com.google.android.gms.ads.identifier.AdvertisingIdClient
> ```

## 2. Start the SDK

Build a `BranchConfiguration` with your Branch key, and pass it to `Branch.initialize` in your `Application` class. Use the same key as your 5.x app, which is usually in the `io.branch.sdk.BranchKey` meta-data in your manifest. If your app doesn't have an `Application` class yet, create one, and name it in the `android:name` attribute of the `<application>` element in your manifest.

**Kotlin**

```kotlin
import android.app.Application
import io.branch.referral.Branch
import io.branch.referral.BranchConfiguration

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // Use your test key in debug builds and your live key in release builds
        val config = BranchConfiguration.Builder("<branch_key>")
            // Automatic opens are on by default. Set this to false to send
            // each open yourself, as in "Send opens yourself"
            .setAutomaticOpenEvents(true)
            // Set any other options on the builder here, as listed in
            // "BranchConfiguration reference"
            .build()

        // Start the SDK here, so it's ready before any activity asks for
        // link data
        Branch.initialize(this, config)
    }
}
```

**Java**

```java
import android.app.Application;
import io.branch.referral.Branch;
import io.branch.referral.BranchConfiguration;

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // Use your test key in debug builds and your live key in release builds
        BranchConfiguration config =
                new BranchConfiguration.Builder("<branch_key>")
                        // Automatic opens are on by default. Set this to
                        // false to send each open yourself, as in
                        // "Send opens yourself"
                        .setAutomaticOpenEvents(true)
                        // Set any other options on the builder here, as
                        // listed in "BranchConfiguration reference"
                        .build();

        // Start the SDK here, so it's ready before any activity asks for
        // link data
        Branch.initialize(this, config);
    }
}
```

Everywhere else, get the SDK from `Branch.getInstance()`, which is `null` until this call runs.

> **Use a different key for debug and release builds**
>
> Define the key for each build type. Then pass `BuildConfig.BRANCH_KEY` to the builder instead of the literal key.
>
> ```kotlin
> // App module build.gradle.kts
> android {
>     // Required with Android Gradle Plugin 8.0 or later
>     buildFeatures { buildConfig = true }
>
>     buildTypes {
>         debug { buildConfigField("String", "BRANCH_KEY", "\"<test_key>\"") }
>         release { buildConfigField("String", "BRANCH_KEY", "\"<live_key>\"") }
>     }
> }
> ```

## 3. Handle deep links

Call `requestDeepLinkData` in your launcher activity's `onCreate` and `onNewIntent` methods, and route the user in its callback.

**Kotlin**

```kotlin
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import io.branch.referral.Branch

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // The app launches. On a new install from a link, this returns
        // that link's data
        // Skip re-creations so they don't count as opens, for example
        // after a rotation
        if (savedInstanceState == null) requestBranchData()
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        // The SDK reads the link from the activity's current intent
        setIntent(intent)
        requestBranchData()
    }

    private fun requestBranchData() {
        // Branch runs the callback on the main thread
        // The params object holds the link's data, including any keys you
        // added to the link
        Branch.getInstance().requestDeepLinkData(this) { params, error ->
            if (error != null) {
                // The request failed, for example because the device is offline
            } else if (params?.optBoolean("+clicked_branch_link") == true) {
                // A Branch Link opened the app, so show the content it
                // points to
            }
        }
    }
}
```

**Java**

```java
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import io.branch.referral.Branch;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // The app launches. On a new install from a link, this returns
        // that link's data
        // Skip re-creations so they don't count as opens, for example
        // after a rotation
        if (savedInstanceState == null) {
            requestBranchData();
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        // The SDK reads the link from the activity's current intent
        setIntent(intent);
        requestBranchData();
    }

    private void requestBranchData() {
        // Branch runs the callback on the main thread
        // The params object holds the link's data, including any keys you
        // added to the link
        Branch.getInstance().requestDeepLinkData(this, (params, error) -> {
            if (error != null) {
                // The request failed, for example because the device is offline
            } else if (params != null
                    && params.optBoolean("+clicked_branch_link")) {
                // A Branch Link opened the app, so show the content it
                // points to
            }
        });
    }
}
```

Each `requestDeepLinkData` call counts as an install or open, so call it only where this sample does. Branch doesn't count an open on its own when your app returns from the background.

Read link data in this callback. When your app moves to the background, the SDK can clear the data that `getLatestReferringParams()` returns.

## 4. Check your integration

After you finish [Upgrade from 5.x](#upgrade-from-5-x), run a debug build with verbose logging, open a Branch Link, and confirm that the link data arrives.

1. Add `.setLogLevel(BranchLogger.BranchLogLevel.VERBOSE)` to the builder in your `Application` class, in debug builds only. The `BranchLogger` class is in the `io.branch.referral` package.
2. Run the app on a device.
3. Filter Logcat by the `BranchSDK` tag.
4. Open a Branch Link for your app from a messaging or notes app. Use a link from the same Branch app as your key, such as a `test-app.link` link for a test key.
5. Check that the `RequestDeepLink Succeeded` line in Logcat shows `+clicked_branch_link` as true.
6. Check that your release build uses your live key, without the verbose log level.

> **If a check fails**
>
> - If the link opens a browser instead of your app, Android didn't verify your App Links. On Android 12 or later, run `adb shell pm get-app-links <package_name>` and check that each Branch host shows as verified. If one doesn't, check that Branch has the SHA256 fingerprint of the key that signed the build.
> - If `Branch.getInstance()` returns `null`, check that the `android:name` attribute of `<application>` names your `Application` class.
> - If your callback gets an error, the `Request DeepLink failed with HTTP code` line in Logcat says why.
> - If `build()` throws an `IllegalArgumentException`, see [Fix a configuration error](#fix-a-configuration-error).

## Handle edge cases

Most integrations don't run into these cases. Check them when your app does one of these things, or when something doesn't work as expected.

### Fix a configuration error

If the key is empty or a value is out of range, `build()` throws an `IllegalArgumentException` that lists each setting that isn't valid. The timeouts and the retry interval must be more than 0, and the retry count must be 0 or more. If you create the builder without a key, `Branch.initialize` throws the same exception.

### Use coroutines

For launches, use the callback version of `requestDeepLinkData` from step 3, not the suspend version. The suspend version drops its request if something cancels the coroutine before Branch sends it, and a rotation cancels the `lifecycleScope` of the activity.

## Upgrade from 5.x

Most of the upgrade is in how the SDK starts and how your app gets deep link data. Version 6.0 removes `getAutoInstance` and the session builder. Your app starts the SDK with `Branch.initialize`, and `requestDeepLinkData` returns link data.

1. Replace `Branch.getAutoInstance(this)` in your `Application` class by following [2. Start the SDK](#_2-start-the-sdk).
2. If your manifest names `io.branch.referral.BranchApp` or your `Application` class extends it, use your own `Application` class that extends `android.app.Application`. Version 6.0 removes `BranchApp`, so an app whose manifest still names it builds but crashes at launch.
3. In your launcher activity, replace the `sessionBuilder(...).init()` call with the `onCreate` code in [3. Handle deep links](#_3-handle-deep-links). The 5.x guide put that call in `onStart`, but don't call `requestDeepLinkData` there or in a base class that every activity shares, because each call counts as another open.
4. In `onNewIntent`, replace the `reInit()` call and the `branch_force_new_session` check around it with the `onNewIntent` code in [3. Handle deep links](#_3-handle-deep-links). Version 6.0 ignores that extra.
5. If you used auto deep linking, start the right activity yourself in your `requestDeepLinkData` callback.
6. If you used auto deep linking, remove the `io.branch.sdk.auto_link_keys` and `io.branch.sdk.auto_link_path` meta-data from your manifest, because 6.0 ignores it.
7. If your app has an `assets/branch.json` file, move its settings to the builder. Version 6.0 ignores the key in this file, but the file's other settings override the builder's.
   - The `branchKey`, `liveKey`, `testKey`, and `useTestInstance` settings become the key you pass to the builder.
   - The `apiUrl`, `fbAppId`, `cppLevel`, and `enableLogging` settings map to the builder's `setApiUrl`, `setFacebookAppId`, `setAttributionLevel`, and `setLogLevel` methods.
   - The `installReferrerFetchTimeout` setting has no replacement. For `deferInitForPluginRuntime`, call `requestDeepLinkData` when your plugin's runtime is ready.
8. Delete the `assets/branch.json` file.
9. If you set the attribution level on the builder, pass each user's saved choice, because `Branch.initialize` applies the builder's level at every launch over the level that Branch saved. If you don't set it, each user's level and opt-out from 5.x carry over.
10. (Optional) Remove the `io.branch.sdk.BranchKey`, `io.branch.sdk.BranchKey.test`, and `io.branch.sdk.TestMode` entries from your manifest and string resources.
11. Build the app.
12. Fix each build error by using the following table.
13. Change the 5.x calls in the table that still build. These are `disableTracking` and `Branch.notifyNativeToInit()`.
14. Run the checks in [4. Check your integration](#_4-check-your-integration).

This table maps 5.x calls to their 6.0 replacements. In this table, a call that starts with `Branch.` is static.

| 5.x | 6.0 |
| --- | --- |
| `Branch.getAutoInstance(context)` or `Branch.getAutoInstance(context, key)` | `Branch.initialize(context, config)` |
| `BranchApp` as your `Application` class | Your own `Application` class that calls `Branch.initialize` |
| `io.branch.sdk.BranchKey` in the manifest or in a string resource, the key in `branch.json`, or `setBranchKey(key)` | `BranchConfiguration.Builder("<branch_key>")` |
| `Branch.enableTestMode()`, `Branch.disableTestMode()`, or `io.branch.sdk.TestMode` in the manifest or in a string resource | Pass your test or live key to `BranchConfiguration.Builder` |
| `Branch.sessionBuilder(activity)...init()` | `requestDeepLinkData(activity, callback)` in `onCreate`, not in `onStart` |
| `Branch.sessionBuilder(activity)...reInit()` in `onNewIntent` | `setIntent(intent)`, then `requestDeepLinkData(this, callback)` for every new intent, with no `branch_force_new_session` check |
| `putExtra("branch", url)` with `putExtra("branch_force_new_session", true)`, for a push notification or a link inside your app | Open your launcher activity with the `branch` extra, which `requestDeepLinkData(activity, callback)` reads. Version 6.0 ignores `branch_force_new_session`. |
| `withData(uri)` on the session builder | `requestDeepLinkData(activity, callback)` when `uri` is the activity's intent data, because that call reads the intent itself. For any other URI, `requestDeepLinkData(uri, callback)`. |
| `withCallback(BranchUniversalReferralInitListener)` on the session builder | A `BranchReferralInitListener`. In it, get the object and link properties with `BranchUniversalObject.getReferredBranchUniversalObject()` and `LinkProperties.getReferredLinkProperties()`. |
| `withDelay`, `isReferrable`, and `ignoreIntent` on the session builder, plus `removeSessionInitializationDelay`, `unlockPendingIntent`, `Branch.expectDelayedSessionInitialization`, `Branch.bypassWaitingForIntent`, `Branch.isWaitingForIntent`, `Branch.enableForcedSession`, `Branch.disableForcedSession`, `Branch.isForceSessionEnabled`, `Branch.enableBypassCurrentActivityIntentState`, and `Branch.bypassCurrentActivityIntentState` | Call `requestDeepLinkData` when your app is ready to handle the link |
| `Branch.notifyNativeToInit()` and `deferInitForPluginRuntime` in `branch.json` | Call `requestDeepLinkData` when your plugin's runtime is ready. The old call still builds but does nothing. |
| Auto deep linking with `io.branch.sdk.auto_link_keys` or `io.branch.sdk.auto_link_path`, and `Branch.isAutoDeepLinkLaunch(activity)` | Start the activity yourself in your `requestDeepLinkData` callback |
| `setIdentity(id)` | `setUserAlias(id)` |
| `disableTracking(true)` and `disableTracking(false)` | `setAttributionLevel(Defines.BranchAttributionLevel.NONE)` in `updateConfiguration`, or another level to opt back in. The old calls still build, with a deprecation warning. |
| `getInitState()` compared to a `SessionState` value | `getInitState()`, which returns a `BranchSessionState` that you check by type |
| `Branch.useEUEndpoint()` | `setEUEndpoint(true)` on the builder |
| `setNetworkTimeout`, `setNetworkConnectTimeout`, `setRetryCount`, and `setRetryInterval` | Builder methods with the same names. An out-of-range value makes `build()` throw. |
| `Branch.setAPIUrl(url)` and `Branch.setCDNBaseUrl(url)` | `setApiUrl(url)` and `setCdnBaseUrl(url)` on the builder |
| `Branch.setCallbackForTracingRequests(callback)` | `setRequestTracingCallback(callback)` on the builder |
| `setBranchRemoteInterface(remoteInterface)` | `setRemoteInterface(remoteInterface)` on the builder |
| `setDMAParamsForEEA(eeaRegion, adPersonalizationConsent, adUserDataUsageConsent)` | `setDMAParameters(params)` on the builder, or in `updateConfiguration` when consent changes, with `params` built by `DMAParameters.Builder` |
| `Branch.setFBAppID(id)` | `setFacebookAppId(id)` on the builder |
| `setPreinstallCampaign`, `setPreinstallPartner`, and `addInstallMetadata` | Builder methods with the same names |
| `Branch.setReferringLinkAttributionForPreinstalledAppsEnabled()` | `setReferringLinkAttributionForPreinstalledApps(true)` on the builder, which has no effect in 6.0.0-beta.3 |
| `addWhiteListedScheme(scheme)` and `setWhiteListedSchemes(schemes)` | `addWhitelistedScheme(scheme)` on the builder, once for each scheme |
| `addUriHostsToSkip(host)` | `addUriHostToSkip(host)` on the builder |
| `Branch.setIsUserAgentSync(sync)` | `setUserAgentFetchSync(sync)` on the builder |
| `setLimitFacebookTracking`, `disableAdNetworkCallouts`, and `setNoConnectionRetryMax` | Removed, with no replacement |
| `registerView()` or `registerView(callback)` on `BranchUniversalObject`, or `registerView(buo, callback)` on `Branch` | `BranchEvent(BRANCH_STANDARD_EVENT.VIEW_ITEM).addContentItems(buo).logEvent(context)` |
| `addContentMetadata(key, value)` and `addContentMetadata(map)` on `BranchUniversalObject` | `getContentMetadata().addCustomMetadata(key, value)` for each key, which adds to the existing metadata |
| `getMetadata()` on `BranchUniversalObject` | `getContentMetadata().getCustomMetadata()` |
| `getPrice()` and `getCurrencyType()` on `BranchUniversalObject` | The `price` and `currencyType` fields of `getContentMetadata()`, which hold the real values. In 5.x, these calls always returned 0.0 and null. The `price` field is a `Double` that's null when no price is set, and `currencyType` is a `CurrencyType` enum. |
| `setContentType(type)` on `BranchUniversalObject` | Delete the call, because it did nothing in 5.x. To set a content type, use `getContentMetadata().setContentSchema(schema)` with a `BranchContentSchema`. |
| `showShareSheet(...)` on `BranchUniversalObject`, `setCallback` on `BranchShareSheetBuilder`, and listeners that implement `Branch.ExtendedBranchLinkShareListener` | `Branch.getInstance().share(activity, buo, linkProperties, callback, title, subject)`, with a `Branch.BranchNativeLinkShareListener` callback. It needs API level 22 or later. |
| `Branch.isInstantApp`, `Branch.showInstallPrompt`, `Branch.disableInstantDeepLinking`, `setInstantDeepLinkPossible`, and `isInstantDeepLinkPossible` | Removed, with no replacement |
| `resetUserSession`, `disableAppList`, `Branch.disableDeviceIDFetch`, `Branch.isDeviceIDFetchDisabled`, `setInstallReferrerTimeout`, `setDeepLinkDebugMode`, `getDeeplinkDebugParams`, `notifyNetworkAvailable`, `cancelShareLinkDialog`, and `getBranchPluginSupport` | Removed, with no replacement |
| `setChannelProperties` on `BranchShareSheetBuilder`, `Branch.IChannelProperties`, and `BranchUniversalObject.RegisterViewStatusListener` | Removed, with no replacement |
| `getType`, `setContentIndexingMode`, `setLocalIndexMode`, `isPublicallyIndexable`, and `isLocallyIndexable` on `BranchUniversalObject` | Removed, with no replacement |

The `BranchEvent` and `LinkProperties` APIs stay the same.

## BranchConfiguration reference

Version 6.0 moves the SDK's settings into one `BranchConfiguration`, which you create with `BranchConfiguration.Builder` and pass to `Branch.initialize`. This sample sets the builder's main options to their defaults or example values, with a note on what each one does.

**Kotlin**

```kotlin
// Your live or test key
val config = BranchConfiguration.Builder("<branch_key>")
    // On by default. With false, Branch holds each open until you call
    // sendOpen(callback) or the app goes to the background
    .setAutomaticOpenEvents(true)

    // The least severe level that Branch logs. Logging stays off until
    // you set this or a logging callback.
    .setLogLevel(BranchLogger.BranchLogLevel.WARN)
    // Your logger instead of Logcat
    .setLoggingCallback { message, severity ->
        Log.d("Branch", "$severity: $message")
    }

    // Milliseconds to connect to Branch's servers
    .setNetworkConnectTimeout(10_000)
    // Milliseconds to wait for a response once connected
    .setNetworkTimeout(5_500)
    // Retries after a server error or a network failure
    .setRetryCount(3)
    // Milliseconds before the first retry, doubled for each retry after it,
    // up to 30 seconds
    .setRetryInterval(1_000)

    // FULL is the default; the others are REDUCED, MINIMAL, and NONE.
    // Branch applies this level at every launch and replaces the level it
    // saved, so if users can change their consent, pass their saved choice
    // instead, or leave this line out.
    .setAttributionLevel(Defines.BranchAttributionLevel.FULL)
    // EEA consent for Google. Branch keeps sending the last values set,
    // including values saved by 5.x.
    .setDMAParameters(
        DMAParameters.Builder()
            .setEeaRegion(true)
            .setAdPersonalizationConsent(false)
            .setAdUserDataUsageConsent(true)
            .build()
    )

    // Turns on the Meta install referrer
    .setFacebookAppId("1234567890")
    // Sent with the install
    .addInstallMetadata("app_variant", "free")
    // Only for apps preinstalled on devices
    .setPreinstallCampaign("spring_promo")
    .setPreinstallPartner("oem_partner")
    .build()

Branch.initialize(this, config)
```

**Java**

```java
// Your live or test key
BranchConfiguration config = new BranchConfiguration.Builder("<branch_key>")
        // On by default. With false, Branch holds each open until you
        // call sendOpen(callback) or the app goes to the background
        .setAutomaticOpenEvents(true)

        // The least severe level that Branch logs. Logging stays off
        // until you set this or a logging callback.
        .setLogLevel(BranchLogger.BranchLogLevel.WARN)
        // Your logger instead of Logcat
        .setLoggingCallback((message, severity) ->
                Log.d("Branch", severity + ": " + message))

        // Milliseconds to connect to Branch's servers
        .setNetworkConnectTimeout(10_000)
        // Milliseconds to wait for a response once connected
        .setNetworkTimeout(5_500)
        // Retries after a server error or a network failure
        .setRetryCount(3)
        // Milliseconds before the first retry, doubled for each retry
        // after it, up to 30 seconds
        .setRetryInterval(1_000)

        // FULL is the default; the others are REDUCED, MINIMAL, and NONE.
        // Branch applies this level at every launch and replaces the level
        // it saved, so if users can change their consent, pass their saved
        // choice instead, or leave this line out.
        .setAttributionLevel(Defines.BranchAttributionLevel.FULL)
        // EEA consent for Google. Branch keeps sending the last values
        // set, including values saved by 5.x.
        .setDMAParameters(new DMAParameters.Builder()
                .setEeaRegion(true)
                .setAdPersonalizationConsent(false)
                .setAdUserDataUsageConsent(true)
                .build())

        // Turns on the Meta install referrer
        .setFacebookAppId("1234567890")
        // Sent with the install
        .addInstallMetadata("app_variant", "free")
        // Only for apps preinstalled on devices
        .setPreinstallCampaign("spring_promo")
        .setPreinstallPartner("oem_partner")
        .build();

Branch.initialize(this, config);
```

> **Note**
>
> The builder also has `setTestMode` and `setReferringLinkAttributionForPreinstalledApps`, which have no effect in 6.0.0-beta.3.

### Send opens yourself

With `setAutomaticOpenEvents(false)`, Branch still resolves each link and calls your `requestDeepLinkData` callback, but it holds the open until you call `sendOpen`. Use this when the open needs data that arrives later, such as Adobe's Experience Cloud ID (ECID). Set the data with `setRequestMetadata`, then call `sendOpen`.

**Kotlin**

```kotlin
// Call Branch.getInstance().sendOpen after requestDeepLinkData
// in requestBranchData() from step 3
// This example uses Adobe Identity, which returns the ECID asynchronously
Identity.getExperienceCloudId { ecid ->
    Branch.getInstance()
        .setRequestMetadata("\$marketing_cloud_visitor_id", ecid)
    Branch.getInstance().sendOpen { error ->
        // error is null when Branch sent the open
    }
}
```

**Java**

```java
// Call Branch.getInstance().sendOpen after requestDeepLinkData
// in requestBranchData() from step 3
// This example uses Adobe Identity, which returns the ECID asynchronously
Identity.getExperienceCloudId(ecid -> {
    Branch.getInstance()
            .setRequestMetadata("$marketing_cloud_visitor_id", ecid);
    Branch.getInstance().sendOpen(error -> {
        // error is null when Branch sent the open
    });
});
```

- Call `sendOpen` once for each `requestDeepLinkData` call.
- If you call `sendOpen` before the link data arrives, Branch sends the open when it does.
- If your app goes to the background first, Branch sends the open then. At the `NONE` attribution level, Branch waits until the user opts in.
- On a new install, events and other requests that need an open fail if they run before Branch sends the open.

### Change settings while the app runs

To change a setting after start-up, pass `updateConfiguration` a configuration that sets only the changed values, as in this consent example. Create its builder without a key.

**Kotlin**

```kotlin
// In your consent screen's handler, after Branch.initialize
fun onConsentChosen(
    level: Defines.BranchAttributionLevel,
    adPersonalization: Boolean,
    adUserData: Boolean
) {
    // Save the choice in your own storage, and pass it to the builder at
    // the next launch
    saveConsent(level, adPersonalization, adUserData)
    // No key
    val changes = BranchConfiguration.Builder()
        .setAttributionLevel(level)
        .setDMAParameters(
            DMAParameters.Builder()
                .setEeaRegion(true)
                .setAdPersonalizationConsent(adPersonalization)
                .setAdUserDataUsageConsent(adUserData)
                .build()
        )
        .build()
    Branch.getInstance().updateConfiguration(changes)
}
```

**Java**

```java
// In your consent screen's handler, after Branch.initialize
void onConsentChosen(Defines.BranchAttributionLevel level,
                     boolean adPersonalization, boolean adUserData) {
    // Save the choice in your own storage, and pass it to the builder at
    // the next launch
    saveConsent(level, adPersonalization, adUserData);
    // No key
    BranchConfiguration changes = new BranchConfiguration.Builder()
            .setAttributionLevel(level)
            .setDMAParameters(new DMAParameters.Builder()
                    .setEeaRegion(true)
                    .setAdPersonalizationConsent(adPersonalization)
                    .setAdUserDataUsageConsent(adUserData)
                    .build())
            .build();
    Branch.getInstance().updateConfiguration(changes);
}
```

The changes apply to the next request Branch sends, and settings you don't set keep their current values. Branch saves the attribution level and DMA values on the device, so they carry over to the next launch, unless your start-up configuration sets new ones.

An update doesn't start a new session. When a user opts in from `NONE`, Branch sends the open it held while attribution was off. With `setAutomaticOpenEvents(false)`, Branch sends that open only after you call `sendOpen`, or once the app has gone to the background. A change between two levels other than `NONE` sends no open.

The key, `setTestMode`, `setFacebookAppId`, the preinstall settings, `addInstallMetadata`, and `setAutomaticOpenEvents` only apply at `Branch.initialize`, so `updateConfiguration` ignores them and logs a warning.
