zixflow-reactnative
v1.1.5
Published
Official Zixflow SDK for React Native. Track customers and send messages to your iOS/Android apps.
Readme
Zixflow React Native SDK - Integration Guide
Welcome to the Zixflow React Native SDK integration guide. This comprehensive document will help you install, configure, and use the Zixflow SDK in your React Native application to track user behavior, send push notifications, display in-app messages, and more.
Table of Contents
- Introduction
- Requirements
- Installation
- iOS Setup
- Android Setup
- Quick Start
- Core Features
- Push Notifications
- Push Notification Tracking
- Location Tracking
- Geofence Tracking
- Live Activities
- Notification Inbox
- Advanced Configuration
- Example Applications
- API Reference
Introduction
The Zixflow React Native SDK enables you to:
- Identify users and track their behavior across your app
- Send targeted push notifications via Apple Push Notification service (APNs) or Firebase Cloud Messaging (FCM)
- Display in-app messages to engage users at the right time
- Track user location to enable location-based messaging
- Manage user profiles with custom attributes
- Track events and screen views automatically or manually
The SDK is built on top of the native Zixflow iOS and Android SDKs, providing a unified TypeScript API for React Native applications.
Requirements
React Native
- React Native: 0.60.0 or higher
- React: 16.8.0 or higher (for hooks support)
iOS
- iOS: 13.0 or higher
- Xcode: 14.0 or higher
- Swift: 5.3 or higher
- CocoaPods: 1.10.0 or higher (if using CocoaPods)
Android
- Android: API level 24 (Android 7.0) or higher
- Kotlin: 1.6.0 or higher
- Gradle: 7.0 or higher
TypeScript (Recommended)
- TypeScript: 4.0 or higher
Installation
The Zixflow React Native SDK is available on npm. You can browse the package here:
npm Installation
Install the SDK using npm:
npm install zixflow-reactnativeYarn Installation
Or install using Yarn:
yarn add zixflow-reactnativeAfter installation, proceed with platform-specific setup for iOS and Android.
iOS Setup
CocoaPods Integration
The Zixflow React Native SDK automatically integrates with the native iOS SDK via CocoaPods or Swift Package Manager. If you're using React Native 0.60 or higher, dependencies are auto-linked.
- Navigate to the iOS directory:
cd ios- Install CocoaPods dependencies:
pod install- Open the workspace in Xcode:
open YourApp.xcworkspaceThe SDK will automatically include the necessary Zixflow iOS modules:
ZixflowCommonZixflowDataPipelinesZixflowMessagingPushZixflowMessagingPushAPN(for APNs)ZixflowMessagingInApp
Swift Package Manager Integration
If you prefer Swift Package Manager (SPM), you can configure your project to use the Zixflow iOS SDK directly:
- Open your project in Xcode
- Go to File > Add Package Dependencies
- Enter the repository URL:
https://github.com/zixflow/zixflow-ios.git - Select the version: Use
1.0.0or higher - Add the following modules to your app target:
Zixflow(umbrella module)ZixflowDataPipelinesZixflowMessagingPushAPNZixflowMessagingInApp
Note: The example app uses SPM for the native iOS SDK integration. See
example/ios/Podfilefor reference.
Push Notification Setup (APNs)
To enable Apple Push Notifications (APNs):
Enable Push Notifications capability in Xcode:
- Select your app target
- Go to Signing & Capabilities
- Click + Capability and add Push Notifications
Enable Background Modes:
- Add Background Modes capability
- Enable Remote notifications
Configure APNs certificates in your Apple Developer account and upload them to Zixflow dashboard.
Notification Service Extension
To support rich push notifications (images, videos, action buttons), you need to add a Notification Service Extension:
Create a Notification Service Extension in Xcode:
- File > New > Target > Notification Service Extension
- Name it
NotificationServiceExtension
Add Zixflow modules to the extension in your
Podfile:
target 'NotificationServiceExtension' do
pod "ZixflowMessagingPushAPN", "~> 1.0"
pod "ZixflowMessagingPush", "~> 1.0"
pod "ZixflowDataPipelines", "~> 1.0"
pod "ZixflowCommon", "~> 1.0"
pod "AnalyticsSwiftZixflow", "1.7.3+zixflow.1"
end- Update
NotificationService.swift:
import UserNotifications
import ZixflowMessagingPushAPN
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
// Use Zixflow to handle rich push
MessagingPushAPN.didReceive(request, withContentHandler: contentHandler)
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}- Run
pod installagain to install extension dependencies.
Android Setup
Gradle Configuration
The React Native auto-linking will handle most of the Android setup. However, you need to ensure the following:
- Set minimum SDK version in
android/build.gradle:
buildscript {
ext {
minSdkVersion = 24
compileSdkVersion = 34
targetSdkVersion = 34
}
}- Add Maven repositories in
android/build.gradle:
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
}
}The Zixflow Android SDK will be automatically included via the React Native module.
Firebase Cloud Messaging Setup
To enable Firebase Cloud Messaging (FCM) for push notifications on Android:
Add Firebase to your project:
- Go to Firebase Console
- Add your Android app
- Download
google-services.jsonand place it inandroid/app/
Add Google Services plugin in
android/build.gradle:
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.2'
}
}- Apply the plugin in
android/app/build.gradle:
apply plugin: 'com.google.gms.google-services'- Configure FCM in the SDK (shown in the initialization section below).
Quick Start
Basic Configuration
The SDK is configured using a ZixflowConfig object with several options:
import { Zixflow, ZixflowConfig, ZixflowLogLevel } from 'zixflow-reactnative';
const config: ZixflowConfig = {
apiKey: 'YOUR_API_KEY',
logLevel: ZixflowLogLevel.debug,
inApp: {
},
autoTrackDeviceAttributes: true,
trackApplicationLifecycleEvents: true,
};Configuration Options:
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| apiKey | string | Yes | Your Zixflow API key |
| logLevel | ZixflowLogLevel | No | Logging level (debug, info, error, none) |
| inApp | object | No | Enable in-app messaging (use empty object: {}) |
| autoTrackDeviceAttributes | boolean | No | Automatically track device info |
| trackApplicationLifecycleEvents | boolean | No | Automatically track app lifecycle |
SDK Initialization
Initialize the SDK in your App.tsx or main component using useEffect:
import React, { useEffect } from 'react';
import { Zixflow, ZixflowConfig, ZixflowLogLevel } from 'zixflow-reactnative';
export default function App() {
useEffect(() => {
// Configure the SDK
const config: ZixflowConfig = {
apiKey: 'YOUR_API_KEY',
logLevel: ZixflowLogLevel.debug,
inApp: {
},
autoTrackDeviceAttributes: true,
trackApplicationLifecycleEvents: true,
};
// Initialize the SDK
Zixflow.initialize(config);
console.log('Zixflow SDK initialized');
}, []);
return (
// Your app UI
);
}Important: Initialize the SDK as early as possible in your app's lifecycle, ideally in the root component's
useEffect.
Core Features
User Identification
Identify users to track their behavior across sessions and devices:
import { Zixflow } from 'zixflow-reactnative';
// Identify user with ID only
Zixflow.identify({
userId: 'user-123'
});
// Identify user with traits
Zixflow.identify({
userId: 'user-123',
traits: {
email: '[email protected]',
firstName: 'John',
lastName: 'Doe',
plan: 'premium'
}
});When to identify users:
- After successful login
- When user information becomes available
- After account creation
Event Tracking
Track custom events to understand user behavior:
import { Zixflow } from 'zixflow-reactnative';
// Track event without properties
Zixflow.track('button_clicked');
// Track event with properties
Zixflow.track('product_viewed', {
product_id: '12345',
product_name: 'Premium Plan',
category: 'subscription',
price: 29.99
});
// Track with Map (alternative syntax)
const properties = new Map<string, any>();
properties.set('item_count', 3);
properties.set('total_amount', 89.97);
Zixflow.track('checkout_completed', properties);Common events to track:
- User actions (button clicks, form submissions)
- E-commerce events (product views, purchases)
- Content interactions (article reads, video plays)
- Feature usage
Screen Tracking
Track screen views to understand user navigation:
import { Zixflow } from 'zixflow-reactnative';
// Track screen view
Zixflow.screen('HomeScreen');
// Track screen with properties
Zixflow.screen('ProductDetailScreen', {
product_id: '12345',
category: 'electronics'
});Automatic screen tracking with React Navigation:
import { NavigationContainer, NavigationContainerRef } from '@react-navigation/native';
import { Zixflow } from 'zixflow-reactnative';
import React, { useRef } from 'react';
export default function App() {
const navigationRef = useRef<NavigationContainerRef>(null);
const routeNameRef = useRef<string>();
return (
<NavigationContainer
ref={navigationRef}
onReady={() => {
routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name;
}}
onStateChange={async () => {
const previousRouteName = routeNameRef.current;
const currentRouteName = navigationRef.current?.getCurrentRoute()?.name;
if (previousRouteName !== currentRouteName && currentRouteName) {
// Track screen change
Zixflow.screen(currentRouteName);
}
// Save current route name
routeNameRef.current = currentRouteName;
}}
>
{/* Your navigation setup */}
</NavigationContainer>
);
}User Profile Attributes
Set custom attributes on user profiles:
import { Zixflow } from 'zixflow-reactnative';
// Set profile attributes
Zixflow.setProfileAttributes({
plan: 'premium',
subscription_status: 'active',
last_login: new Date().toISOString(),
preferences: {
newsletter: true,
notifications: true
}
});Device Attributes
Set custom attributes on the current device:
import { Zixflow } from 'zixflow-reactnative';
// Set device attributes
Zixflow.setDeviceAttributes({
app_version: '2.1.0',
build_number: '421',
theme: 'dark',
language_preference: 'en-US'
});Clearing User Identity
Clear user identity when users log out:
import { Zixflow } from 'zixflow-reactnative';
// Clear identify on logout
const handleLogout = async () => {
// Clear Zixflow identity
Zixflow.clearIdentify();
// Perform other logout actions
// ...
};Push Notifications
Complete guide to implementing push notifications in React Native with Zixflow using Apple Push Notifications (APNs) or Firebase Cloud Messaging (FCM).
** Track your campaigns:** The SDK automatically tracks delivery, opens, and clicks. For advanced tracking customization and implementation details, see Push Notification Tracking.
Prerequisites
Before implementing push notifications:
- Configure push credentials in Zixflow dashboard - Add APNs certificates or FCM Server Key
- Complete iOS/Android native setup - Ensure native dependencies are installed
- Device tokens must be associated with users - Call
identify()before sending notifications
Important Limitation: The Zixflow React Native SDK currently supports deep links and images in push notifications. Custom action buttons require additional native code.
Platform-Specific Requirements
iOS Requirements
- APNs or FCM: Choose either Apple Push Notification service or Firebase Cloud Messaging
- Xcode Capabilities: Push Notifications and Background Modes
- Notification Service Extension: Required for rich push (images, videos)
- Physical Device: iOS Simulator cannot receive push notifications
Android Requirements
- Firebase Project: Required for FCM integration
- google-services.json: Must be in
android/app/directory - Minimum API Level 24: Android 7.0 or higher
- POST_NOTIFICATIONS Permission: Required for Android 13+ (API 33+)
iOS Setup
You can use either APNs (Apple Push Notification service) or FCM (Firebase Cloud Messaging) on iOS.
Step 1: Enable Push Capabilities in Xcode
- Open your project's
.xcworkspacefile in Xcode - Select your app target
- Go to Signing & Capabilities tab
- Click + Capability → Add Push Notifications
- Click + Capability → Add Background Modes
- Enable Remote notifications under Background Modes
Step 2: Choose APNs or FCM
Option A: APNs (Recommended for iOS-only apps)
Update your ios/Podfile:
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '13.0'
target 'YourApp' do
config = use_native_modules!
use_react_native!(:path => config[:reactNativePath])
# Add Zixflow with APNs support
pod 'zixflow-reactnative/apn', :path => '../node_modules/zixflow-reactnative'
# Your other dependencies...
endOption B: FCM (For cross-platform Firebase apps)
Update your ios/Podfile with static linkage:
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '13.0'
# Required for FCM
use_frameworks! :linkage => :static
target 'YourApp' do
config = use_native_modules!
use_react_native!(:path => config[:reactNativePath])
# Add Zixflow with FCM support
pod 'zixflow-reactnative/fcm', :path => '../node_modules/zixflow-reactnative'
# Your other dependencies...
endInstall dependencies:
cd ios
pod install
cd ..Step 3: Configure AppDelegate (Swift - Recommended)
For modern Swift-based React Native apps with APNs:
AppDelegate.swift:
import UIKit
import ZixflowMessagingPushAPN
@main
class AppDelegateWithZixflowIntegration: ZixflowAppDelegateWrapper<AppDelegate> {}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Set notification delegate
UNUserNotificationCenter.current().delegate = self
// Initialize Zixflow push messaging (APNs)
MessagingPushAPN.initialize(
withConfig: MessagingPushConfigBuilder()
.build()
)
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
// Show notifications when app is in foreground
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
completionHandler([.banner, .list, .badge, .sound])
}
}For FCM, import ZixflowMessagingPushFCM instead:
import ZixflowMessagingPushFCM
// Initialize with FCM
MessagingPushFCM.initialize(
withConfig: MessagingPushConfigBuilder()
.build()
)Step 4: Configure AppDelegate (Objective-C)
If your React Native app uses Objective-C, create a Swift bridge:
Create MyAppPushNotificationsHandler.swift:
import Foundation
import ZixflowMessagingPushAPN
@objc
public class MyAppPushNotificationsHandler: NSObject {
@objc(setupZixflowClickHandling)
public func setupZixflowClickHandling() {
MessagingPushAPN.initialize(
withConfig: MessagingPushConfigBuilder().build()
)
}
@objc(application:deviceToken:)
public func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
MessagingPush.shared.application(
application,
didRegisterForRemoteNotificationsWithDeviceToken: deviceToken
)
}
@objc(application:error:)
public func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
MessagingPush.shared.application(
application,
didFailToRegisterForRemoteNotificationsWithError: error
)
}
}Update AppDelegate.mm:
#import "YourApp-Swift.h"
@implementation AppDelegate
MyAppPushNotificationsHandler* pnHandlerObj;
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ... existing initialization code ...
// Register for remote notifications
[application registerForRemoteNotifications];
// Initialize push handling
pnHandlerObj = [[MyAppPushNotificationsHandler alloc] init];
[pnHandlerObj setupZixflowClickHandling];
return YES;
}
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[pnHandlerObj application:application deviceToken:deviceToken];
}
- (void)application:(UIApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
[pnHandlerObj application:application error:error];
}
@endStep 5: Rich Push with Notification Service Extension
To support rich push notifications (images, videos, GIFs), add a Notification Service Extension:
1. Create Notification Service Extension:
- In Xcode: File → New → Target
- Select Notification Service Extension
- Name it
NotificationServiceExtension - Click Finish (activate scheme when prompted)
2. Add Zixflow to Extension:
Update your ios/Podfile to include the extension:
# Main app target
target 'YourApp' do
# ... existing configuration ...
pod 'zixflow-reactnative/apn', :path => '../node_modules/zixflow-reactnative'
end
# Notification Service Extension target
target 'NotificationServiceExtension' do
pod 'zixflow-reactnative-richpush/apn', :path => '../node_modules/zixflow-reactnative'
endFor FCM:
target 'NotificationServiceExtension' do
pod 'zixflow-reactnative-richpush/fcm', :path => '../node_modules/zixflow-reactnative'
end3. Install dependencies:
cd ios
pod install
cd ..4. Update NotificationService.swift:
import UserNotifications
import ZixflowMessagingPushAPN
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
// Initialize SDK for extension
MessagingPushAPN.initializeForExtension(
withConfig: MessagingPushConfigBuilder(apiKey: "YOUR_API_KEY")
.build()
)
if let bestAttemptContent = bestAttemptContent {
// Let Zixflow handle rich push and track delivery
MessagingPush.shared.didReceive(request, withContentHandler: contentHandler)
}
}
override func serviceExtensionTimeWillExpire() {
// Called when extension is about to be terminated
MessagingPush.shared.serviceExtensionTimeWillExpire()
if let contentHandler = contentHandler,
let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}Important: Replace "YOUR_API_KEY" with your actual API key.
Android Setup
Android push notifications use Firebase Cloud Messaging (FCM).
Step 1: Add Firebase to Your Project
- Go to Firebase Console
- Add your Android app to Firebase project
- Download
google-services.json - Place
google-services.jsoninandroid/app/directory
Step 2: Configure Gradle
Project-level android/build.gradle:
buildscript {
ext {
minSdkVersion = 24
compileSdkVersion = 34
targetSdkVersion = 34
}
dependencies {
classpath 'com.google.gms:google-services:4.4.2'
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}App-level android/app/build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services' // Add this line
android {
// ... existing configuration ...
}
dependencies {
// React Native auto-linking handles Zixflow dependencies
// ... your other dependencies ...
}Step 3: Add Permissions
Add to android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required for push notifications -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Required for Android 13+ (API 33+) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application>
<!-- Your app configuration -->
</application>
</manifest>Step 4: Configure Notification Icon and Color (Optional)
Add to android/app/src/main/AndroidManifest.xml inside <application> tag:
<application>
<!-- Default notification icon (white, transparent background) -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
<!-- Default notification color (accent color) -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/notification_color" />
</application>React Native Integration
Step 1: Initialize SDK
Initialize the Zixflow SDK in your App.tsx:
import React, { useEffect } from 'react';
import { Zixflow, ZixflowConfig, ZixflowLogLevel } from 'zixflow-reactnative';
export default function App() {
useEffect(() => {
// Configure the SDK
const config: ZixflowConfig = {
apiKey: 'YOUR_API_KEY',
logLevel: ZixflowLogLevel.debug,
inApp: {
},
autoTrackDeviceAttributes: true,
trackApplicationLifecycleEvents: true,
};
// Initialize the SDK
Zixflow.initialize(config);
console.log('Zixflow SDK initialized');
}, []);
return (
// Your app UI
);
}Step 2: Request Push Permission
Request permission to send push notifications:
import React, { useState } from 'react';
import { Button, Alert } from 'react-native';
import { Zixflow, ZixflowPushPermissionStatus } from 'zixflow-reactnative';
export default function PushPermissionButton() {
const [permissionStatus, setPermissionStatus] = useState<ZixflowPushPermissionStatus | null>(null);
const requestPushPermission = async () => {
try {
const permission = await Zixflow.pushMessaging.showPromptForPushNotifications({
ios: {
sound: true,
badge: true,
alert: true,
},
});
setPermissionStatus(permission);
switch (permission) {
case ZixflowPushPermissionStatus.Granted:
Alert.alert('Success', 'Push notifications enabled!');
console.log('Push notifications enabled');
break;
case ZixflowPushPermissionStatus.Denied:
Alert.alert('Denied', 'Push notification permission was denied');
console.log('Push notifications denied');
break;
case ZixflowPushPermissionStatus.NotDetermined:
// iOS only: permission not yet asked
console.log('Push notification permission not determined');
break;
}
} catch (error) {
console.error('Failed to request push permission:', error);
}
};
return (
<Button
title="Enable Push Notifications"
onPress={requestPushPermission}
/>
);
}Permission Options (iOS):
| Option | Type | Description |
|--------|------|-------------|
| sound | boolean | Enable notification sounds |
| badge | boolean | Enable app badge updates |
| alert | boolean | Show notification alerts |
Step 3: Check Permission Status
Check current push permission status:
import { Zixflow, ZixflowPushPermissionStatus } from 'zixflow-reactnative';
const checkPushPermission = async () => {
try {
const status = await Zixflow.pushMessaging.getPushPermissionStatus();
console.log('Push permission status:', status);
if (status === ZixflowPushPermissionStatus.Granted) {
console.log('Push notifications are enabled');
} else if (status === ZixflowPushPermissionStatus.Denied) {
console.log('Push notifications are disabled');
} else {
console.log('Push permission not determined');
}
} catch (error) {
console.error('Failed to get push permission status:', error);
}
};Step 4: Identify Users
Critical: Device tokens must be associated with a user before push notifications can be delivered.
import { Zixflow } from 'zixflow-reactnative';
// Identify user when they log in
const handleLogin = async (userId: string, userEmail: string) => {
try {
// Identify user with Zixflow
Zixflow.identify({
userId: userId,
traits: {
email: userEmail,
firstName: 'John',
lastName: 'Doe',
plan: 'premium',
},
});
console.log('User identified:', userId);
} catch (error) {
console.error('Failed to identify user:', error);
}
};Important Notes:
- When users start the app, they automatically generate a device token
- This token links to their Zixflow profile when you call
identify() - This ensures notifications are delivered to the correct user
Step 5: Get Device Token
Retrieve the registered device token:
import { Zixflow } from 'zixflow-reactnative';
const getDeviceToken = async () => {
try {
const token = await Zixflow.pushMessaging.getRegisteredDeviceToken();
console.log('Device token:', token);
return token;
} catch (error) {
console.error('Failed to get device token:', error);
return null;
}
};Deep Links and Navigation
Handle deep links from push notifications:
Setup Deep Linking
1. Configure Deep Links (iOS):
Add to ios/YourApp/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>yourapp</string>
</array>
</dict>
</array>2. Configure Deep Links (Android):
Add to android/app/src/main/AndroidManifest.xml:
<activity android:name=".MainActivity">
<!-- Existing intent filter -->
<!-- Deep link intent filter -->
<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="*" />
</intent-filter>
<!-- Universal 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="yourapp.com" />
</intent-filter>
</activity>Handle Deep Links in React Native
Use React Navigation's linking configuration:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Linking } from 'react-native';
const Stack = createNativeStackNavigator();
const linking = {
prefixes: ['yourapp://', 'https://yourapp.com'],
config: {
screens: {
Home: 'home',
Product: 'product/:id',
Profile: 'profile',
},
},
};
export default function App() {
return (
<NavigationContainer linking={linking}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Product" component={ProductScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}Rich Push Notification Payloads
The Zixflow SDK automatically handles rich push notifications. Here's how to structure payloads:
iOS APNs Payload
{
"aps": {
"mutable-content": 1,
"alert": {
"title": "New Product Available",
"body": "Check out our latest premium features"
},
"badge": 1,
"sound": "default"
},
"Zixflow": {
"push": {
"link": "yourapp://product/123",
"image": "https://example.com/product-image.jpg"
}
}
}iOS FCM Payload
{
"message": {
"apns": {
"payload": {
"aps": {
"mutable-content": 1,
"alert": {
"title": "Special Offer",
"body": "Limited time discount!"
}
},
"Zixflow": {
"push": {
"link": "https://yourapp.com/offers",
"image": "https://example.com/offer.png"
}
}
},
"headers": {
"apns-priority": 10
}
}
}
}Android FCM Payload
{
"message": {
"data": {
"title": "Order Shipped",
"body": "Your order is on the way!",
"image": "https://example.com/shipping.jpg",
"link": "yourapp://orders/456"
}
}
}Testing Push Notifications
1. Verify Device Token Registration
Check if device token is registered:
const verifyPushSetup = async () => {
try {
const token = await Zixflow.pushMessaging.getRegisteredDeviceToken();
const status = await Zixflow.pushMessaging.getPushPermissionStatus();
console.log('Device token:', token);
console.log('Permission status:', status);
if (token && status === ZixflowPushPermissionStatus.Granted) {
console.log('✓ Push notifications ready');
} else {
console.log('✗ Push setup incomplete');
}
} catch (error) {
console.error('Push verification failed:', error);
}
};2. Enable Debug Logging
Set log level to debug during development:
const config: ZixflowConfig = {
apiKey: 'YOUR_API_KEY',
logLevel: ZixflowLogLevel.debug, // Verbose logging
};
Zixflow.initialize(config);3. Test on Physical Devices
iOS:
- Push notifications do not work on iOS Simulator
- Must use physical iOS device
- Ensure APNs certificate is configured in Zixflow dashboard
Android:
- Emulator works if Google Play Services installed
- Physical device always recommended
- Ensure FCM Server Key is configured in Zixflow dashboard
4. Send Test Push from Zixflow
- Log into Zixflow dashboard
- Navigate to Messaging → Push Notifications
- Create test push notification
- Send to specific user (using
userIdfromidentify())
Troubleshooting
iOS Push Not Received
Symptoms: Push sent but not delivered on iOS
Solutions:
- Verify Push Notifications capability enabled in Xcode
- Check APNs certificate uploaded to Zixflow dashboard
- Ensure testing on physical device (not simulator)
- Verify user identified:
Zixflow.identify({ userId: ... }) - Check permission granted:
getPushPermissionStatus() - Review logs for errors
Android Push Not Received
Symptoms: Push sent but not delivered on Android
Solutions:
- Verify
google-services.jsoninandroid/app/directory - Check FCM Server Key in Zixflow dashboard
- Ensure POST_NOTIFICATIONS permission granted (Android 13+)
- Verify Google Services plugin applied
- Check device token registered
- Review logs for errors
Rich Push Not Working (Images)
Symptoms: Images not loading in notifications
iOS Solutions:
- Ensure Notification Service Extension properly configured
- Verify extension has correct dependencies in Podfile
- Check App Groups configuration (if using)
- Verify image URL is accessible
- Check extension logs for errors
Android Solutions:
- Verify image URL is accessible from device
- Check internet connectivity
- Ensure image format is supported (JPEG, PNG, GIF)
Permission Denied
Symptoms: User denied push permission
Solutions:
- Explain value before requesting permission
- Guide users to Settings to enable manually
- Show in-app message explaining benefits
- Request permission at appropriate time (after user engagement)
Device Token Not Registered
Symptoms: getRegisteredDeviceToken() returns empty or fails
Solutions:
- Verify SDK initialized before calling
- Check permission granted
- Ensure identify() called to associate token
- Review native logs for errors
- Rebuild app and retry
Best Practices
- Request permission thoughtfully - Explain value before asking
- Identify users immediately after authentication
- Test on physical devices - Simulators have limitations
- Use rich push - Images increase engagement
- Handle deep links - Provide seamless navigation
- Monitor metrics - Track delivery and open rates
- Enable debug logging - During development only
- Test both platforms - iOS and Android behave differently
- Clear identity on logout - Call
clearIdentify() - Keep credentials secure - Never commit API keys to git
Push Notification Tracking
Overview
Zixflow automatically tracks push notification delivery and engagement metrics to help you measure campaign performance. The SDK tracks three key lifecycle events:
- Delivery Confirmed - When the notification arrives on the device
- Notification Opened - When the user taps the notification
- Action Button Clicked - When the user taps an action button
How Push Tracking Works
When Zixflow sends a push notification, it includes special tracking fields in the data payload:
| Field | Purpose |
|-------|---------|
| Zixflow-Delivery-ID | Unique ID for this delivery (links to campaign record) |
| Zixflow-Delivery-Token | The FCM/APNs token the notification was sent to |
Example push payload:
{
"Zixflow-Delivery-ID": "626533406292836846",
"Zixflow-Delivery-Token": "dcFRlDhiRbehM1vg...",
"title": "Flash Sale! 70% OFF",
"body": "Limited time only — grab your deal now!",
"deeplink_url": "https://yourapp.com/sale",
"image_url": "https://cdn.yourapp.com/banner.png",
"action_buttons": "[{\"name\":\"Shop Now\",\"deeplink\":\"https://yourapp.com/sale\"},{\"name\":\"Remind Me\",\"deeplink\":\"\"}]"
}Note: The SDK automatically handles most tracking for you when using the default push implementation. This section covers advanced customization scenarios.
Tracking Events
1. Delivery Confirmed
When to track: The moment the push payload arrives on the device
SDK method: Zixflow.trackMetric({ deliveryID, deviceToken, event: MetricEvent.delivered })
Implementation:
import messaging from '@react-native-firebase/messaging';
import { Zixflow, MetricEvent } from 'zixflow-reactnative';
// Listen for foreground messages
useEffect(() => {
const unsubscribe = messaging().onMessage(async (remoteMessage) => {
const deliveryId = remoteMessage.data?.['Zixflow-Delivery-ID'] ?? '';
const deliveryToken = remoteMessage.data?.['Zixflow-Delivery-Token'] ?? cachedToken ?? '';
if (deliveryId && deliveryToken) {
await Zixflow.trackMetric({
deliveryID: deliveryId,
deviceToken: deliveryToken,
event: MetricEvent.delivered,
});
}
});
return unsubscribe;
}, []);Important: The Zixflow SDK automatically tracks delivery. Manual tracking is only needed for custom implementations.
2. Notification Opened
When to track: When the user taps the notification banner
SDK method: Zixflow.trackMetric({ deliveryID, deviceToken, event: MetricEvent.opened })
Implementation:
import messaging from '@react-native-firebase/messaging';
import { Zixflow, MetricEvent } from 'zixflow-reactnative';
// Background / quit tap
useEffect(() => {
const unsubscribe = messaging().onNotificationOpenedApp(async (remoteMessage) => {
trackOpened(remoteMessage.data);
handleDeeplink(remoteMessage.data?.deeplink_url);
});
return unsubscribe;
}, []);
// Terminated tap
useEffect(() => {
messaging()
.getInitialNotification()
.then((remoteMessage) => {
if (remoteMessage) {
trackOpened(remoteMessage.data);
handleDeeplink(remoteMessage.data?.deeplink_url);
}
});
}, []);
const trackOpened = async (data: any) => {
const deliveryId = data?.['Zixflow-Delivery-ID'] ?? '';
const deliveryToken = data?.['Zixflow-Delivery-Token'] ?? cachedToken ?? '';
if (deliveryId && deliveryToken) {
await Zixflow.trackMetric({
deliveryID: deliveryId,
deviceToken: deliveryToken,
event: MetricEvent.opened,
});
}
};Note: The SDK automatically tracks opens when using the default push implementation.
3. Action Button Clicked
When to track: When the user taps a named action button
SDK method: Zixflow.track({ name: "Push Notification Action Clicked", properties: {...} })
Implementation:
import { Zixflow, MetricEvent } from 'zixflow-reactnative';
// Handle action press from local notification
const handleActionPress = async (data: any, actionId: string) => {
const deliveryId = data['Zixflow-Delivery-ID'] ?? '';
const token = data['Zixflow-Delivery-Token'] ?? '';
const actionIndex = parseInt(actionId.replace(/\D/g, ''), 10);
const buttons = parseButtons(data['action_buttons']);
const actionName = buttons[actionIndex]?.name ?? `Action ${actionIndex + 1}`;
const actionDeeplink = buttons[actionIndex]?.deeplink ?? '';
// Always fire opened first
await Zixflow.trackMetric({
deliveryID: deliveryId,
deviceToken: token,
event: MetricEvent.opened,
});
// Then fire action clicked
await Zixflow.track({
name: 'Push Notification Action Clicked',
properties: {
'Zixflow-Delivery-ID': deliveryId,
'Zixflow-Delivery-Token': token,
'action_index': actionIndex,
'action_name': actionName,
'action_deeplink': actionDeeplink,
},
});
};
const parseButtons = (raw: any) => {
if (!raw) return [];
try {
return typeof raw === 'string' ? JSON.parse(raw) : raw;
} catch {
return [];
}
};Action button properties:
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| Zixflow-Delivery-ID | string | ✅ | Links event to campaign delivery |
| action_index | integer | ✅ | 0-based index of button tapped |
| action_name | string | ✅ | Button label (e.g., "Shop Now") |
| Zixflow-Delivery-Token | string | Recommended | FCM/APNs token |
| action_deeplink | string | Recommended | Button's URL |
Action Buttons Format
The action_buttons field is a JSON-encoded string containing button definitions:
Raw payload value:
"[{\"name\":\"Shop Now\",\"deeplink\":\"https://yourapp.com/sale\"},{\"name\":\"Remind Me\",\"deeplink\":\"\"}]"Parsed structure:
[
{ "name": "Shop Now", "deeplink": "https://yourapp.com/sale" },
{ "name": "Remind Me", "deeplink": "" }
]Parsing example:
const parseActionButtons = (raw: any): Array<{ name: string; deeplink: string }> => {
if (!raw) return [];
try {
const decoded = typeof raw === 'string' ? JSON.parse(raw) : raw;
return Array.isArray(decoded) ? decoded : [];
} catch (error) {
console.error('Error parsing action buttons:', error);
return [];
}
};
// Usage
const buttons = parseActionButtons(remoteMessage.data?.action_buttons);
buttons.forEach((btn, index) => {
console.log(`Button ${index}: ${btn.name} -> ${btn.deeplink}`);
});Rules:
- Maximum 2 buttons per notification (recommended for consistency across platforms)
deeplinkmay be empty — handle gracefully- Button index is 0-based (first button = index 0)
Complete Push Tracking Implementation
Here's a complete example integrating all tracking events:
import React, { useEffect, useState } from 'react';
import messaging, { FirebaseMessagingTypes } from '@react-native-firebase/messaging';
import { Zixflow, MetricEvent } from 'zixflow-reactnative';
const App = () => {
const [fcmToken, setFcmToken] = useState<string | null>(null);
useEffect(() => {
setupPushNotifications();
}, []);
const setupPushNotifications = async () => {
// Request permission
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
// Get FCM token
const token = await messaging().getToken();
setFcmToken(token);
// Register with Zixflow
await Zixflow.registerDeviceToken({ deviceToken: token });
// Listen for token refresh
messaging().onTokenRefresh(async (newToken) => {
setFcmToken(newToken);
await Zixflow.registerDeviceToken({ deviceToken: newToken });
});
// Handle foreground messages
messaging().onMessage(async (remoteMessage) => {
trackDelivery(remoteMessage);
showLocalNotification(remoteMessage);
});
// Handle background/quit taps
messaging().onNotificationOpenedApp((remoteMessage) => {
trackOpened(remoteMessage.data);
handleDeeplink(remoteMessage.data?.deeplink_url);
});
// Handle terminated tap
const initialNotification = await messaging().getInitialNotification();
if (initialNotification) {
trackOpened(initialNotification.data);
handleDeeplink(initialNotification.data?.deeplink_url);
}
}
};
const trackDelivery = async (message: FirebaseMessagingTypes.RemoteMessage) => {
const deliveryId = message.data?.['Zixflow-Delivery-ID'] ?? '';
const deliveryToken = message.data?.['Zixflow-Delivery-Token'] ?? fcmToken ?? '';
if (deliveryId && deliveryToken) {
await Zixflow.trackMetric({
deliveryID: deliveryId,
deviceToken: deliveryToken,
event: MetricEvent.delivered,
});
}
};
const trackOpened = async (data: any) => {
const deliveryId = data?.['Zixflow-Delivery-ID'] ?? '';
const deliveryToken = data?.['Zixflow-Delivery-Token'] ?? fcmToken ?? '';
if (deliveryId && deliveryToken) {
await Zixflow.trackMetric({
deliveryID: deliveryId,
deviceToken: deliveryToken,
event: MetricEvent.opened,
});
}
};
const handleDeeplink = (url?: string) => {
if (!url) return;
// Implement your deep link navigation logic
console.log('Navigating to:', url);
};
const showLocalNotification = async (message: FirebaseMessagingTypes.RemoteMessage) => {
// Use local notification library to show notification
};
return (
// Your app UI
<></>
);
};
export default App;Tracking Decision Flowchart
Notification received?
├── YES → trackMetric(delivered) [automatic with SDK]
│
User interacted?
├── Tapped notification body
│ └── trackMetric(opened) [automatic with SDK]
│ └── Navigate to deeplink_url
│
└── Tapped action button
├── trackMetric(opened) [automatic with SDK]
└── track("Push Notification Action Clicked")
└── Navigate to button's deeplinkFallback for Non-Zixflow Push
If a push notification doesn't contain Zixflow-Delivery-ID (sent from another source), the SDK automatically skips tracking.
For custom analytics on non-Zixflow pushes, use a different event name:
// Don't use reserved push event names for non-Zixflow pushes
await Zixflow.track({
name: 'External Push Received',
properties: {
'notification_id': message.messageId ?? '',
'title': message.notification?.title ?? '',
'body': message.notification?.body ?? '',
'source': 'external',
},
});Important: Push notification event names (
Push Notification Delivered,Push Notification Opened,Push Notification Action Clicked) are reserved for Zixflow's delivery pipeline.
Testing Push Tracking
Verify Tracking Events
Enable debug logging to see tracking events:
const config: ZixflowConfig = {
apiKey: 'YOUR_API_KEY',
logLevel: 'debug',
};
await Zixflow.setup(config);Look for these log messages:
[Zixflow] Push Notification Delivered tracked[Zixflow] Push Notification Opened tracked[Zixflow] Push Notification Action Clicked tracked
Check Campaign Analytics
- Log into Zixflow dashboard
- Navigate to Messaging → Push Notifications
- View campaign metrics:
- Sent - Total notifications sent
- Delivered - Arrived on device
- Opened - User tapped notification
- Clicked - User tapped action button
Location Tracking
Enable location tracking to send location-based messages:
import { Zixflow } from 'zixflow-reactnative';
// Location tracking is configured via the native SDK
// Make sure to request location permissions in your app
// iOS: Add location permission keys to Info.plist
// - NSLocationWhenInUseUsageDescription
// - NSLocationAlwaysAndWhenInUseUsageDescription
// Android: Add location permissions to AndroidManifest.xml
// - ACCESS_FINE_LOCATION
// - ACCESS_COARSE_LOCATIONRequest location permissions using a library like react-native-permissions:
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
import { Platform } from 'react-native';
const requestLocationPermission = async () => {
const permission = Platform.select({
ios: PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
android: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
});
if (!permission) return;
const result = await request(permission);
if (result === RESULTS.GRANTED) {
console.log('Location permission granted');
}
};On iOS, a React Native 0.88+ UIScene host using the acknowledged handler must declare that ownership before React Native starts. This API is not used on Android or by AppDelegate-only hosts. Call this first in scene(_:willConnectTo:options:) so cold destinations wait for the JavaScript handler instead of entering the legacy Linking path:
NativeZixflow.configureAcknowledgedSceneDeepLinkRouting()Register the app's Zixflow deep-link handler before calling Zixflow.initialize. Return
true after routing a URL. Return false to let the native SDK try the host AppDelegate, then pass
a host-owned custom scheme to React Native Linking or open other URLs through the system. If your
handler might decline an app-owned custom scheme, keep a Linking URL listener registered for that
fallback. A thrown error, rejected promise, missing handler, or handler timeout follows the same
native fallback. Cold URLs wait up to ten seconds for registration and are replayed once the handler
is ready. After delivery, the handler has ten seconds to settle. If it takes longer, native fallback
runs; a handler that later routes the URL can cause a second navigation because its acknowledgement
cannot cancel the fallback.
const subscription = Zixflow.setDeepLinkHandler(async (url) => {
if (!canRouteInApp(url)) {
return false;
}
await routeInApp(url);
return true;
});
Zixflow.initialize(config);Remove the returned subscription when the routing owner is torn down. If no replacement handler registers, later destinations wait for the readiness timeout and then use the native fallback.
The existing Linking path remains available for backward compatibility. Keep
NativeZixflow.configureSceneDeepLinkRouting() in your SceneDelegate, then signal readiness
after registering the listener:
const subscription = Linking.addEventListener('url', ({ url }) => {
// Route the URL in your app.
});
Zixflow.setDeepLinkRoutingReady();Cold destinations wait up to ten seconds for this readiness signal. If it does not arrive, the SDK
tries the host AppDelegate, passes a host-owned custom scheme to React Native Linking, or opens
other URLs through the system.
This older path cannot acknowledge whether JavaScript handled the URL, so the SDK cannot safely fall back after it publishes a Linking event. Prefer setDeepLinkHandler for new UIScene integrations. Older React Native versions and AppDelegate-only hosts keep their existing deep-link integration.
Expo apps keep the Linking path. With config-plugin auto-initialization, register the app's
Linking listener, then call Zixflow.setDeepLinkRoutingReady() after the router is ready. The
Expo plugin configures its native scene lifecycle automatically, so Expo app code does not call a
native configuration method. Apps using JavaScript initialization register the router before
Zixflow.initialize; initialization marks Linking ready automatically.
This integration applies after the host has adopted React Native's UIScene lifecycle; the plugin does not replace React Native's root application lifecycle.
This release's compatibility scope is one simultaneous window scene. Multiple simultaneous React Native window scenes are not supported. React Native's URL notification is process-wide, so SDK-published destinations may reach every connected React Native instance rather than one selected window.
Geofence Tracking
Geofence is an optional module, off by default. Enabling it also enables the Location module, which geofence depends on.
Enable it at build time:
# android/gradle.properties
zixflow_geofence_enabled=true# ios/Podfile
pod 'zixflow-reactnative', :subspecs => ['geofence']Then opt in by passing a geofence config to initialize:
import { Zixflow, ZixflowGeofenceLocationMode } from 'zixflow-reactnative';
Zixflow.initialize({
apiKey: 'YOUR_API_KEY',
geofence: {
// AUTOMATIC (default): the SDK acquires location itself on identify and app launch.
// MANUAL: drive refreshes yourself via Zixflow.geofence.refreshFromCurrentLocation().
locationMode: ZixflowGeofenceLocationMode.Automatic,
},
ios: {
// Whether geofence transitions are delivered in real time on a background cold-wake.
// Defaults to on when the geofence module is enabled.
allowBackgroundDelivery: true,
},
});Request location permissions the same way as for Location Tracking above — geofence monitoring requires them and the SDK never requests permission itself.
With MANUAL location mode, trigger a refresh after permission is granted:
Zixflow.geofence.refreshFromCurrentLocation();This requests a one-shot location fix and refreshes the nearby geofence set from it. It no-ops if the geofence module is not enabled or a user has not been identified.
🔴 Live Activities
Enable the activity types you use under the liveNotifications key of your SDK config. On iOS, also add NSSupportsLiveActivities to your app's Info.plist, the liveactivities pod subspec, and a Widget Extension that renders the SDK's built-in templates. Without the Info.plist key, iOS refuses to start any activity:
<key>NSSupportsLiveActivities</key>
<true/>One manual step is required on iOS. Forward every opened URL to the SDK from the host's active lifecycle, or taps on a Live Activity are not attributed. NativeLiveActivities comes from the wrapper pod, so import it. This only compiles once the liveactivities subspec is installed.
For an AppDelegate host:
import zixflow_reactnative
import React
extension AppDelegate {
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
// Reports an `opened` metric and returns the deep link to route to. A non-Zixflow URL comes
// back unchanged; `nil` means the activity carried no deep link, so there is nothing to open.
guard let routableUrl = NativeLiveActivities.handleWidgetUrl(url) else { return true }
return RCTLinkingManager.application(app, open: routableUrl, options: options)
}
}A React Native AppDelegate conforms to UIApplicationDelegate directly rather than subclassing, so this method is not an override, and the URL is passed on to RCTLinkingManager instead of super. See the sample app's AppDelegate.swift for this in context.
For a UIScene host, handle both lifecycle paths. At scene connection, pass the connection options through the wrapper so a cold Live Activity tap is attributed and its destination enters the acknowledged Zixflow router. Ordinary app links remain in React Native launch options for Linking:
import zixflow_reactnative
reactNativeFactory?.startReactNative(
withModuleName: "YourApp",
in: window,
launchOptions: NativeLiveActivities.reactNativeLaunchOptions(from: connectionOptions)
)Then replace the ordinary React Native URL-forwarding body in the existing SceneDelegate for warm opens. This reports Live Activity taps, sends Zixflow destinations through the configured Zixflow router, and forwards ordinary app links to React Native Linking:
import zixflow_reactnative
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
for context in URLContexts {
NativeLiveActivities.handleAndRouteWidgetUrl(context.url)
}
}Do not also pass those URLs to RCTLinkingManager. The helper already routes them through the
Zixflow bridge, and forwarding them again can deliver the same URL twice.
Android needs no equivalent native step.
For Expo Router, unwrap the URL once in the app's top-level app/+native-intent.tsx file:
import { Zixflow } from 'zixflow-reactnative';
export async function redirectSystemPath({ path }: { path: string }) {
return Zixflow.liveActivities.handleWidgetUrl(path);
}This reports the opened event, returns the customer's destination, preserves ordinary URLs, and
returns null for a Zixflow tracking URL without a destination. Do not also call the helper
from a Linking listener because processing the same tracking URL twice reports two opened events.
Expo apps without Expo Router can apply the helper once in their central Linking initial-URL and
subscription pipeline.
Notification Inbox
The Visual Notification Inbox renders received messages in a list the SDK owns the design of. Two components are available:
NotificationInboxBellView— a bell icon with an unread badge. Tapping it opens the SDK's own inbox panel; the host presents nothing.NotificationInboxView— the message list itself, embeddable directly in your own screen with no surrounding chrome (no bell, no scrim).
import { NotificationInboxBellView, NotificationInboxView } from 'zixflow-reactnative';
// Place the bell wherever your layout calls for it. Give it a fixed size for
// predictable layout — at least 88 points/dp square.
<NotificationInboxBellView
style={{ width: 88, height: 88 }}
onTap={() => analytics.track('inbox_bell_tapped')}
/>
// Or embed the message list directly in a screen of your own.
<NotificationInboxView style={{ flex: 1 }} />onTap on NotificationInboxBellView is observational only — the SDK opens the inbox panel itself. Message actions inside NotificationInboxView are reported through the global inbox event listener below, not a per-message callback.
Remote branding styles the bell and list themselves (colors, icon); the host still owns layout and placement via style.
The SDK ships no text of its own in the visual inbox, so accessibility labels are the one place a string is still needed. Every label is optional — an omitted label leaves that element unlabeled rather than falling back to English:
Zixflow.initialize({
apiKey: 'YOUR_API_KEY',
inApp: {
notificationInboxAccessibilityLabels: {
bell: t('inbox.bell'),
bellWithUnreadCount: t('inbox.unread'), // e.g. "{count} unread notifications"
loadingIndicator: t('inbox.loading'),
emptyState: t('inbox.empty'),
},
},
});Register a listener to observe inbox events (shown, opened, dismissed, and non-dismiss actions taken on a message):
import { InboxEventType } from 'zixflow-reactnative';
const subscription = Zixflow.inAppMessaging.registerInboxEventListener((event) => {
switch (event.eventType) {
case InboxEventType.messageActionTaken:
// event.actionName / event.actionValue are only present for this event
console.log('Inbox action taken:', event.actionName, event.actionValue);
break;
case InboxEventType.messageShown:
case InboxEventType.messageOpened:
case InboxEventType.messageDismissed:
console.log(event.eventType, event.message);
break;
}
});
// Remove listener
subscription.remove();You can also fetch and manage inbox messages directly through Zixflow.inAppMessaging.inbox():
const inbox = Zixflow.inAppMessaging.inbox();
const messages = await inbox.getMessages();
inbox.markMessageOpened(message);
inbox.markMessageDeleted(message);Advanced Configuration
Log Levels
Control SDK logging for debugging:
import { Zixflow, ZixflowLogLevel } from 'zixflow-reactnative';
const config = {
apiKey: 'YOUR_API_KEY',
logLevel: ZixflowLogLevel.debug, // debug, info, error, none
};
Zixflow.initialize(config);Log levels:
ZixflowLogLevel.debug- Verbose logging (development)ZixflowLogLevel.info- Informational messagesZixflowLogLevel.error- Errors onlyZixflowLogLevel.none- No logging (production)
Auto-Tracking Options
Configure automatic tracking features:
import { Zixflow } from 'zixflow-reactnative';
const config = {
apiKey: 'YOUR_API_KEY',
// Automatically track device attributes (OS, model, app version)
autoTrackDeviceAttributes: true,
// Automatically track app lifecycle events (open, close, background)
trackApplicationLifecycleEvents: true,
// Automatically track screens (requires integration)
autoTrackScreenViews: true,
};
Zixflow.initialize(config);Custom API Hosts
Override API endpoints for testing or custom infrastructure:
import { Zixflow } from 'zixflow-reactnative';
const config = {
apiKey: 'YOUR_API_KEY',
// Custom tracking API host
trackingApiUrl: 'https://custom-track.zixflow.com',
// Custom in-app messaging API host
inApp: {
// Override in-app messaging API endpoint if needed
},
};
Zixflow.initialize(config);Example Applications
The Zixflow React Native SDK includes example applications demonstrating best practices:
Sample App (APNs)
Location: example/
Features:
- User identification and logout
- Event tracking
- Screen tracking with React Navigation
- Push notifications with APNs
- In-app messaging with event listeners
- Profile and device attributes
Running the example:
# Install dependencies
cd example
npm install
# iOS
cd ios && pod install && cd ..
npx react-native run-ios
# Android
npx react-native run-androidAPI Reference
Core SDK
Zixflow.initialize(config: ZixflowConfig): void
Initialize the SDK with configuration.
Zixflow.initialize({
apiKey: 'YOUR_API_KEY',
});Zixflow.identify(params: { userId: string; traits?: object }): void
Identify a user with optional traits.
Zixflow.identify({
userId: 'user-123',
traits: { email: '[email protected]' }
});Zixflow.clearIdentify(): void
Clear the current user's identity.
Zixflow.clearIdentify();Zixflow.track(name: string, properties?: object | Map<string, any>): void
Track a custom event.
Zixflow.track('button_clicked', { button_name: 'signup' });Zixflow.screen(name: string, properties?: object): void
Track a screen view.
Zixflow.screen('HomeScreen');Zixflow.setProfileAttributes(attributes: object): void
Set attributes on the user profile.
Zixflow.setProfileAttributes({ plan: 'premium' });Zixflow.setDeviceAttributes(attributes: object): void
Set attributes on the current device.
Zixflow.setDeviceAttributes({ app_version: '2.0.0' });Push Messaging
Zixflow.pushMessaging.showPromptForPushNotifications(options): Promise<ZixflowPushPermissionStatus>
Request push notification permission.
const status = await Zixflow.pushMessaging.showPromptForPushNotifications({
ios: { sound: true, badge: true }
});In-App Messaging
Zixflow.inAppMessaging.registerEventsListener(callback): EventSubscription
Register a listener for in-app message events.
const listener = Zixflow.inAppMessaging.registerEventsListener((event) => {
console.log('In-app event:', event);
});
// Remove listener
listener.remove();Zixflow.inAppMessaging.dismissMessage(): void
Dismiss the currently displayed in-app message.
Zixflow.inAppMessaging.dismissMessage();Types
ZixflowConfig
Configuration object for SDK initialization.
interface ZixflowConfig {
apiKey: string;
logLevel?: ZixflowLogLevel;
inApp?: {
};
autoTrackDeviceAttributes?: boolean;
trackApplicationLifecycleEvents?: boolean;
autoTrackScreenViews?: boolean;
trackingApiUrl?: string;
}ZixflowLogLevel
Log level enum.
enum ZixflowLogLev