Braze Device Mode Integration

Send events to Braze in RudderStack device mode.

After you have successfully instrumented Braze as a destination in RudderStack, follow this guide to correctly send your events to Braze in device mode.

Add Braze integration

Make sure to add the Braze integration to your project before sending events to Braze in device mode.

Depending on your integration platform, follow these steps:

The Braze integration v1.0.0 and above requires minimum SDK version (minSdk) of 25.

Follow the steps in this section to add Braze to your Kotlin project.

  1. In your module (app-level) Gradle file (usually <project>/<app-module>/build.gradle.kts or <project>/<app-module>/build.gradle), add the following dependencies for the RudderStack-Braze integration:
kotlin
dependencies {
  // ...
  
  // Add Rudder Kotlin and Braze integration SDKs:
  implementation("com.rudderstack.sdk.kotlin:android:<latest-version>")
  implementation("com.rudderstack.integration.kotlin:braze:<latest-version>")
}
  1. For further steps on permissions and other optional configurations, see the Braze documentation.
  2. Add the SDK initialization and the Rudder-Braze integration in your Application class:
kotlin
import android.app.Application
import com.rudderstack.sdk.kotlin.android.Analytics
import com.rudderstack.sdk.kotlin.android.Configuration
import com.rudderstack.integration.kotlin.braze.BrazeIntegration

class MyApplication : Application() {
    lateinit var analytics: Analytics

    override fun onCreate() {
        super.onCreate()
        analytics = Analytics(
            configuration = Configuration(
                writeKey = "WRITE_KEY",
                application = this,
                dataPlaneUrl = "DATA_PLANE_URL",
            )
        )
        
        analytics.add(BrazeIntegration())
    }
}

Use platform-specific Braze App Identifier keys

For device mode connections, you can configure platform-specific (Android, iOS, and web) Braze App Identifier keys while setting up your Braze destination. This is useful especially when connecting cross-platform SDK sources like React Native and Flutter, while also allowing Android and iOS sources to be configured to the same Braze destination.

To use this feature:

  1. Enable the Enable Platform-specific App Identifier Keys setting in the Connection settings.
  2. Configure the relevant App Identifier keys based on your connected sources.

How App Identifier key selection works

The Braze device mode integration looks for platform-specific App Identifier keys first. If unavailable, it uses the Default App Identifier Key instead.

Note that:

  • An older version of the device mode integration will continue to work with the default App Identifier key.
  • If you remove the default App Identifier key and configure platform-specific App Identifier keys, you must upgrade to the latest version of the device mode integration highlighted below:
SDKMinimum supported integration version
Android (Kotlin)1.1.1
iOS (Swift)1.0.1
React Native2.1.0
Flutter2.5.0
Android (Java) — Legacy2.1.1
iOS (Obj-C) — Legacy4.2.1

Migration example

Scenario

Suppose you have three sources connected to three separate Braze destinations in your current setup:

  • Android source (A) → Braze destination (B1)
  • iOS source (B) → Braze destination (B2)
  • JavaScript source (C) → Braze destination (B3)

Each destination is configured with platform-specific keys.

What you want to achieve

You want to consolidate these connections to a single Braze destination (B3, for example) that supports all the platform-specific App Identifier keys, simplifying your overall setup.

Steps

  1. Upgrade your SDK integrations: Upgrade your Android and iOS SDK integrations to the minimum versions that support platform-specific App Identifier keys. See the supported versions table above for details.

  2. Enable platform-specific keys: In your existing Braze destination B3 (previously connected only to the JavaScript source), enable the Enable Platform-specific App Identifier Keys toggle in the Connection settings and specify the platform-specific key for the JavaScript source.

  3. Connect additional sources: Connect your Android (A) and iOS (B) sources to the Braze destination.

  4. Add platform-specific keys: Configure the Android and iOS App Identifier keys in the destination settings.

  5. Remove old destinations: Delete the older separate Braze destinations (B1 and B2) that are no longer needed.

