Skip to main content
Complete guide to push notifications in React Native with Zixflow using @react-native-firebase/messaging for FCM and @notifee/react-native for display and action buttons.
Track your campaigns: Track opens with Zixflow.trackMetric({ event: MetricEvent.Opened }) and action presses with Zixflow.track('Push Notification Action Clicked', ...). See Push Notification Tracking. Reference implementation: src/pushHandlers.ts in sdk-examples/react-native.

Prerequisites

  1. Configure FCM (and APNs for iOS) in the Zixflow dashboard
  2. Add Firebase config files (google-services.json, GoogleService-Info.plist)
  3. Call identify() so device tokens attach to a user
  4. Test on a physical device for iOS

Dependencies


Architecture

The Zixflow native FCM service may still run in parallel for token/delivery on Android. This stack owns display and open/action tracking in JavaScript — no custom Kotlin action installer required.

Initialize handlers

After Zixflow.initialize():
Register background handlers in index.js (before AppRegistry.registerComponent):
Background FCM handler should call the same showNotification path so action buttons work when the app is backgrounded or terminated.

Display with notifee (including action buttons)

Parse action_buttons (max 2). Use channel zixflow_default, iOS categoryId: 'ZX_2BTN', and store the full data map on the notification for tap tracking.
Payload fields: Zixflow-Delivery-ID, Zixflow-Delivery-Token, title, body, deeplink_url, image_url, large_icon_url, action_buttons, sticky, sound, badge.

Open and action tracking

Wire trackOpened / handleNotifeeEvent / handleDeeplink as in the example pushHandlers.ts:
  • Body taptrackMetric(Opened) + open deeplink_url
  • Action taptrackMetric(Opened) + track('Push Notification Action Clicked') + cancel notification + open button deeplink (else deeplink_url)
Full helpers and property contract: Push Notification Tracking.

Custom Action Buttons — iOS category

Register ZX_2BTN at launch so system / notifee notifications can show ACTION_0 / ACTION_1:
Call this from application(_:didFinishLaunchingWithOptions:) (see the example AppDelegate). Also configure Firebase (FirebaseApp.configure()). When notifee displays the notification, action presses are handled in JS via notifee.onForegroundEvent / onBackgroundEvent — you do not need a separate AppDelegate didReceive tracker for that path.

iOS Capabilities

  1. Open the .xcworkspace in Xcode
  2. App target → Signing & Capabilities
  3. Add Push Notifications
  4. Add Background ModesRemote notifications
Optional: Notification Service Extension + App Groups for rich push and reliable delivered metrics — see App Groups below.

App Groups

App Groups improve delivery metric reliability on iOS. If the system terminates the Notification Service Extension before a tracking request finishes, the SDK can recover pending metrics on the next app launch when both targets share an App Group. Add the same App Group to the host app and the Notification Service Extension:
  1. Host app target → Signing & Capabilities+ CapabilityApp Groups
  2. Create an ID such as group.com.yourcompany.yourapp.zixflow
  3. NSE target → App Groups → select the same identifier
Both targets must use the identical string. If you use manual signing, register the App Group in the Apple Developer portal, enable it on both App IDs, and regenerate provisioning profiles. Configure .appGroupId(...) in both the host app push init and the NSE init. Values must match the Xcode entitlements. Host app (AppDelegate, APNs example):
For FCM, use MessagingPushFCM.initialize with the same .appGroupId(...). Notification Service Extension:
The sdk-examples React Native app uses group.com.zixflow.demo.rn as a concrete sample. If you omit .appGroupId(...), the SDK may try a default patterned identifier. Prefer an explicit App Group ID to avoid mismatches.

Android Setup

  1. Place google-services.json in android/app/
  2. Apply the Google Services Gradle plugin
  3. Declare POST_NOTIFICATIONS and request it at runtime on API 33+
  4. Create the notifee channel zixflow_default in JS (as above)

Notification Channels

On Android 8.0+, notifications belong to a channel that controls sound, importance, and user settings.

When you display with notifee (example path)

The React Native example creates the channel in JavaScript:
Use the same channel ID in notifee.displayNotification({ android: { channelId: 'zixflow_default', ... } }). Manifest io.customer.notification_channel_* meta-data does not configure this notifee channel.

When the native Zixflow SDK displays the notification

Zixflow creates one channel per app when the first Zixflow push is delivered (unless you customize it via manifest meta-data). Importance levels: 0 min, 1 low, 2 medium, 3 default/high, 4 urgent.

Customize native SDK channel in AndroidManifest

Set meta-data under <application> before you ship a build that creates the channel. After users have the channel, Android only lets you reliably change the name; ID and importance are sticky for that channel ID.
Use these exact android:name strings — the native SDK reads those keys. Changing the displayed android:value for name is supported after release; changing ID/importance for an existing channel generally has no effect for users who already have that channel.
If you previously shipped with an undesired channel ID, Android allows deleting a channel and creating another with new settings. Do this carefully in native code (users lose prior preference for the old ID):

Deep links send users to a specific screen when they tap a push (or an action button). The React Native example opens them in JS after tracking:
See Push Notification Tracking — Deeplink opening for the full open / action / payload contract. Also configure native URL handling if you use a custom scheme or universal links:

Android

Add intent filters on your main activity in AndroidManifest.xml:
Optional HTTPS app links:
Push click behavior (Android)
Control activity recreation when a notification is tapped:
Opened metrics are tracked for all options when using the default Zixflow push path.

iOS

App scheme
  1. In Xcode → target InfoURL Types, add your scheme (for example yourapp).
  2. Forward opens to React Native:
Zixflow push handling forwards deep links from Zixflow notifications into this path when using the recommended AppDelegate wrapper.
Universal Links
Follow React Native’s Linking / associated domains setup for https:// links that should open the app when installed.

React Navigation

Use deeplink_url for body taps and action_buttons[].deeplink for action taps (fallback to deeplink_url). Open them with handleDeeplink after tracking — see Push Notification Tracking. If deep links fail when the app was killed on iOS, see Troubleshooting.

Multiple Push Providers

The example app uses @react-native-firebase/messaging + @notifee/react-native for receive and display, and tracks opens/actions in JS. If another library also receives FCM, avoid double display and double metrics.

Option 1: Display yourself (Firebase + notifee)

Own display with notifee (or similar), then:
  • Track opened / action clicked with trackMetric / track (see Push Notification Tracking)
  • Optionally track delivered with trackMetric(Delivered), or forward for tracking only:
Do not call onMessageReceived(..., true) if notifee already displayed the same message.

Option 2: Forward payloads for Zixflow to display

Background helper (avoids duplicate display when FCM already showed a notification payload):
Example with @react-native-firebase/messaging

Option 3: Register Zixflow’s FCM service

Hand Android FCM delivery to Zixflow by declaring the service in AndroidManifest.xml under <application>:
Prefer Option 1 when your app displays notifications with notifee (as in the example).

Identify Users

On logout:

Testing

  1. Register token + identify a test user
  2. Send a push from the Zixflow dashboard (include action_buttons to test buttons)
  3. Use a physical iOS device
  4. Enable ZixflowLogLevel.Debug during development
Full sample: sdk-examples/react-native.