After completing these steps, all three sources (Android, iOS, and JavaScript) send events to a single Braze destination configured with platform-specific App Identifier keys.

Identify

You can use the identify call to identify a user in Braze in any of the below cases:

  • When the user registers to the app for the first time.
  • When they log into their app.
  • When they update their information.

A sample identify call is shown below:

javascript
rudderanalytics.identify("1hKOmRA4GRlm", {
  email: "alex@example.com",
  name: "Alex Keener"
});

Set custom user ID (externalId)

In mobile device mode, that is, when using Android (Java), iOS (Obj-C), React Native, or Flutter as source, you need to pass externalId in your identify events. Otherwise, Braze uses userId to identify the user.

Braze gives first preference to the externalId field in the identify event to identify the user. If externalId is absent, it falls back to the userId field.

The following code snippet shows how to add an externalId to your identify event using the React Native SDK:

typescript
const options = {
  externalIds: [
    {
      id: "<your_external_id>",
      type: "brazeExternalId",
    },
  ],
}
rudderClient.identify(
  "1hKOmRA4GRlm",
  {
    email: "alex@example.com",
    gender: "male",
  },
  options
)
Make sure to send the identify event containing the externalId before sending any subsequent track events. That way, RudderStack is able to successfully persist the externalId information in all the future events.

Track

The track event lets you record the customer events along with any associated properties.

A sample track call is shown below:

javascript
rudderanalytics.track("Product Added", {
  numberOfRatings: "12",
  name: "item 1"
});

Order Completed

When you use the track call for an Order Completed event, RudderStack sends the product information present in the event to Braze as purchases.

A sample Order Completed event is shown:

javascript
rudderanalytics.track("Order Completed", {
  userId: "1hKOmRA4GRlm",
  currency: "USD",
  products: [
    {
      product_id: "123454387",
      name: "Game",
      price: 15.99
    }
  ]
});

Page

The page event lets you record your website’s page views, with the additional relevant information about the viewed page.

A sample page call is as shown:

javascript
rudderanalytics.page("Cart", "Cart Viewed", {
  path: "/cart",
  referrer: "test.com",
  search: "term",
  title: "test_item",
  url: "http://test.in"
});

Delta management for identify and track calls

If you are sending events to Braze in device mode, you can save costs by deduplicating your identify calls. To do so, enable the Deduplicate Traits dashboard setting. RudderStack then sends only the changed or modified attributes (traits) to Braze.

RudderStack recommends reviewing Braze’s data points policy to fully understand how this functionality can help you avoid data overages.

Advanced features

This section covers some advanced Braze operations that you can perform using RudderStack.

Send push notification events

Depending on your iOS (Obj-C) SDK version, follow these steps to send push notification events to Braze:

The iOS (Swift) SDK does not auto-forward push notifications. You must explicitly integrate the push notification handling code in your app.

The underlying Braze instance is exposed and can be accessed via the getDestinationInstance() or onDestinationReady() callbacks for customizing the push notification handling code.

Prerequisites

You must enable the Push Notifications capability in Xcode under your target’s Signing & Capabilities section.

Step 1: Initialize integration and register for push notifications

Store the BrazeIntegration instance as a property so it can be referenced throughout the app’s lifecycle. Set up UNUserNotificationCenter synchronously before the app finishes launching.

For SwiftUI apps, use @UIApplicationDelegateAdaptor to wire in a UIApplicationDelegate implementation:

swift
import SwiftUI
import UIKit
import UserNotifications
import RudderStackAnalytics
import RudderIntegrationBraze
import BrazeKit

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

class AppDelegate: UIResponder, UIApplicationDelegate {

    // Store the plugin instance — required for getDestinationInstance() and onDestinationReady
    private let brazePlugin = BrazeIntegration()
    private var pendingDeviceToken: Data?

    private var braze: Braze? {
        brazePlugin.getDestinationInstance() as? Braze
    }

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        setupRudderStack()
        setupPushNotifications(application)
        return true
    }

    private func setupRudderStack() {
        let configuration = Configuration(
            writeKey: "<WRITE_KEY>",
            dataPlaneUrl: "<DATA_PLANE_URL>"
        )
        let analytics = Analytics(configuration: configuration)
        analytics.add(plugin: brazePlugin)
    }

    private func setupPushNotifications(_ application: UIApplication) {
        let center = UNUserNotificationCenter.current()
        center.setNotificationCategories(Braze.Notifications.categories)
        center.delegate = self
        center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
            guard granted else { return }
            DispatchQueue.main.async {
                application.registerForRemoteNotifications()
            }
        }
    }
}

Step 2: Forward device token

The didRegisterForRemoteNotificationsWithDeviceToken callback can be triggered very early during app launch. Depending on OS-level timing, the device token may be received before the Braze SDK has been initialized and is ready to accept the token.

To avoid losing the token in such cases, temporarily store it and register it once Braze becomes available using onDestinationReady:

swift
extension AppDelegate {

    func application(_ application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        if let braze {
            // Braze already initialized — register immediately
            braze.notifications.register(deviceToken: deviceToken)
        } else {
            // Hold token until onDestinationReady fires
            pendingDeviceToken = deviceToken
            brazePlugin.onDestinationReady { [weak self] instance, result in
                guard let self, case .success = result,
                      let token = self.pendingDeviceToken,
                      let braze = instance as? Braze else { return }
                braze.notifications.register(deviceToken: token)
                self.pendingDeviceToken = nil
            }
        }
    }

    func application(_ application: UIApplication,
                     didFailToRegisterForRemoteNotificationsWithError error: Error) {
        // Handle registration failure
    }
}

Step 3: Handle notification events

swift
extension AppDelegate: UNUserNotificationCenterDelegate {

    // Foreground display options
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.list, .banner, .sound])
    }

    // Notification tap / action response
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        if let braze, braze.notifications.handleUserNotification(response: response, withCompletionHandler: completionHandler) {
            return
        }
        completionHandler()
    }

    // Silent / background push
    func application(_ application: UIApplication,
                     didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        if let braze, braze.notifications.handleBackgroundNotification(userInfo: userInfo, fetchCompletionHandler: completionHandler) {
            return
        }
        completionHandler(.noData)
    }
}

See the following references for more information:

Send in-app message events

Braze in-app messages are not automatically supported in the iOS (Swift) SDK. After the Braze SDK is initialized, you must explicitly configure a presenter — use the onDestinationReady callback to assign BrazeInAppMessageUI as the in-app message presenter.

1. Add dependency

  • Using Package.swift (requires adding BrazeUI to your target’s package dependencies in the Package.swift file):
swift
..
dependencies: [
  .package(url: "https://github.com/braze-inc/braze-swift-sdk-prebuilt-static", from: "<latest_version>"),
],
targets: [
  .target(
    name: "<your_target>",
    dependencies: [
      .product(name: "BrazeUI", package: "braze-swift-sdk-prebuilt-static"),
    ]
   )
]
..
  • Using SPM:

    • Use the Braze repository to search for the package.
    • Select the BrazeUI package to add it as a dependency for your target.

2. Implementation

After add the dependency, import the package as shown:

swift
import BrazeKit
import BrazeUI
import RudderIntegrationBraze

// Inside setupAnalytics(), after analytics.add(plugin: brazePlugin):
brazePlugin.onDestinationReady { instance, result in
    guard case .success = result, let braze = instance as? Braze else { return }
    braze.inAppMessagePresenter = BrazeInAppMessageUI()
}

In-app messages are triggered by custom events. When the app is foregrounded and a matching campaign is active in the Braze dashboard, the message displays automatically after the presenter is assigned.

See the Braze documentation for more information on this feature.

Questions? Let's figure it out together.

Join the RudderStack Slack community to connect with other users, customers, and the RudderStack team — or reach out for direct support.