zixflow-reactnative 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/README.md +2224 -322
  2. package/android/build.gradle +18 -1
  3. package/android/consumer-rules.pro +3 -2
  4. package/android/gradle.properties +1 -1
  5. package/android/src/main/java/com/zixflow/reactnative/sdk/NativeZixflowModule.kt +69 -24
  6. package/android/src/main/java/com/zixflow/reactnative/sdk/ZixflowReactNativePackage.kt +25 -1
  7. package/android/src/main/java/com/zixflow/reactnative/sdk/constant/Keys.kt +19 -3
  8. package/android/src/main/java/com/zixflow/reactnative/sdk/geofence/NativeGeofenceModule.kt +65 -0
  9. package/android/src/main/java/com/zixflow/reactnative/sdk/liveactivities/NativeLiveActivitiesModule.kt +310 -0
  10. package/android/src/main/java/com/zixflow/reactnative/sdk/logging/NativeZixflowLoggingModule.kt +2 -2
  11. package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginapp/NativeMessagingInAppModule.kt +149 -10
  12. package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginapp/ReactInboxEventListener.kt +99 -0
  13. package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/NotificationInboxBellViewManager.kt +38 -0
  14. package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/NotificationInboxViewManager.kt +30 -0
  15. package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/ReactComposeHostView.kt +96 -0
  16. package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/ReactNotificationInboxBellView.kt +48 -0
  17. package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/ReactNotificationInboxView.kt +17 -0
  18. package/android/src/main/java/com/zixflow/reactnative/sdk/messagingpush/NativeMessagingPushModule.kt +11 -1
  19. package/android/src/main/res/values/zixflow_config.xml +1 -1
  20. package/android/zixflow-core.gradle +17 -7
  21. package/docs/cocoapods-deployment-target-normalization.md +139 -0
  22. package/ios/cocoapods_deployment_target.rb +432 -0
  23. package/ios/wrappers/NativeZixflow.mm +37 -0
  24. package/ios/wrappers/NativeZixflow.swift +135 -1
  25. package/ios/wrappers/ZixflowReactNativeDeepLinkRequestStore.swift +123 -0
  26. package/ios/wrappers/ZixflowReactNativeDeepLinkRouter.swift +312 -0
  27. package/ios/wrappers/geofence/NativeGeofence.mm +46 -0
  28. package/ios/wrappers/geofence/NativeGeofence.swift +27 -0
  29. package/ios/wrappers/inapp/NativeMessagingInApp.mm +22 -0
  30. package/ios/wrappers/inapp/NativeMessagingInApp.swift +90 -0
  31. package/ios/wrappers/inbox/InboxHostContainment.swift +40 -0
  32. package/ios/wrappers/inbox/RCTNotificationInboxBellNative.h +12 -0
  33. package/ios/wrappers/inbox/RCTNotificationInboxBellNative.mm +98 -0
  34. package/ios/wrappers/inbox/RCTNotificationInboxViewNative.h +12 -0
  35. package/ios/wrappers/inbox/RCTNotificationInboxViewNative.mm +78 -0
  36. package/ios/wrappers/inbox/ReactInboxEventListener.swift +76 -0
  37. package/ios/wrappers/inbox/ReactNotificationInboxBellView.h +22 -0
  38. package/ios/wrappers/inbox/ReactNotificationInboxBellView.swift +109 -0
  39. package/ios/wrappers/inbox/ReactNotificationInboxView.h +22 -0
  40. package/ios/wrappers/inbox/ReactNotificationInboxView.swift +69 -0
  41. package/ios/wrappers/liveactivities/NativeLiveActivities.mm +83 -0
  42. package/ios/wrappers/liveactivities/NativeLiveActivities.swift +390 -0
  43. package/ios/wrappers/location/NativeLocation.swift +7 -5
  44. package/ios/wrappers/utils/ZixflowConfigUtils.swift +5 -9
  45. package/ios/wrappers/utils/ZixflowConstants.swift +4 -0
  46. package/ios/wrappers/zixflow_reactnative.h +6 -0
  47. package/lib/commonjs/components/NotificationInboxBellView.js +49 -0
  48. package/lib/commonjs/components/NotificationInboxBellView.js.map +1 -0
  49. package/lib/commonjs/components/NotificationInboxView.js +36 -0
  50. package/lib/commonjs/components/NotificationInboxView.js.map +1 -0
  51. package/lib/commonjs/components/index.js +14 -0
  52. package/lib/commonjs/components/index.js.map +1 -1
  53. package/lib/commonjs/index.js +81 -4
  54. package/lib/commonjs/index.js.map +1 -1
  55. package/lib/commonjs/notification-inbox.js +1 -0
  56. package/lib/commonjs/notification-inbox.js.map +1 -1
  57. package/lib/commonjs/specs/components/NotificationInboxBellNativeComponent.ts +24 -0
  58. package/lib/commonjs/specs/components/NotificationInboxViewNativeComponent.ts +22 -0
  59. package/lib/commonjs/specs/modules/NativeZixflow.js.map +1 -1
  60. package/lib/commonjs/specs/modules/NativeZixflowGeofence.js +15 -0
  61. package/lib/commonjs/specs/modules/NativeZixflowGeofence.js.map +1 -0
  62. package/lib/commonjs/specs/modules/NativeZixflowLiveActivities.js +23 -0
  63. package/lib/commonjs/specs/modules/NativeZixflowLiveActivities.js.map +1 -0
  64. package/lib/commonjs/specs/modules/NativeZixflowMessagingInApp.js +3 -1
  65. package/lib/commonjs/specs/modules/NativeZixflowMessagingInApp.js.map +1 -1
  66. package/lib/commonjs/specs/modules/NativeZixflowMessagingPush.js +3 -1
  67. package/lib/commonjs/specs/modules/NativeZixflowMessagingPush.js.map +1 -1
  68. package/lib/commonjs/types/data-pipelines.js +15 -15
  69. package/lib/commonjs/types/data-pipelines.js.map +1 -1
  70. package/lib/commonjs/types/in-app.js +24 -1
  71. package/lib/commonjs/types/in-app.js.map +1 -1
  72. package/lib/commonjs/types/inbox.js +79 -0
  73. package/lib/commonjs/types/inbox.js.map +1 -0
  74. package/lib/commonjs/types/index.js +22 -0
  75. package/lib/commonjs/types/index.js.map +1 -1
  76. package/lib/commonjs/types/live-activities.js +85 -0
  77. package/lib/commonjs/types/live-activities.js.map +1 -0
  78. package/lib/commonjs/utils/param-validation.js +77 -2
  79. package/lib/commonjs/utils/param-validation.js.map +1 -1
  80. package/lib/commonjs/zixflow-cdp.js +101 -11
  81. package/lib/commonjs/zixflow-cdp.js.map +1 -1
  82. package/lib/commonjs/zixflow-geofence.js +55 -0
  83. package/lib/commonjs/zixflow-geofence.js.map +1 -0
  84. package/lib/commonjs/zixflow-inapp.js +120 -0
  85. package/lib/commonjs/zixflow-inapp.js.map +1 -1
  86. package/lib/commonjs/zixflow-liveactivities.js +85 -0
  87. package/lib/commonjs/zixflow-liveactivities.js.map +1 -0
  88. package/lib/commonjs/zixflow.js.map +1 -1
  89. package/lib/module/components/NotificationInboxBellView.js +44 -0
  90. package/lib/module/components/NotificationInboxBellView.js.map +1 -0
  91. package/lib/module/components/NotificationInboxView.js +31 -0
  92. package/lib/module/components/NotificationInboxView.js.map +1 -0
  93. package/lib/module/components/index.js +5 -0
  94. package/lib/module/components/index.js.map +1 -1
  95. package/lib/module/index.js +8 -3
  96. package/lib/module/index.js.map +1 -1
  97. package/lib/module/notification-inbox.js +1 -1
  98. package/lib/module/notification-inbox.js.map +1 -1
  99. package/lib/module/specs/components/NotificationInboxBellNativeComponent.ts +24 -0
  100. package/lib/module/specs/components/NotificationInboxViewNativeComponent.ts +22 -0
  101. package/lib/module/specs/modules/NativeZixflow.js.map +1 -1
  102. package/lib/module/specs/modules/NativeZixflowGeofence.js +13 -0
  103. package/lib/module/specs/modules/NativeZixflowGeofence.js.map +1 -0
  104. package/lib/module/specs/modules/NativeZixflowLiveActivities.js +21 -0
  105. package/lib/module/specs/modules/NativeZixflowLiveActivities.js.map +1 -0
  106. package/lib/module/specs/modules/NativeZixflowMessagingInApp.js +3 -1
  107. package/lib/module/specs/modules/NativeZixflowMessagingInApp.js.map +1 -1
  108. package/lib/module/specs/modules/NativeZixflowMessagingPush.js +3 -1
  109. package/lib/module/specs/modules/NativeZixflowMessagingPush.js.map +1 -1
  110. package/lib/module/types/data-pipelines.js +15 -15
  111. package/lib/module/types/data-pipelines.js.map +1 -1
  112. package/lib/module/types/in-app.js +24 -0
  113. package/lib/module/types/in-app.js.map +1 -1
  114. package/lib/module/types/inbox.js +75 -0
  115. package/lib/module/types/inbox.js.map +1 -0
  116. package/lib/module/types/index.js +2 -0
  117. package/lib/module/types/index.js.map +1 -1
  118. package/lib/module/types/live-activities.js +88 -0
  119. package/lib/module/types/live-activities.js.map +1 -0
  120. package/lib/module/utils/param-validation.js +77 -2
  121. package/lib/module/utils/param-validation.js.map +1 -1
  122. package/lib/module/zixflow-cdp.js +101 -11
  123. package/lib/module/zixflow-cdp.js.map +1 -1
  124. package/lib/module/zixflow-geofence.js +50 -0
  125. package/lib/module/zixflow-geofence.js.map +1 -0
  126. package/lib/module/zixflow-inapp.js +99 -1
  127. package/lib/module/zixflow-inapp.js.map +1 -1
  128. package/lib/module/zixflow-liveactivities.js +80 -0
  129. package/lib/module/zixflow-liveactivities.js.map +1 -0
  130. package/lib/module/zixflow.js +0 -6
  131. package/lib/module/zixflow.js.map +1 -1
  132. package/lib/typescript/commonjs/components/NotificationInboxBellView.d.ts +39 -0
  133. package/lib/typescript/commonjs/components/NotificationInboxBellView.d.ts.map +1 -0
  134. package/lib/typescript/commonjs/components/NotificationInboxView.d.ts +25 -0
  135. package/lib/typescript/commonjs/components/NotificationInboxView.d.ts.map +1 -0
  136. package/lib/typescript/commonjs/components/index.d.ts +4 -0
  137. package/lib/typescript/commonjs/components/index.d.ts.map +1 -1
  138. package/lib/typescript/commonjs/index.d.ts +8 -1
  139. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  140. package/lib/typescript/commonjs/notification-inbox.d.ts +5 -0
  141. package/lib/typescript/commonjs/notification-inbox.d.ts.map +1 -1
  142. package/lib/typescript/commonjs/specs/components/NotificationInboxBellNativeComponent.d.ts +13 -0
  143. package/lib/typescript/commonjs/specs/components/NotificationInboxBellNativeComponent.d.ts.map +1 -0
  144. package/lib/typescript/commonjs/specs/components/NotificationInboxViewNativeComponent.d.ts +12 -0
  145. package/lib/typescript/commonjs/specs/components/NotificationInboxViewNativeComponent.d.ts.map +1 -0
  146. package/lib/typescript/commonjs/specs/modules/NativeZixflow.d.ts +6 -1
  147. package/lib/typescript/commonjs/specs/modules/NativeZixflow.d.ts.map +1 -1
  148. package/lib/typescript/commonjs/specs/modules/NativeZixflowGeofence.d.ts +13 -0
  149. package/lib/typescript/commonjs/specs/modules/NativeZixflowGeofence.d.ts.map +1 -0
  150. package/lib/typescript/commonjs/specs/modules/NativeZixflowLiveActivities.d.ts +31 -0
  151. package/lib/typescript/commonjs/specs/modules/NativeZixflowLiveActivities.d.ts.map +1 -0
  152. package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingInApp.d.ts +5 -1
  153. package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingInApp.d.ts.map +1 -1
  154. package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingPush.d.ts +1 -1
  155. package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingPush.d.ts.map +1 -1
  156. package/lib/typescript/commonjs/types/data-pipelines.d.ts +54 -18
  157. package/lib/typescript/commonjs/types/data-pipelines.d.ts.map +1 -1
  158. package/lib/typescript/commonjs/types/in-app.d.ts +22 -0
  159. package/lib/typescript/commonjs/types/in-app.d.ts.map +1 -1
  160. package/lib/typescript/commonjs/types/inbox.d.ts +97 -0
  161. package/lib/typescript/commonjs/types/inbox.d.ts.map +1 -0
  162. package/lib/typescript/commonjs/types/index.d.ts +2 -0
  163. package/lib/typescript/commonjs/types/index.d.ts.map +1 -1
  164. package/lib/typescript/commonjs/types/live-activities.d.ts +161 -0
  165. package/lib/typescript/commonjs/types/live-activities.d.ts.map +1 -0
  166. package/lib/typescript/commonjs/utils/param-validation.d.ts +7 -0
  167. package/lib/typescript/commonjs/utils/param-validation.d.ts.map +1 -1
  168. package/lib/typescript/commonjs/zixflow-cdp.d.ts +38 -0
  169. package/lib/typescript/commonjs/zixflow-cdp.d.ts.map +1 -1
  170. package/lib/typescript/commonjs/zixflow-geofence.d.ts +36 -0
  171. package/lib/typescript/commonjs/zixflow-geofence.d.ts.map +1 -0
  172. package/lib/typescript/commonjs/zixflow-inapp.d.ts +36 -2
  173. package/lib/typescript/commonjs/zixflow-inapp.d.ts.map +1 -1
  174. package/lib/typescript/commonjs/zixflow-liveactivities.d.ts +66 -0
  175. package/lib/typescript/commonjs/zixflow-liveactivities.d.ts.map +1 -0
  176. package/lib/typescript/commonjs/zixflow.d.ts +0 -5
  177. package/lib/typescript/commonjs/zixflow.d.ts.map +1 -1
  178. package/lib/typescript/module/components/NotificationInboxBellView.d.ts +39 -0
  179. package/lib/typescript/module/components/NotificationInboxBellView.d.ts.map +1 -0
  180. package/lib/typescript/module/components/NotificationInboxView.d.ts +25 -0
  181. package/lib/typescript/module/components/NotificationInboxView.d.ts.map +1 -0
  182. package/lib/typescript/module/components/index.d.ts +4 -0
  183. package/lib/typescript/module/components/index.d.ts.map +1 -1
  184. package/lib/typescript/module/index.d.ts +8 -1
  185. package/lib/typescript/module/index.d.ts.map +1 -1
  186. package/lib/typescript/module/notification-inbox.d.ts +5 -0
  187. package/lib/typescript/module/notification-inbox.d.ts.map +1 -1
  188. package/lib/typescript/module/specs/components/NotificationInboxBellNativeComponent.d.ts +13 -0
  189. package/lib/typescript/module/specs/components/NotificationInboxBellNativeComponent.d.ts.map +1 -0
  190. package/lib/typescript/module/specs/components/NotificationInboxViewNativeComponent.d.ts +12 -0
  191. package/lib/typescript/module/specs/components/NotificationInboxViewNativeComponent.d.ts.map +1 -0
  192. package/lib/typescript/module/specs/modules/NativeZixflow.d.ts +6 -1
  193. package/lib/typescript/module/specs/modules/NativeZixflow.d.ts.map +1 -1
  194. package/lib/typescript/module/specs/modules/NativeZixflowGeofence.d.ts +13 -0
  195. package/lib/typescript/module/specs/modules/NativeZixflowGeofence.d.ts.map +1 -0
  196. package/lib/typescript/module/specs/modules/NativeZixflowLiveActivities.d.ts +31 -0
  197. package/lib/typescript/module/specs/modules/NativeZixflowLiveActivities.d.ts.map +1 -0
  198. package/lib/typescript/module/specs/modules/NativeZixflowMessagingInApp.d.ts +5 -1
  199. package/lib/typescript/module/specs/modules/NativeZixflowMessagingInApp.d.ts.map +1 -1
  200. package/lib/typescript/module/specs/modules/NativeZixflowMessagingPush.d.ts +1 -1
  201. package/lib/typescript/module/specs/modules/NativeZixflowMessagingPush.d.ts.map +1 -1
  202. package/lib/typescript/module/types/data-pipelines.d.ts +54 -18
  203. package/lib/typescript/module/types/data-pipelines.d.ts.map +1 -1
  204. package/lib/typescript/module/types/in-app.d.ts +22 -0
  205. package/lib/typescript/module/types/in-app.d.ts.map +1 -1
  206. package/lib/typescript/module/types/inbox.d.ts +97 -0
  207. package/lib/typescript/module/types/inbox.d.ts.map +1 -0
  208. package/lib/typescript/module/types/index.d.ts +2 -0
  209. package/lib/typescript/module/types/index.d.ts.map +1 -1
  210. package/lib/typescript/module/types/live-activities.d.ts +161 -0
  211. package/lib/typescript/module/types/live-activities.d.ts.map +1 -0
  212. package/lib/typescript/module/utils/param-validation.d.ts +7 -0
  213. package/lib/typescript/module/utils/param-validation.d.ts.map +1 -1
  214. package/lib/typescript/module/zixflow-cdp.d.ts +38 -0
  215. package/lib/typescript/module/zixflow-cdp.d.ts.map +1 -1
  216. package/lib/typescript/module/zixflow-geofence.d.ts +36 -0
  217. package/lib/typescript/module/zixflow-geofence.d.ts.map +1 -0
  218. package/lib/typescript/module/zixflow-inapp.d.ts +36 -2
  219. package/lib/typescript/module/zixflow-inapp.d.ts.map +1 -1
  220. package/lib/typescript/module/zixflow-liveactivities.d.ts +66 -0
  221. package/lib/typescript/module/zixflow-liveactivities.d.ts.map +1 -0
  222. package/lib/typescript/module/zixflow.d.ts +0 -5
  223. package/lib/typescript/module/zixflow.d.ts.map +1 -1
  224. package/package.json +14 -5
  225. package/src/components/NotificationInboxBellView.tsx +55 -0
  226. package/src/components/NotificationInboxView.tsx +30 -0
  227. package/src/components/index.ts +6 -0
  228. package/src/index.ts +8 -3
  229. package/src/notification-inbox.ts +1 -1
  230. package/src/specs/components/NotificationInboxBellNativeComponent.ts +24 -0
  231. package/src/specs/components/NotificationInboxViewNativeComponent.ts +22 -0
  232. package/src/specs/modules/NativeZixflow.ts +9 -1
  233. package/src/specs/modules/NativeZixflowGeofence.ts +14 -0
  234. package/src/specs/modules/NativeZixflowLiveActivities.ts +39 -0
  235. package/src/specs/modules/NativeZixflowMessagingInApp.ts +12 -1
  236. package/src/specs/modules/NativeZixflowMessagingPush.ts +3 -1
  237. package/src/types/data-pipelines.ts +55 -19
  238. package/src/types/in-app.ts +23 -0
  239. package/src/types/inbox.ts +110 -0
  240. package/src/types/index.ts +2 -0
  241. package/src/types/live-activities.ts +170 -0
  242. package/src/utils/param-validation.ts +104 -1
  243. package/src/zixflow-cdp.ts +119 -13
  244. package/src/zixflow-geofence.ts +56 -0
  245. package/src/zixflow-inapp.ts +125 -2
  246. package/src/zixflow-liveactivities.ts +86 -0
  247. package/src/zixflow.ts +0 -6
  248. package/zixflow-reactnative-richpush.podspec +6 -3
  249. package/zixflow-reactnative.podspec +28 -2
package/README.md CHANGED
@@ -1,446 +1,2238 @@
1
- <p align="center">
2
- <a href="https://zixflow.com">
3
- <img src="https://zixflow.com/logo.svg" height="60">
4
- </a>
5
- </p>
1
+ # Zixflow React Native SDK - Integration Guide
6
2
 
7
- [![npm version](https://img.shields.io/npm/v/zixflow-reactnative.svg)](https://www.npmjs.com/package/zixflow-reactnative)
8
- [![npm downloads](https://img.shields.io/npm/dm/zixflow-reactnative)](https://www.npmjs.com/package/zixflow-reactnative)
9
- ![min Android SDK version is 21](https://img.shields.io/badge/min%20Android%20SDK-21-green)
10
- ![min iOS version is 13](https://img.shields.io/badge/min%20iOS%20version-13-blue)
11
- ![min Swift version is 5.3](https://img.shields.io/badge/min%20Swift%20version-5.3-orange)
12
- [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.0-4baaaa.svg)](CODE_OF_CONDUCT.md)
3
+ 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.
13
4
 
14
- # Zixflow React Native SDK
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Introduction](#introduction)
10
+ 2. [Requirements](#requirements)
11
+ 3. [Installation](#installation)
12
+ - [npm Installation](#npm-installation)
13
+ - [Yarn Installation](#yarn-installation)
14
+ 4. [iOS Setup](#ios-setup)
15
+ - [CocoaPods Integration](#cocoapods-integration)
16
+ - [Swift Package Manager Integration](#swift-package-manager-integration)
17
+ - [Push Notification Setup (APNs)](#push-notification-setup-apns)
18
+ - [Notification Service Extension](#notification-service-extension)
19
+ 5. [Android Setup](#android-setup)
20
+ - [Gradle Configuration](#gradle-configuration)
21
+ - [Firebase Cloud Messaging Setup](#firebase-cloud-messaging-setup)
22
+ 6. [Quick Start](#quick-start)
23
+ - [Basic Configuration](#basic-configuration)
24
+ - [SDK Initialization](#sdk-initialization)
25
+ 7. [Core Features](#core-features)
26
+ - [User Identification](#user-identification)
27
+ - [Event Tracking](#event-tracking)
28
+ - [Screen Tracking](#screen-tracking)
29
+ - [User Profile Attributes](#user-profile-attributes)
30
+ - [Device Attributes](#device-attributes)
31
+ - [Clearing User Identity](#clearing-user-identity)
32
+ 8. [Push Notifications](#push-notifications)
33
+ - [Requesting Permission](#requesting-permission)
34
+ - [Handling Push Notifications](#handling-push-notifications)
35
+ - [Device Token Registration](#device-token-registration)
36
+ 9. [Push Notification Tracking](#push-notification-tracking)
37
+ 10. [Location Tracking](#location-tracking)
38
+ 11. [Geofence Tracking](#geofence-tracking)
39
+ 12. [Live Activities](#-live-activities)
40
+ 13. [Notification Inbox](#notification-inbox)
41
+ 14. [Advanced Configuration](#advanced-configuration)
42
+ - [Log Levels](#log-levels)
43
+ - [Auto-Tracking Options](#auto-tracking-options)
44
+ - [Custom API Hosts](#custom-api-hosts)
45
+ 15. [Example Applications](#example-applications)
46
+ 16. [API Reference](#api-reference)
47
+
48
+ ---
49
+
50
+ ## Introduction
51
+
52
+ The **Zixflow React Native SDK** enables you to:
53
+
54
+ - **Identify users** and track their behavior across your app
55
+ - **Send targeted push notifications** via Apple Push Notification service (APNs) or Firebase Cloud Messaging (FCM)
56
+ - **Display in-app messages** to engage users at the right time
57
+ - **Track user location** to enable location-based messaging
58
+ - **Manage user profiles** with custom attributes
59
+ - **Track events and screen views** automatically or manually
60
+
61
+ The SDK is built on top of the native Zixflow iOS and Android SDKs, providing a unified TypeScript API for React Native applications.
62
+
63
+ ---
64
+
65
+ ## Requirements
66
+
67
+ ### React Native
68
+
69
+ - **React Native**: 0.60.0 or higher
70
+ - **React**: 16.8.0 or higher (for hooks support)
71
+
72
+ ### iOS
73
+
74
+ - **iOS**: 13.0 or higher
75
+ - **Xcode**: 14.0 or higher
76
+ - **Swift**: 5.3 or higher
77
+ - **CocoaPods**: 1.10.0 or higher (if using CocoaPods)
78
+
79
+ ### Android
80
+
81
+ - **Android**: API level 24 (Android 7.0) or higher
82
+ - **Kotlin**: 1.6.0 or higher
83
+ - **Gradle**: 7.0 or higher
84
+
85
+ ### TypeScript (Recommended)
86
+
87
+ - **TypeScript**: 4.0 or higher
88
+
89
+ ---
90
+
91
+ ## Installation
92
+
93
+ The Zixflow React Native SDK is available on **npm**. You can browse the package here:
94
+
95
+ **[npm - zixflow-reactnative](https://www.npmjs.com/package/zixflow-reactnative)**
96
+
97
+ ### npm Installation
98
+
99
+ Install the SDK using npm:
100
+
101
+ ```bash
102
+ npm install zixflow-reactnative
103
+ ```
104
+
105
+ ### Yarn Installation
106
+
107
+ Or install using Yarn:
108
+
109
+ ```bash
110
+ yarn add zixflow-reactnative
111
+ ```
112
+
113
+ After installation, proceed with platform-specific setup for iOS and Android.
114
+
115
+ ---
116
+
117
+ ## iOS Setup
118
+
119
+ ### CocoaPods Integration
120
+
121
+ 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.
122
+
123
+ 1. **Navigate to the iOS directory**:
124
+
125
+ ```bash
126
+ cd ios
127
+ ```
128
+
129
+ 2. **Install CocoaPods dependencies**:
130
+
131
+ ```bash
132
+ pod install
133
+ ```
134
+
135
+ 3. **Open the workspace in Xcode**:
136
+
137
+ ```bash
138
+ open YourApp.xcworkspace
139
+ ```
140
+
141
+ The SDK will automatically include the necessary Zixflow iOS modules:
142
+ - `ZixflowCommon`
143
+ - `ZixflowDataPipelines`
144
+ - `ZixflowMessagingPush`
145
+ - `ZixflowMessagingPushAPN` (for APNs)
146
+ - `ZixflowMessagingInApp`
147
+
148
+ ### Swift Package Manager Integration
149
+
150
+ If you prefer **Swift Package Manager (SPM)**, you can configure your project to use the Zixflow iOS SDK directly:
151
+
152
+ 1. **Open your project in Xcode**
153
+ 2. **Go to File > Add Package Dependencies**
154
+ 3. **Enter the repository URL**:
155
+ ```
156
+ https://github.com/zixflow/zixflow-ios.git
157
+ ```
158
+ 4. **Select the version**: Use `1.0.0` or higher
159
+ 5. **Add the following modules** to your app target:
160
+ - `Zixflow` (umbrella module)
161
+ - `ZixflowDataPipelines`
162
+ - `ZixflowMessagingPushAPN`
163
+ - `ZixflowMessagingInApp`
164
+
165
+ > **Note**: The example app uses SPM for the native iOS SDK integration. See `example/ios/Podfile` for reference.
166
+
167
+ ### Push Notification Setup (APNs)
168
+
169
+ To enable **Apple Push Notifications (APNs)**:
170
+
171
+ 1. **Enable Push Notifications capability** in Xcode:
172
+ - Select your app target
173
+ - Go to **Signing & Capabilities**
174
+ - Click **+ Capability** and add **Push Notifications**
175
+
176
+ 2. **Enable Background Modes**:
177
+ - Add **Background Modes** capability
178
+ - Enable **Remote notifications**
179
+
180
+ 3. **Configure APNs certificates** in your Apple Developer account and upload them to Zixflow dashboard.
181
+
182
+ ### Notification Service Extension
183
+
184
+ To support **rich push notifications** (images, videos, action buttons), you need to add a **Notification Service Extension**:
185
+
186
+ 1. **Create a Notification Service Extension** in Xcode:
187
+ - File > New > Target > Notification Service Extension
188
+ - Name it `NotificationServiceExtension`
189
+
190
+ 2. **Add Zixflow modules to the extension** in your `Podfile`:
191
+
192
+ ```ruby
193
+ target 'NotificationServiceExtension' do
194
+ pod "ZixflowMessagingPushAPN", "~> 1.0"
195
+ pod "ZixflowMessagingPush", "~> 1.0"
196
+ pod "ZixflowDataPipelines", "~> 1.0"
197
+ pod "ZixflowCommon", "~> 1.0"
198
+ pod "AnalyticsSwiftZixflow", "1.7.3+zixflow.1"
199
+ end
200
+ ```
201
+
202
+ 3. **Update `NotificationService.swift`**:
203
+
204
+ ```swift
205
+ import UserNotifications
206
+ import ZixflowMessagingPushAPN
207
+
208
+ class NotificationService: UNNotificationServiceExtension {
209
+ var contentHandler: ((UNNotificationContent) -> Void)?
210
+ var bestAttemptContent: UNMutableNotificationContent?
211
+
212
+ override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
213
+ self.contentHandler = contentHandler
214
+ bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
215
+
216
+ // Use Zixflow to handle rich push
217
+ MessagingPushAPN.didReceive(request, withContentHandler: contentHandler)
218
+ }
219
+
220
+ override func serviceExtensionTimeWillExpire() {
221
+ if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
222
+ contentHandler(bestAttemptContent)
223
+ }
224
+ }
225
+ }
226
+ ```
227
+
228
+ 4. **Run `pod install`** again to install extension dependencies.
229
+
230
+ ---
231
+
232
+ ## Android Setup
233
+
234
+ ### Gradle Configuration
235
+
236
+ The React Native auto-linking will handle most of the Android setup. However, you need to ensure the following:
237
+
238
+ 1. **Set minimum SDK version** in `android/build.gradle`:
239
+
240
+ ```gradle
241
+ buildscript {
242
+ ext {
243
+ minSdkVersion = 24
244
+ compileSdkVersion = 34
245
+ targetSdkVersion = 34
246
+ }
247
+ }
248
+ ```
249
+
250
+ 2. **Add Maven repositories** in `android/build.gradle`:
251
+
252
+ ```gradle
253
+ allprojects {
254
+ repositories {
255
+ google()
256
+ mavenCentral()
257
+ maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
258
+ }
259
+ }
260
+ ```
261
+
262
+ The Zixflow Android SDK will be automatically included via the React Native module.
263
+
264
+ ### Firebase Cloud Messaging Setup
265
+
266
+ To enable **Firebase Cloud Messaging (FCM)** for push notifications on Android:
267
+
268
+ 1. **Add Firebase to your project**:
269
+ - Go to [Firebase Console](https://console.firebase.google.com/)
270
+ - Add your Android app
271
+ - Download `google-services.json` and place it in `android/app/`
272
+
273
+ 2. **Add Google Services plugin** in `android/build.gradle`:
274
+
275
+ ```gradle
276
+ buildscript {
277
+ dependencies {
278
+ classpath 'com.google.gms:google-services:4.4.2'
279
+ }
280
+ }
281
+ ```
282
+
283
+ 3. **Apply the plugin** in `android/app/build.gradle`:
284
+
285
+ ```gradle
286
+ apply plugin: 'com.google.gms.google-services'
287
+ ```
288
+
289
+ 4. **Configure FCM in the SDK** (shown in the initialization section below).
290
+
291
+ ---
292
+
293
+ ## Quick Start
294
+
295
+ ### Basic Configuration
296
+
297
+ The SDK is configured using a `ZixflowConfig` object with several options:
298
+
299
+ ```typescript
300
+ import { Zixflow, ZixflowConfig, ZixflowLogLevel } from 'zixflow-reactnative';
301
+
302
+ const config: ZixflowConfig = {
303
+ apiKey: 'YOUR_API_KEY',
304
+ logLevel: ZixflowLogLevel.debug,
305
+ inApp: {
306
+ },
307
+ autoTrackDeviceAttributes: true,
308
+ trackApplicationLifecycleEvents: true,
309
+ };
310
+ ```
311
+
312
+ **Configuration Options**:
313
+
314
+ | Option | Type | Required | Description |
315
+ |--------|------|----------|-------------|
316
+ | `apiKey` | string | Yes | Your Zixflow API key |
317
+ | `logLevel` | `ZixflowLogLevel` | No | Logging level (debug, info, error, none) |
318
+ | `inApp` | object | No | Enable in-app messaging (use empty object: {}) |
319
+ | `autoTrackDeviceAttributes` | boolean | No | Automatically track device info |
320
+ | `trackApplicationLifecycleEvents` | boolean | No | Automatically track app lifecycle |
321
+
322
+ ### SDK Initialization
323
+
324
+ Initialize the SDK in your `App.tsx` or main component using `useEffect`:
325
+
326
+ ```typescript
327
+ import React, { useEffect } from 'react';
328
+ import { Zixflow, ZixflowConfig, ZixflowLogLevel } from 'zixflow-reactnative';
329
+
330
+ export default function App() {
331
+ useEffect(() => {
332
+ // Configure the SDK
333
+ const config: ZixflowConfig = {
334
+ apiKey: 'YOUR_API_KEY',
335
+ logLevel: ZixflowLogLevel.debug,
336
+ inApp: {
337
+ },
338
+ autoTrackDeviceAttributes: true,
339
+ trackApplicationLifecycleEvents: true,
340
+ };
341
+
342
+ // Initialize the SDK
343
+ Zixflow.initialize(config);
344
+
345
+ console.log('Zixflow SDK initialized');
346
+ }, []);
347
+
348
+ return (
349
+ // Your app UI
350
+ );
351
+ }
352
+ ```
353
+
354
+ > **Important**: Initialize the SDK as early as possible in your app's lifecycle, ideally in the root component's `useEffect`.
355
+
356
+ ---
357
+
358
+ ## Core Features
359
+
360
+ ### User Identification
361
+
362
+ Identify users to track their behavior across sessions and devices:
363
+
364
+ ```typescript
365
+ import { Zixflow } from 'zixflow-reactnative';
366
+
367
+ // Identify user with ID only
368
+ Zixflow.identify({
369
+ userId: 'user-123'
370
+ });
371
+
372
+ // Identify user with traits
373
+ Zixflow.identify({
374
+ userId: 'user-123',
375
+ traits: {
376
+ email: 'user@example.com',
377
+ firstName: 'John',
378
+ lastName: 'Doe',
379
+ plan: 'premium'
380
+ }
381
+ });
382
+ ```
383
+
384
+ **When to identify users**:
385
+ - After successful login
386
+ - When user information becomes available
387
+ - After account creation
388
+
389
+ ### Event Tracking
390
+
391
+ Track custom events to understand user behavior:
392
+
393
+ ```typescript
394
+ import { Zixflow } from 'zixflow-reactnative';
395
+
396
+ // Track event without properties
397
+ Zixflow.track('button_clicked');
398
+
399
+ // Track event with properties
400
+ Zixflow.track('product_viewed', {
401
+ product_id: '12345',
402
+ product_name: 'Premium Plan',
403
+ category: 'subscription',
404
+ price: 29.99
405
+ });
406
+
407
+ // Track with Map (alternative syntax)
408
+ const properties = new Map<string, any>();
409
+ properties.set('item_count', 3);
410
+ properties.set('total_amount', 89.97);
411
+ Zixflow.track('checkout_completed', properties);
412
+ ```
413
+
414
+ **Common events to track**:
415
+ - User actions (button clicks, form submissions)
416
+ - E-commerce events (product views, purchases)
417
+ - Content interactions (article reads, video plays)
418
+ - Feature usage
419
+
420
+ ### Screen Tracking
421
+
422
+ Track screen views to understand user navigation:
423
+
424
+ ```typescript
425
+ import { Zixflow } from 'zixflow-reactnative';
426
+
427
+ // Track screen view
428
+ Zixflow.screen('HomeScreen');
429
+
430
+ // Track screen with properties
431
+ Zixflow.screen('ProductDetailScreen', {
432
+ product_id: '12345',
433
+ category: 'electronics'
434
+ });
435
+ ```
436
+
437
+ **Automatic screen tracking** with React Navigation:
438
+
439
+ ```typescript
440
+ import { NavigationContainer, NavigationContainerRef } from '@react-navigation/native';
441
+ import { Zixflow } from 'zixflow-reactnative';
442
+ import React, { useRef } from 'react';
443
+
444
+ export default function App() {
445
+ const navigationRef = useRef<NavigationContainerRef>(null);
446
+ const routeNameRef = useRef<string>();
447
+
448
+ return (
449
+ <NavigationContainer
450
+ ref={navigationRef}
451
+ onReady={() => {
452
+ routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name;
453
+ }}
454
+ onStateChange={async () => {
455
+ const previousRouteName = routeNameRef.current;
456
+ const currentRouteName = navigationRef.current?.getCurrentRoute()?.name;
457
+
458
+ if (previousRouteName !== currentRouteName && currentRouteName) {
459
+ // Track screen change
460
+ Zixflow.screen(currentRouteName);
461
+ }
462
+
463
+ // Save current route name
464
+ routeNameRef.current = currentRouteName;
465
+ }}
466
+ >
467
+ {/* Your navigation setup */}
468
+ </NavigationContainer>
469
+ );
470
+ }
471
+ ```
472
+
473
+ ### User Profile Attributes
474
+
475
+ Set custom attributes on user profiles:
476
+
477
+ ```typescript
478
+ import { Zixflow } from 'zixflow-reactnative';
479
+
480
+ // Set profile attributes
481
+ Zixflow.setProfileAttributes({
482
+ plan: 'premium',
483
+ subscription_status: 'active',
484
+ last_login: new Date().toISOString(),
485
+ preferences: {
486
+ newsletter: true,
487
+ notifications: true
488
+ }
489
+ });
490
+ ```
491
+
492
+ ### Device Attributes
493
+
494
+ Set custom attributes on the current device:
495
+
496
+ ```typescript
497
+ import { Zixflow } from 'zixflow-reactnative';
498
+
499
+ // Set device attributes
500
+ Zixflow.setDeviceAttributes({
501
+ app_version: '2.1.0',
502
+ build_number: '421',
503
+ theme: 'dark',
504
+ language_preference: 'en-US'
505
+ });
506
+ ```
507
+
508
+ ### Clearing User Identity
509
+
510
+ Clear user identity when users log out:
511
+
512
+ ```typescript
513
+ import { Zixflow } from 'zixflow-reactnative';
514
+
515
+ // Clear identify on logout
516
+ const handleLogout = async () => {
517
+ // Clear Zixflow identity
518
+ Zixflow.clearIdentify();
519
+
520
+ // Perform other logout actions
521
+ // ...
522
+ };
523
+ ```
524
+
525
+ ---
526
+
527
+ ## Push Notifications
528
+
529
+ Complete guide to implementing push notifications in React Native with Zixflow using Apple Push Notifications (APNs) or Firebase Cloud Messaging (FCM).
530
+
531
+ > ** Track your campaigns:** The SDK automatically tracks delivery, opens, and clicks. For advanced tracking customization and implementation details, see [Push Notification Tracking](#push-notification-tracking).
532
+
533
+ ### Prerequisites
534
+
535
+ Before implementing push notifications:
536
+
537
+ 1. **Configure push credentials in Zixflow dashboard** - Add APNs certificates or FCM Server Key
538
+ 2. **Complete iOS/Android native setup** - Ensure native dependencies are installed
539
+ 3. **Device tokens must be associated with users** - Call `identify()` before sending notifications
540
+
541
+ **Important Limitation**: The Zixflow React Native SDK currently supports deep links and images in push notifications. Custom action buttons require additional native code.
542
+
543
+ ---
544
+
545
+ ### Platform-Specific Requirements
546
+
547
+ #### iOS Requirements
548
+
549
+ - **APNs or FCM**: Choose either Apple Push Notification service or Firebase Cloud Messaging
550
+ - **Xcode Capabilities**: Push Notifications and Background Modes
551
+ - **Notification Service Extension**: Required for rich push (images, videos)
552
+ - **Physical Device**: iOS Simulator cannot receive push notifications
553
+
554
+ #### Android Requirements
555
+
556
+ - **Firebase Project**: Required for FCM integration
557
+ - **google-services.json**: Must be in `android/app/` directory
558
+ - **Minimum API Level 24**: Android 7.0 or higher
559
+ - **POST_NOTIFICATIONS Permission**: Required for Android 13+ (API 33+)
560
+
561
+ ---
562
+
563
+ ### iOS Setup
564
+
565
+ You can use either **APNs (Apple Push Notification service)** or **FCM (Firebase Cloud Messaging)** on iOS.
566
+
567
+ #### Step 1: Enable Push Capabilities in Xcode
568
+
569
+ 1. Open your project's `.xcworkspace` file in Xcode
570
+ 2. Select your app target
571
+ 3. Go to **Signing & Capabilities** tab
572
+ 4. Click **+ Capability** → Add **Push Notifications**
573
+ 5. Click **+ Capability** → Add **Background Modes**
574
+ 6. Enable **Remote notifications** under Background Modes
575
+
576
+ #### Step 2: Choose APNs or FCM
577
+
578
+ **Option A: APNs (Recommended for iOS-only apps)**
579
+
580
+ Update your `ios/Podfile`:
581
+
582
+ ```ruby
583
+ require_relative '../node_modules/react-native/scripts/react_native_pods'
584
+ require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
585
+
586
+ platform :ios, '13.0'
587
+
588
+ target 'YourApp' do
589
+ config = use_native_modules!
590
+
591
+ use_react_native!(:path => config[:reactNativePath])
592
+
593
+ # Add Zixflow with APNs support
594
+ pod 'zixflow-reactnative/apn', :path => '../node_modules/zixflow-reactnative'
595
+
596
+ # Your other dependencies...
597
+ end
598
+ ```
599
+
600
+ **Option B: FCM (For cross-platform Firebase apps)**
601
+
602
+ Update your `ios/Podfile` with static linkage:
603
+
604
+ ```ruby
605
+ require_relative '../node_modules/react-native/scripts/react_native_pods'
606
+ require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
607
+
608
+ platform :ios, '13.0'
609
+
610
+ # Required for FCM
611
+ use_frameworks! :linkage => :static
612
+
613
+ target 'YourApp' do
614
+ config = use_native_modules!
615
+
616
+ use_react_native!(:path => config[:reactNativePath])
617
+
618
+ # Add Zixflow with FCM support
619
+ pod 'zixflow-reactnative/fcm', :path => '../node_modules/zixflow-reactnative'
620
+
621
+ # Your other dependencies...
622
+ end
623
+ ```
624
+
625
+ **Install dependencies:**
626
+
627
+ ```bash
628
+ cd ios
629
+ pod install
630
+ cd ..
631
+ ```
632
+
633
+ #### Step 3: Configure AppDelegate (Swift - Recommended)
634
+
635
+ For modern Swift-based React Native apps with APNs:
636
+
637
+ **AppDelegate.swift:**
638
+
639
+ ```swift
640
+ import UIKit
641
+ import ZixflowMessagingPushAPN
642
+
643
+ @main
644
+ class AppDelegateWithZixflowIntegration: ZixflowAppDelegateWrapper<AppDelegate> {}
645
+
646
+ class AppDelegate: NSObject, UIApplicationDelegate {
647
+
648
+ func application(
649
+ _ application: UIApplication,
650
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
651
+ ) -> Bool {
652
+ // Set notification delegate
653
+ UNUserNotificationCenter.current().delegate = self
654
+
655
+ // Initialize Zixflow push messaging (APNs)
656
+ MessagingPushAPN.initialize(
657
+ withConfig: MessagingPushConfigBuilder()
658
+ .build()
659
+ )
660
+
661
+ return true
662
+ }
663
+ }
664
+
665
+ extension AppDelegate: UNUserNotificationCenterDelegate {
666
+ // Show notifications when app is in foreground
667
+ func userNotificationCenter(
668
+ _ center: UNUserNotificationCenter,
669
+ willPresent notification: UNNotification,
670
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
671
+ ) {
672
+ completionHandler([.banner, .list, .badge, .sound])
673
+ }
674
+ }
675
+ ```
676
+
677
+ **For FCM**, import `ZixflowMessagingPushFCM` instead:
678
+
679
+ ```swift
680
+ import ZixflowMessagingPushFCM
681
+
682
+ // Initialize with FCM
683
+ MessagingPushFCM.initialize(
684
+ withConfig: MessagingPushConfigBuilder()
685
+ .build()
686
+ )
687
+ ```
688
+
689
+ #### Step 4: Configure AppDelegate (Objective-C)
690
+
691
+ If your React Native app uses Objective-C, create a Swift bridge:
692
+
693
+ **Create `MyAppPushNotificationsHandler.swift`:**
694
+
695
+ ```swift
696
+ import Foundation
697
+ import ZixflowMessagingPushAPN
698
+
699
+ @objc
700
+ public class MyAppPushNotificationsHandler: NSObject {
701
+
702
+ @objc(setupZixflowClickHandling)
703
+ public func setupZixflowClickHandling() {
704
+ MessagingPushAPN.initialize(
705
+ withConfig: MessagingPushConfigBuilder().build()
706
+ )
707
+ }
708
+
709
+ @objc(application:deviceToken:)
710
+ public func application(
711
+ _ application: UIApplication,
712
+ didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
713
+ ) {
714
+ MessagingPush.shared.application(
715
+ application,
716
+ didRegisterForRemoteNotificationsWithDeviceToken: deviceToken
717
+ )
718
+ }
719
+
720
+ @objc(application:error:)
721
+ public func application(
722
+ _ application: UIApplication,
723
+ didFailToRegisterForRemoteNotificationsWithError error: Error
724
+ ) {
725
+ MessagingPush.shared.application(
726
+ application,
727
+ didFailToRegisterForRemoteNotificationsWithError: error
728
+ )
729
+ }
730
+ }
731
+ ```
732
+
733
+ **Update `AppDelegate.mm`:**
734
+
735
+ ```objc
736
+ #import "YourApp-Swift.h"
737
+
738
+ @implementation AppDelegate
739
+
740
+ MyAppPushNotificationsHandler* pnHandlerObj;
741
+
742
+ - (BOOL)application:(UIApplication *)application
743
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
744
+ // ... existing initialization code ...
745
+
746
+ // Register for remote notifications
747
+ [application registerForRemoteNotifications];
748
+
749
+ // Initialize push handling
750
+ pnHandlerObj = [[MyAppPushNotificationsHandler alloc] init];
751
+ [pnHandlerObj setupZixflowClickHandling];
752
+
753
+ return YES;
754
+ }
755
+
756
+ - (void)application:(UIApplication *)application
757
+ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
758
+ [pnHandlerObj application:application deviceToken:deviceToken];
759
+ }
760
+
761
+ - (void)application:(UIApplication *)application
762
+ didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
763
+ [pnHandlerObj application:application error:error];
764
+ }
765
+
766
+ @end
767
+ ```
768
+
769
+ #### Step 5: Rich Push with Notification Service Extension
770
+
771
+ To support rich push notifications (images, videos, GIFs), add a Notification Service Extension:
772
+
773
+ **1. Create Notification Service Extension:**
774
+
775
+ 1. In Xcode: **File** → **New** → **Target**
776
+ 2. Select **Notification Service Extension**
777
+ 3. Name it `NotificationServiceExtension`
778
+ 4. Click **Finish** (activate scheme when prompted)
779
+
780
+ **2. Add Zixflow to Extension:**
781
+
782
+ Update your `ios/Podfile` to include the extension:
783
+
784
+ ```ruby
785
+ # Main app target
786
+ target 'YourApp' do
787
+ # ... existing configuration ...
788
+ pod 'zixflow-reactnative/apn', :path => '../node_modules/zixflow-reactnative'
789
+ end
790
+
791
+ # Notification Service Extension target
792
+ target 'NotificationServiceExtension' do
793
+ pod 'zixflow-reactnative-richpush/apn', :path => '../node_modules/zixflow-reactnative'
794
+ end
795
+ ```
796
+
797
+ For FCM:
798
+
799
+ ```ruby
800
+ target 'NotificationServiceExtension' do
801
+ pod 'zixflow-reactnative-richpush/fcm', :path => '../node_modules/zixflow-reactnative'
802
+ end
803
+ ```
804
+
805
+ **3. Install dependencies:**
806
+
807
+ ```bash
808
+ cd ios
809
+ pod install
810
+ cd ..
811
+ ```
812
+
813
+ **4. Update `NotificationService.swift`:**
814
+
815
+ ```swift
816
+ import UserNotifications
817
+ import ZixflowMessagingPushAPN
818
+
819
+ class NotificationService: UNNotificationServiceExtension {
820
+ var contentHandler: ((UNNotificationContent) -> Void)?
821
+ var bestAttemptContent: UNMutableNotificationContent?
822
+
823
+ override func didReceive(
824
+ _ request: UNNotificationRequest,
825
+ withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
826
+ ) {
827
+ self.contentHandler = contentHandler
828
+ bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
829
+
830
+ // Initialize SDK for extension
831
+ MessagingPushAPN.initializeForExtension(
832
+ withConfig: MessagingPushConfigBuilder(apiKey: "YOUR_API_KEY")
833
+ .build()
834
+ )
835
+
836
+ if let bestAttemptContent = bestAttemptContent {
837
+ // Let Zixflow handle rich push and track delivery
838
+ MessagingPush.shared.didReceive(request, withContentHandler: contentHandler)
839
+ }
840
+ }
841
+
842
+ override func serviceExtensionTimeWillExpire() {
843
+ // Called when extension is about to be terminated
844
+ MessagingPush.shared.serviceExtensionTimeWillExpire()
845
+
846
+ if let contentHandler = contentHandler,
847
+ let bestAttemptContent = bestAttemptContent {
848
+ contentHandler(bestAttemptContent)
849
+ }
850
+ }
851
+ }
852
+ ```
853
+
854
+ **Important:** Replace `"YOUR_API_KEY"` with your actual API key.
855
+
856
+ ---
857
+
858
+ ### Android Setup
859
+
860
+ Android push notifications use Firebase Cloud Messaging (FCM).
861
+
862
+ #### Step 1: Add Firebase to Your Project
863
+
864
+ 1. Go to [Firebase Console](https://console.firebase.google.com/)
865
+ 2. Add your Android app to Firebase project
866
+ 3. Download `google-services.json`
867
+ 4. Place `google-services.json` in `android/app/` directory
868
+
869
+ #### Step 2: Configure Gradle
870
+
871
+ **Project-level `android/build.gradle`:**
872
+
873
+ ```gradle
874
+ buildscript {
875
+ ext {
876
+ minSdkVersion = 24
877
+ compileSdkVersion = 34
878
+ targetSdkVersion = 34
879
+ }
880
+
881
+ dependencies {
882
+ classpath 'com.google.gms:google-services:4.4.2'
883
+ }
884
+ }
885
+
886
+ allprojects {
887
+ repositories {
888
+ google()
889
+ mavenCentral()
890
+ }
891
+ }
892
+ ```
893
+
894
+ **App-level `android/app/build.gradle`:**
895
+
896
+ ```gradle
897
+ apply plugin: 'com.android.application'
898
+ apply plugin: 'com.google.gms.google-services' // Add this line
899
+
900
+ android {
901
+ // ... existing configuration ...
902
+ }
903
+
904
+ dependencies {
905
+ // React Native auto-linking handles Zixflow dependencies
906
+ // ... your other dependencies ...
907
+ }
908
+ ```
909
+
910
+ #### Step 3: Add Permissions
911
+
912
+ Add to `android/app/src/main/AndroidManifest.xml`:
913
+
914
+ ```xml
915
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
916
+
917
+ <!-- Required for push notifications -->
918
+ <uses-permission android:name="android.permission.INTERNET" />
919
+
920
+ <!-- Required for Android 13+ (API 33+) -->
921
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
922
+
923
+ <application>
924
+ <!-- Your app configuration -->
925
+ </application>
926
+ </manifest>
927
+ ```
928
+
929
+ #### Step 4: Configure Notification Icon and Color (Optional)
930
+
931
+ Add to `android/app/src/main/AndroidManifest.xml` inside `<application>` tag:
932
+
933
+ ```xml
934
+ <application>
935
+ <!-- Default notification icon (white, transparent background) -->
936
+ <meta-data
937
+ android:name="com.google.firebase.messaging.default_notification_icon"
938
+ android:resource="@drawable/ic_notification" />
939
+
940
+ <!-- Default notification color (accent color) -->
941
+ <meta-data
942
+ android:name="com.google.firebase.messaging.default_notification_color"
943
+ android:resource="@color/notification_color" />
944
+ </application>
945
+ ```
946
+
947
+ ---
948
+
949
+ ### React Native Integration
950
+
951
+ #### Step 1: Initialize SDK
952
+
953
+ Initialize the Zixflow SDK in your `App.tsx`:
954
+
955
+ ```typescript
956
+ import React, { useEffect } from 'react';
957
+ import { Zixflow, ZixflowConfig, ZixflowLogLevel } from 'zixflow-reactnative';
958
+
959
+ export default function App() {
960
+ useEffect(() => {
961
+ // Configure the SDK
962
+ const config: ZixflowConfig = {
963
+ apiKey: 'YOUR_API_KEY',
964
+ logLevel: ZixflowLogLevel.debug,
965
+ inApp: {
966
+ },
967
+ autoTrackDeviceAttributes: true,
968
+ trackApplicationLifecycleEvents: true,
969
+ };
970
+
971
+ // Initialize the SDK
972
+ Zixflow.initialize(config);
973
+
974
+ console.log('Zixflow SDK initialized');
975
+ }, []);
976
+
977
+ return (
978
+ // Your app UI
979
+ );
980
+ }
981
+ ```
982
+
983
+ #### Step 2: Request Push Permission
984
+
985
+ Request permission to send push notifications:
986
+
987
+ ```typescript
988
+ import React, { useState } from 'react';
989
+ import { Button, Alert } from 'react-native';
990
+ import { Zixflow, ZixflowPushPermissionStatus } from 'zixflow-reactnative';
991
+
992
+ export default function PushPermissionButton() {
993
+ const [permissionStatus, setPermissionStatus] = useState<ZixflowPushPermissionStatus | null>(null);
994
+
995
+ const requestPushPermission = async () => {
996
+ try {
997
+ const permission = await Zixflow.pushMessaging.showPromptForPushNotifications({
998
+ ios: {
999
+ sound: true,
1000
+ badge: true,
1001
+ alert: true,
1002
+ },
1003
+ });
1004
+
1005
+ setPermissionStatus(permission);
1006
+
1007
+ switch (permission) {
1008
+ case ZixflowPushPermissionStatus.Granted:
1009
+ Alert.alert('Success', 'Push notifications enabled!');
1010
+ console.log('Push notifications enabled');
1011
+ break;
1012
+
1013
+ case ZixflowPushPermissionStatus.Denied:
1014
+ Alert.alert('Denied', 'Push notification permission was denied');
1015
+ console.log('Push notifications denied');
1016
+ break;
1017
+
1018
+ case ZixflowPushPermissionStatus.NotDetermined:
1019
+ // iOS only: permission not yet asked
1020
+ console.log('Push notification permission not determined');
1021
+ break;
1022
+ }
1023
+ } catch (error) {
1024
+ console.error('Failed to request push permission:', error);
1025
+ }
1026
+ };
1027
+
1028
+ return (
1029
+ <Button
1030
+ title="Enable Push Notifications"
1031
+ onPress={requestPushPermission}
1032
+ />
1033
+ );
1034
+ }
1035
+ ```
1036
+
1037
+ **Permission Options (iOS)**:
1038
+
1039
+ | Option | Type | Description |
1040
+ |--------|------|-------------|
1041
+ | `sound` | boolean | Enable notification sounds |
1042
+ | `badge` | boolean | Enable app badge updates |
1043
+ | `alert` | boolean | Show notification alerts |
1044
+
1045
+ #### Step 3: Check Permission Status
1046
+
1047
+ Check current push permission status:
1048
+
1049
+ ```typescript
1050
+ import { Zixflow, ZixflowPushPermissionStatus } from 'zixflow-reactnative';
1051
+
1052
+ const checkPushPermission = async () => {
1053
+ try {
1054
+ const status = await Zixflow.pushMessaging.getPushPermissionStatus();
1055
+
1056
+ console.log('Push permission status:', status);
1057
+
1058
+ if (status === ZixflowPushPermissionStatus.Granted) {
1059
+ console.log('Push notifications are enabled');
1060
+ } else if (status === ZixflowPushPermissionStatus.Denied) {
1061
+ console.log('Push notifications are disabled');
1062
+ } else {
1063
+ console.log('Push permission not determined');
1064
+ }
1065
+ } catch (error) {
1066
+ console.error('Failed to get push permission status:', error);
1067
+ }
1068
+ };
1069
+ ```
1070
+
1071
+ #### Step 4: Identify Users
1072
+
1073
+ **Critical**: Device tokens must be associated with a user before push notifications can be delivered.
1074
+
1075
+ ```typescript
1076
+ import { Zixflow } from 'zixflow-reactnative';
1077
+
1078
+ // Identify user when they log in
1079
+ const handleLogin = async (userId: string, userEmail: string) => {
1080
+ try {
1081
+ // Identify user with Zixflow
1082
+ Zixflow.identify({
1083
+ userId: userId,
1084
+ traits: {
1085
+ email: userEmail,
1086
+ firstName: 'John',
1087
+ lastName: 'Doe',
1088
+ plan: 'premium',
1089
+ },
1090
+ });
1091
+
1092
+ console.log('User identified:', userId);
1093
+ } catch (error) {
1094
+ console.error('Failed to identify user:', error);
1095
+ }
1096
+ };
1097
+ ```
1098
+
1099
+ **Important Notes:**
1100
+ - When users start the app, they automatically generate a device token
1101
+ - This token links to their Zixflow profile when you call `identify()`
1102
+ - This ensures notifications are delivered to the correct user
1103
+
1104
+ #### Step 5: Get Device Token
1105
+
1106
+ Retrieve the registered device token:
1107
+
1108
+ ```typescript
1109
+ import { Zixflow } from 'zixflow-reactnative';
1110
+
1111
+ const getDeviceToken = async () => {
1112
+ try {
1113
+ const token = await Zixflow.pushMessaging.getRegisteredDeviceToken();
1114
+ console.log('Device token:', token);
1115
+ return token;
1116
+ } catch (error) {
1117
+ console.error('Failed to get device token:', error);
1118
+ return null;
1119
+ }
1120
+ };
1121
+ ```
1122
+
1123
+ ---
1124
+
1125
+ ### Deep Links and Navigation
1126
+
1127
+ Handle deep links from push notifications:
1128
+
1129
+ #### Setup Deep Linking
1130
+
1131
+ **1. Configure Deep Links (iOS):**
1132
+
1133
+ Add to `ios/YourApp/Info.plist`:
1134
+
1135
+ ```xml
1136
+ <key>CFBundleURLTypes</key>
1137
+ <array>
1138
+ <dict>
1139
+ <key>CFBundleURLSchemes</key>
1140
+ <array>
1141
+ <string>yourapp</string>
1142
+ </array>
1143
+ </dict>
1144
+ </array>
1145
+ ```
1146
+
1147
+ **2. Configure Deep Links (Android):**
1148
+
1149
+ Add to `android/app/src/main/AndroidManifest.xml`:
1150
+
1151
+ ```xml
1152
+ <activity android:name=".MainActivity">
1153
+ <!-- Existing intent filter -->
1154
+
1155
+ <!-- Deep link intent filter -->
1156
+ <intent-filter>
1157
+ <action android:name="android.intent.action.VIEW" />
1158
+ <category android:name="android.intent.category.DEFAULT" />
1159
+ <category android:name="android.intent.category.BROWSABLE" />
1160
+
1161
+ <data
1162
+ android:scheme="yourapp"
1163
+ android:host="*" />
1164
+ </intent-filter>
1165
+
1166
+ <!-- Universal Links (optional) -->
1167
+ <intent-filter android:autoVerify="true">
1168
+ <action android:name="android.intent.action.VIEW" />
1169
+ <category android:name="android.intent.category.DEFAULT" />
1170
+ <category android:name="android.intent.category.BROWSABLE" />
1171
+
1172
+ <data
1173
+ android:scheme="https"
1174
+ android:host="yourapp.com" />
1175
+ </intent-filter>
1176
+ </activity>
1177
+ ```
1178
+
1179
+ #### Handle Deep Links in React Native
1180
+
1181
+ Use React Navigation's linking configuration:
1182
+
1183
+ ```typescript
1184
+ import React from 'react';
1185
+ import { NavigationContainer } from '@react-navigation/native';
1186
+ import { createNativeStackNavigator } from '@react-navigation/native-stack';
1187
+ import { Linking } from 'react-native';
1188
+
1189
+ const Stack = createNativeStackNavigator();
1190
+
1191
+ const linking = {
1192
+ prefixes: ['yourapp://', 'https://yourapp.com'],
1193
+ config: {
1194
+ screens: {
1195
+ Home: 'home',
1196
+ Product: 'product/:id',
1197
+ Profile: 'profile',
1198
+ },
1199
+ },
1200
+ };
1201
+
1202
+ export default function App() {
1203
+ return (
1204
+ <NavigationContainer linking={linking}>
1205
+ <Stack.Navigator>
1206
+ <Stack.Screen name="Home" component={HomeScreen} />
1207
+ <Stack.Screen name="Product" component={ProductScreen} />
1208
+ <Stack.Screen name="Profile" component={ProfileScreen} />
1209
+ </Stack.Navigator>
1210
+ </NavigationContainer>
1211
+ );
1212
+ }
1213
+ ```
1214
+
1215
+ ---
1216
+
1217
+ ### Rich Push Notification Payloads
1218
+
1219
+ The Zixflow SDK automatically handles rich push notifications. Here's how to structure payloads:
1220
+
1221
+ #### iOS APNs Payload
1222
+
1223
+ ```json
1224
+ {
1225
+ "aps": {
1226
+ "mutable-content": 1,
1227
+ "alert": {
1228
+ "title": "New Product Available",
1229
+ "body": "Check out our latest premium features"
1230
+ },
1231
+ "badge": 1,
1232
+ "sound": "default"
1233
+ },
1234
+ "Zixflow": {
1235
+ "push": {
1236
+ "link": "yourapp://product/123",
1237
+ "image": "https://example.com/product-image.jpg"
1238
+ }
1239
+ }
1240
+ }
1241
+ ```
1242
+
1243
+ #### iOS FCM Payload
1244
+
1245
+ ```json
1246
+ {
1247
+ "message": {
1248
+ "apns": {
1249
+ "payload": {
1250
+ "aps": {
1251
+ "mutable-content": 1,
1252
+ "alert": {
1253
+ "title": "Special Offer",
1254
+ "body": "Limited time discount!"
1255
+ }
1256
+ },
1257
+ "Zixflow": {
1258
+ "push": {
1259
+ "link": "https://yourapp.com/offers",
1260
+ "image": "https://example.com/offer.png"
1261
+ }
1262
+ }
1263
+ },
1264
+ "headers": {
1265
+ "apns-priority": 10
1266
+ }
1267
+ }
1268
+ }
1269
+ }
1270
+ ```
1271
+
1272
+ #### Android FCM Payload
1273
+
1274
+ ```json
1275
+ {
1276
+ "message": {
1277
+ "data": {
1278
+ "title": "Order Shipped",
1279
+ "body": "Your order is on the way!",
1280
+ "image": "https://example.com/shipping.jpg",
1281
+ "link": "yourapp://orders/456"
1282
+ }
1283
+ }
1284
+ }
1285
+ ```
1286
+
1287
+ ---
1288
+
1289
+ ### Testing Push Notifications
1290
+
1291
+ #### 1. Verify Device Token Registration
1292
+
1293
+ Check if device token is registered:
1294
+
1295
+ ```typescript
1296
+ const verifyPushSetup = async () => {
1297
+ try {
1298
+ const token = await Zixflow.pushMessaging.getRegisteredDeviceToken();
1299
+ const status = await Zixflow.pushMessaging.getPushPermissionStatus();
1300
+
1301
+ console.log('Device token:', token);
1302
+ console.log('Permission status:', status);
1303
+
1304
+ if (token && status === ZixflowPushPermissionStatus.Granted) {
1305
+ console.log('✓ Push notifications ready');
1306
+ } else {
1307
+ console.log('✗ Push setup incomplete');
1308
+ }
1309
+ } catch (error) {
1310
+ console.error('Push verification failed:', error);
1311
+ }
1312
+ };
1313
+ ```
1314
+
1315
+ #### 2. Enable Debug Logging
1316
+
1317
+ Set log level to debug during development:
1318
+
1319
+ ```typescript
1320
+ const config: ZixflowConfig = {
1321
+ apiKey: 'YOUR_API_KEY',
1322
+ logLevel: ZixflowLogLevel.debug, // Verbose logging
1323
+ };
1324
+
1325
+ Zixflow.initialize(config);
1326
+ ```
1327
+
1328
+ #### 3. Test on Physical Devices
1329
+
1330
+ **iOS:**
1331
+ - Push notifications **do not work** on iOS Simulator
1332
+ - Must use physical iOS device
1333
+ - Ensure APNs certificate is configured in Zixflow dashboard
1334
+
1335
+ **Android:**
1336
+ - Emulator works if Google Play Services installed
1337
+ - Physical device always recommended
1338
+ - Ensure FCM Server Key is configured in Zixflow dashboard
1339
+
1340
+ #### 4. Send Test Push from Zixflow
1341
+
1342
+ 1. Log into Zixflow dashboard
1343
+ 2. Navigate to **Messaging** → **Push Notifications**
1344
+ 3. Create test push notification
1345
+ 4. Send to specific user (using `userId` from `identify()`)
1346
+
1347
+ ---
1348
+
1349
+ ### Troubleshooting
1350
+
1351
+ #### iOS Push Not Received
1352
+
1353
+ **Symptoms:** Push sent but not delivered on iOS
1354
+
1355
+ **Solutions:**
1356
+ 1. Verify Push Notifications capability enabled in Xcode
1357
+ 2. Check APNs certificate uploaded to Zixflow dashboard
1358
+ 3. Ensure testing on physical device (not simulator)
1359
+ 4. Verify user identified: `Zixflow.identify({ userId: ... })`
1360
+ 5. Check permission granted: `getPushPermissionStatus()`
1361
+ 6. Review logs for errors
1362
+
1363
+ #### Android Push Not Received
1364
+
1365
+ **Symptoms:** Push sent but not delivered on Android
1366
+
1367
+ **Solutions:**
1368
+ 1. Verify `google-services.json` in `android/app/` directory
1369
+ 2. Check FCM Server Key in Zixflow dashboard
1370
+ 3. Ensure POST_NOTIFICATIONS permission granted (Android 13+)
1371
+ 4. Verify Google Services plugin applied
1372
+ 5. Check device token registered
1373
+ 6. Review logs for errors
1374
+
1375
+ #### Rich Push Not Working (Images)
1376
+
1377
+ **Symptoms:** Images not loading in notifications
1378
+
1379
+ **iOS Solutions:**
1380
+ 1. Ensure Notification Service Extension properly configured
1381
+ 2. Verify extension has correct dependencies in Podfile
1382
+ 3. Check App Groups configuration (if using)
1383
+ 4. Verify image URL is accessible
1384
+ 5. Check extension logs for errors
1385
+
1386
+ **Android Solutions:**
1387
+ 1. Verify image URL is accessible from device
1388
+ 2. Check internet connectivity
1389
+ 3. Ensure image format is supported (JPEG, PNG, GIF)
1390
+
1391
+ #### Permission Denied
1392
+
1393
+ **Symptoms:** User denied push permission
1394
+
1395
+ **Solutions:**
1396
+ 1. Explain value before requesting permission
1397
+ 2. Guide users to Settings to enable manually
1398
+ 3. Show in-app message explaining benefits
1399
+ 4. Request permission at appropriate time (after user engagement)
1400
+
1401
+ #### Device Token Not Registered
1402
+
1403
+ **Symptoms:** `getRegisteredDeviceToken()` returns empty or fails
1404
+
1405
+ **Solutions:**
1406
+ 1. Verify SDK initialized before calling
1407
+ 2. Check permission granted
1408
+ 3. Ensure identify() called to associate token
1409
+ 4. Review native logs for errors
1410
+ 5. Rebuild app and retry
1411
+
1412
+ ---
1413
+
1414
+ ### Best Practices
1415
+
1416
+ 1. **Request permission thoughtfully** - Explain value before asking
1417
+ 2. **Identify users immediately** after authentication
1418
+ 3. **Test on physical devices** - Simulators have limitations
1419
+ 4. **Use rich push** - Images increase engagement
1420
+ 5. **Handle deep links** - Provide seamless navigation
1421
+ 6. **Monitor metrics** - Track delivery and open rates
1422
+ 7. **Enable debug logging** - During development only
1423
+ 8. **Test both platforms** - iOS and Android behave differently
1424
+ 9. **Clear identity on logout** - Call `clearIdentify()`
1425
+ 10. **Keep credentials secure** - Never commit API keys to git
1426
+
1427
+ ---
1428
+
1429
+ ---
15
1430
 
16
- The official Zixflow SDK for React Native enables you to integrate customer engagement features—like in-app messaging and push notifications—into your app. Track customer behavior, send targeted messages, and create personalized experiences.
1431
+ ## Push Notification Tracking
17
1432
 
18
- > 📖 Full documentation: [zixflow.com/docs/sdk/react-native](https://zixflow.com/docs/sdk/react-native/)
19
- > 🧪 Example apps: [see the `/example` directory](/example)
1433
+ ### Overview
20
1434
 
21
- ---
1435
+ Zixflow automatically tracks push notification delivery and engagement metrics to help you measure campaign performance. The SDK tracks three key lifecycle events:
1436
+
1437
+ 1. **Delivery Confirmed** - When the notification arrives on the device
1438
+ 2. **Notification Opened** - When the user taps the notification
1439
+ 3. **Action Button Clicked** - When the user taps an action button
22
1440
 
23
- ## About Zixflow
1441
+ ### How Push Tracking Works
24
1442
 
25
- Zixflow is a customer engagement platform built on proven Zixflow technology. This SDK is a customized fork of the Zixflow React Native SDK, optimized for use with the Zixflow platform.
1443
+ When Zixflow sends a push notification, it includes special tracking fields in the data payload:
26
1444
 
27
- ### Key Features
1445
+ | Field | Purpose |
1446
+ |-------|---------|
1447
+ | `Zixflow-Delivery-ID` | Unique ID for this delivery (links to campaign record) |
1448
+ | `Zixflow-Delivery-Token` | The FCM/APNs token the notification was sent to |
1449
+
1450
+ **Example push payload:**
1451
+ ```json
1452
+ {
1453
+ "Zixflow-Delivery-ID": "626533406292836846",
1454
+ "Zixflow-Delivery-Token": "dcFRlDhiRbehM1vg...",
1455
+ "title": "Flash Sale! 70% OFF",
1456
+ "body": "Limited time only — grab your deal now!",
1457
+ "deeplink_url": "https://yourapp.com/sale",
1458
+ "image_url": "https://cdn.yourapp.com/banner.png",
1459
+ "action_buttons": "[{\"name\":\"Shop Now\",\"deeplink\":\"https://yourapp.com/sale\"},{\"name\":\"Remind Me\",\"deeplink\":\"\"}]"
1460
+ }
1461
+ ```
28
1462
 
29
- - 📊 Customer identification and event tracking
30
- - 📲 Push notifications (iOS APN and Android FCM)
31
- - 💬 In-app messaging
32
- - 📍 Location tracking (optional)
33
- - 🎯 Personalized customer experiences
34
- - 📈 Analytics and customer data pipelines
35
- - 🔧 TypeScript support
36
- - ⚡ React Native New Architecture (TurboModules) support
1463
+ > **Note:** The SDK automatically handles most tracking for you when using the default push implementation. This section covers advanced customization scenarios.
37
1464
 
38
1465
  ---
39
1466
 
40
- ## Installation
1467
+ ### Tracking Events
41
1468
 
42
- ```bash
43
- npm install zixflow-reactnative
44
- ```
1469
+ #### 1. Delivery Confirmed
45
1470
 
46
- or
1471
+ **When to track:** The moment the push payload arrives on the device
47
1472
 
48
- ```bash
49
- yarn add zixflow-reactnative
1473
+ **SDK method:** `Zixflow.trackMetric({ deliveryID, deviceToken, event: MetricEvent.delivered })`
1474
+
1475
+ **Implementation:**
1476
+
1477
+ ```typescript
1478
+ import messaging from '@react-native-firebase/messaging';
1479
+ import { Zixflow, MetricEvent } from 'zixflow-reactnative';
1480
+
1481
+ // Listen for foreground messages
1482
+ useEffect(() => {
1483
+ const unsubscribe = messaging().onMessage(async (remoteMessage) => {
1484
+ const deliveryId = remoteMessage.data?.['Zixflow-Delivery-ID'] ?? '';
1485
+ const deliveryToken = remoteMessage.data?.['Zixflow-Delivery-Token'] ?? cachedToken ?? '';
1486
+
1487
+ if (deliveryId && deliveryToken) {
1488
+ await Zixflow.trackMetric({
1489
+ deliveryID: deliveryId,
1490
+ deviceToken: deliveryToken,
1491
+ event: MetricEvent.delivered,
1492
+ });
1493
+ }
1494
+ });
1495
+
1496
+ return unsubscribe;
1497
+ }, []);
50
1498
  ```
51
1499
 
1500
+ > **Important:** The Zixflow SDK automatically tracks delivery. Manual tracking is only needed for custom implementations.
1501
+
52
1502
  ---
53
1503
 
54
- ## Quick Start
1504
+ #### 2. Notification Opened
55
1505
 
56
- ### SDK Initialization
1506
+ **When to track:** When the user taps the notification banner
1507
+
1508
+ **SDK method:** `Zixflow.trackMetric({ deliveryID, deviceToken, event: MetricEvent.opened })`
57
1509
 
58
- Here's a simplified example showing how to initialize the SDK to enable mobile features:
1510
+ **Implementation:**
59
1511
 
60
- ```ts
61
- import {
62
- Zixflow,
63
- ZixflowConfig,
64
- ZixflowLogLevel,
65
- } from 'zixflow-reactnative';
1512
+ ```typescript
1513
+ import messaging from '@react-native-firebase/messaging';
1514
+ import { Zixflow, MetricEvent } from 'zixflow-reactnative';
66
1515
 
1516
+ // Background / quit tap
67
1517
  useEffect(() => {
68
- const config: ZixflowConfig = {
69
- cdpApiKey: 'your-api-key', // Required
70
- migrationSiteId: 'your-site-id', // Optional, for migrating from older SDKs
71
- logLevel: ZixflowLogLevel.Debug,
72
- trackApplicationLifecycleEvents: true,
73
- inApp: {
74
- siteId: 'your-site-id', // Required for in-app messaging
75
- },
76
- push: {
77
- android: {
78
- pushClickBehavior: 'ActivityPreventRestart', // Optional
79
- },
80
- },
81
- };
1518
+ const unsubscribe = messaging().onNotificationOpenedApp(async (remoteMessage) => {
1519
+ trackOpened(remoteMessage.data);
1520
+ handleDeeplink(remoteMessage.data?.deeplink_url);
1521
+ });
1522
+
1523
+ return unsubscribe;
1524
+ }, []);
82
1525
 
83
- Zixflow.initialize(config);
1526
+ // Terminated tap
1527
+ useEffect(() => {
1528
+ messaging()
1529
+ .getInitialNotification()
1530
+ .then((remoteMessage) => {
1531
+ if (remoteMessage) {
1532
+ trackOpened(remoteMessage.data);
1533
+ handleDeeplink(remoteMessage.data?.deeplink_url);
1534
+ }
1535
+ });
84
1536
  }, []);
1537
+
1538
+ const trackOpened = async (data: any) => {
1539
+ const deliveryId = data?.['Zixflow-Delivery-ID'] ?? '';
1540
+ const deliveryToken = data?.['Zixflow-Delivery-Token'] ?? cachedToken ?? '';
1541
+
1542
+ if (deliveryId && deliveryToken) {
1543
+ await Zixflow.trackMetric({
1544
+ deliveryID: deliveryId,
1545
+ deviceToken: deliveryToken,
1546
+ event: MetricEvent.opened,
1547
+ });
1548
+ }
1549
+ };
85
1550
  ```
86
1551
 
87
- > 🔑 For help finding your credentials, check out the [Quick Start Guide](https://zixflow.com/docs/sdk/react-native/quick-start-guide/).
1552
+ > **Note:** The SDK automatically tracks opens when using the default push implementation.
88
1553
 
89
1554
  ---
90
1555
 
91
- ## Core Features
1556
+ #### 3. Action Button Clicked
1557
+
1558
+ **When to track:** When the user taps a named action button
1559
+
1560
+ **SDK method:** `Zixflow.track({ name: "Push Notification Action Clicked", properties: {...} })`
1561
+
1562
+ **Implementation:**
1563
+
1564
+ ```typescript
1565
+ import { Zixflow, MetricEvent } from 'zixflow-reactnative';
1566
+
1567
+ // Handle action press from local notification
1568
+ const handleActionPress = async (data: any, actionId: string) => {
1569
+ const deliveryId = data['Zixflow-Delivery-ID'] ?? '';
1570
+ const token = data['Zixflow-Delivery-Token'] ?? '';
1571
+ const actionIndex = parseInt(actionId.replace(/\D/g, ''), 10);
1572
+ const buttons = parseButtons(data['action_buttons']);
1573
+ const actionName = buttons[actionIndex]?.name ?? `Action ${actionIndex + 1}`;
1574
+ const actionDeeplink = buttons[actionIndex]?.deeplink ?? '';
1575
+
1576
+ // Always fire opened first
1577
+ await Zixflow.trackMetric({
1578
+ deliveryID: deliveryId,
1579
+ deviceToken: token,
1580
+ event: MetricEvent.opened,
1581
+ });
1582
+
1583
+ // Then fire action clicked
1584
+ await Zixflow.track({
1585
+ name: 'Push Notification Action Clicked',
1586
+ properties: {
1587
+ 'Zixflow-Delivery-ID': deliveryId,
1588
+ 'Zixflow-Delivery-Token': token,
1589
+ 'action_index': actionIndex,
1590
+ 'action_name': actionName,
1591
+ 'action_deeplink': actionDeeplink,
1592
+ },
1593
+ });
1594
+ };
1595
+
1596
+ const parseButtons = (raw: any) => {
1597
+ if (!raw) return [];
1598
+ try {
1599
+ return typeof raw === 'string' ? JSON.parse(raw) : raw;
1600
+ } catch {
1601
+ return [];
1602
+ }
1603
+ };
1604
+ ```
92
1605
 
93
- ### 👤 Identify Users
1606
+ **Action button properties:**
94
1607
 
95
- Associate events and devices with customer profiles:
1608
+ | Property | Type | Required | Description |
1609
+ |----------|------|----------|-------------|
1610
+ | `Zixflow-Delivery-ID` | string | ✅ | Links event to campaign delivery |
1611
+ | `action_index` | integer | ✅ | 0-based index of button tapped |
1612
+ | `action_name` | string | ✅ | Button label (e.g., "Shop Now") |
1613
+ | `Zixflow-Delivery-Token` | string | Recommended | FCM/APNs token |
1614
+ | `action_deeplink` | string | Recommended | Button's URL |
96
1615
 
97
- ```ts
98
- Zixflow.identify({
99
- userId: 'user123',
100
- traits: {
101
- email: 'user@example.com',
102
- firstName: 'John',
103
- lastName: 'Doe',
104
- plan: 'premium',
105
- },
106
- });
107
- ```
1616
+ ---
108
1617
 
109
- ### 📊 Track Events
1618
+ ### Action Buttons Format
110
1619
 
111
- Track custom events to trigger messaging based on user behavior:
1620
+ The `action_buttons` field is a JSON-encoded string containing button definitions:
112
1621
 
113
- ```ts
114
- Zixflow.track('Product Viewed', {
115
- productId: '12345',
116
- productName: 'Awesome Product',
117
- price: 49.99,
118
- category: 'Electronics',
119
- });
1622
+ **Raw payload value:**
1623
+ ```
1624
+ "[{\"name\":\"Shop Now\",\"deeplink\":\"https://yourapp.com/sale\"},{\"name\":\"Remind Me\",\"deeplink\":\"\"}]"
1625
+ ```
1626
+
1627
+ **Parsed structure:**
1628
+ ```json
1629
+ [
1630
+ { "name": "Shop Now", "deeplink": "https://yourapp.com/sale" },
1631
+ { "name": "Remind Me", "deeplink": "" }
1632
+ ]
120
1633
  ```
121
1634
 
122
- ### 📺 Screen Tracking
1635
+ **Parsing example:**
1636
+
1637
+ ```typescript
1638
+ const parseActionButtons = (raw: any): Array<{ name: string; deeplink: string }> => {
1639
+ if (!raw) return [];
123
1640
 
124
- Track screen views in your app:
1641
+ try {
1642
+ const decoded = typeof raw === 'string' ? JSON.parse(raw) : raw;
1643
+ return Array.isArray(decoded) ? decoded : [];
1644
+ } catch (error) {
1645
+ console.error('Error parsing action buttons:', error);
1646
+ return [];
1647
+ }
1648
+ };
125
1649
 
126
- ```ts
127
- Zixflow.screen('Product Details', {
128
- productId: '12345',
129
- category: 'Electronics',
1650
+ // Usage
1651
+ const buttons = parseActionButtons(remoteMessage.data?.action_buttons);
1652
+ buttons.forEach((btn, index) => {
1653
+ console.log(`Button ${index}: ${btn.name} -> ${btn.deeplink}`);
130
1654
  });
131
1655
  ```
132
1656
 
133
- ### 🏷️ Set Profile Attributes
1657
+ **Rules:**
1658
+ - Maximum 2 buttons per notification (recommended for consistency across platforms)
1659
+ - `deeplink` may be empty — handle gracefully
1660
+ - Button index is 0-based (first button = index 0)
134
1661
 
135
- Update customer profile attributes:
1662
+ ---
136
1663
 
137
- ```ts
138
- Zixflow.setProfileAttributes({
139
- plan: 'enterprise',
140
- lastSeenAt: Date.now(),
141
- preferences: {
142
- notifications: true,
143
- newsletter: true,
144
- },
145
- });
1664
+ ### Complete Push Tracking Implementation
1665
+
1666
+ Here's a complete example integrating all tracking events:
1667
+
1668
+ ```typescript
1669
+ import React, { useEffect, useState } from 'react';
1670
+ import messaging, { FirebaseMessagingTypes } from '@react-native-firebase/messaging';
1671
+ import { Zixflow, MetricEvent } from 'zixflow-reactnative';
1672
+
1673
+ const App = () => {
1674
+ const [fcmToken, setFcmToken] = useState<string | null>(null);
1675
+
1676
+ useEffect(() => {
1677
+ setupPushNotifications();
1678
+ }, []);
1679
+
1680
+ const setupPushNotifications = async () => {
1681
+ // Request permission
1682
+ const authStatus = await messaging().requestPermission();
1683
+ const enabled =
1684
+ authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
1685
+ authStatus === messaging.AuthorizationStatus.PROVISIONAL;
1686
+
1687
+ if (enabled) {
1688
+ // Get FCM token
1689
+ const token = await messaging().getToken();
1690
+ setFcmToken(token);
1691
+
1692
+ // Register with Zixflow
1693
+ await Zixflow.registerDeviceToken({ deviceToken: token });
1694
+
1695
+ // Listen for token refresh
1696
+ messaging().onTokenRefresh(async (newToken) => {
1697
+ setFcmToken(newToken);
1698
+ await Zixflow.registerDeviceToken({ deviceToken: newToken });
1699
+ });
1700
+
1701
+ // Handle foreground messages
1702
+ messaging().onMessage(async (remoteMessage) => {
1703
+ trackDelivery(remoteMessage);
1704
+ showLocalNotification(remoteMessage);
1705
+ });
1706
+
1707
+ // Handle background/quit taps
1708
+ messaging().onNotificationOpenedApp((remoteMessage) => {
1709
+ trackOpened(remoteMessage.data);
1710
+ handleDeeplink(remoteMessage.data?.deeplink_url);
1711
+ });
1712
+
1713
+ // Handle terminated tap
1714
+ const initialNotification = await messaging().getInitialNotification();
1715
+ if (initialNotification) {
1716
+ trackOpened(initialNotification.data);
1717
+ handleDeeplink(initialNotification.data?.deeplink_url);
1718
+ }
1719
+ }
1720
+ };
1721
+
1722
+ const trackDelivery = async (message: FirebaseMessagingTypes.RemoteMessage) => {
1723
+ const deliveryId = message.data?.['Zixflow-Delivery-ID'] ?? '';
1724
+ const deliveryToken = message.data?.['Zixflow-Delivery-Token'] ?? fcmToken ?? '';
1725
+
1726
+ if (deliveryId && deliveryToken) {
1727
+ await Zixflow.trackMetric({
1728
+ deliveryID: deliveryId,
1729
+ deviceToken: deliveryToken,
1730
+ event: MetricEvent.delivered,
1731
+ });
1732
+ }
1733
+ };
1734
+
1735
+ const trackOpened = async (data: any) => {
1736
+ const deliveryId = data?.['Zixflow-Delivery-ID'] ?? '';
1737
+ const deliveryToken = data?.['Zixflow-Delivery-Token'] ?? fcmToken ?? '';
1738
+
1739
+ if (deliveryId && deliveryToken) {
1740
+ await Zixflow.trackMetric({
1741
+ deliveryID: deliveryId,
1742
+ deviceToken: deliveryToken,
1743
+ event: MetricEvent.opened,
1744
+ });
1745
+ }
1746
+ };
1747
+
1748
+ const handleDeeplink = (url?: string) => {
1749
+ if (!url) return;
1750
+ // Implement your deep link navigation logic
1751
+ console.log('Navigating to:', url);
1752
+ };
1753
+
1754
+ const showLocalNotification = async (message: FirebaseMessagingTypes.RemoteMessage) => {
1755
+ // Use local notification library to show notification
1756
+ };
1757
+
1758
+ return (
1759
+ // Your app UI
1760
+ <></>
1761
+ );
1762
+ };
1763
+
1764
+ export default App;
146
1765
  ```
147
1766
 
148
1767
  ---
149
1768
 
150
- ## 📲 Push Notifications
1769
+ ### Tracking Decision Flowchart
151
1770
 
152
- This SDK supports rich push notifications using Firebase (for Android) and either Firebase or APNs (for iOS).
1771
+ ```
1772
+ Notification received?
1773
+ ├── YES → trackMetric(delivered) [automatic with SDK]
1774
+ │
1775
+ User interacted?
1776
+ ├── Tapped notification body
1777
+ │ └── trackMetric(opened) [automatic with SDK]
1778
+ │ └── Navigate to deeplink_url
1779
+ │
1780
+ └── Tapped action button
1781
+ ├── trackMetric(opened) [automatic with SDK]
1782
+ └── track("Push Notification Action Clicked")
1783
+ └── Navigate to button's deeplink
1784
+ ```
153
1785
 
154
- ### Request Permission (iOS)
1786
+ ---
155
1787
 
156
- ```ts
157
- const status = await Zixflow.pushMessaging.showPromptForPushNotifications();
158
- console.log('Push permission status:', status);
159
- ```
1788
+ ### Fallback for Non-Zixflow Push
160
1789
 
161
- ### Handle Push Notifications
1790
+ If a push notification doesn't contain `Zixflow-Delivery-ID` (sent from another source), the SDK automatically skips tracking.
162
1791
 
163
- ```ts
164
- // Track when user receives a notification
165
- Zixflow.pushMessaging.onMessageReceived((message) => {
166
- console.log('Notification received:', message);
167
- });
1792
+ For custom analytics on non-Zixflow pushes, use a different event name:
168
1793
 
169
- // Track when user clicks on a notification
170
- Zixflow.pushMessaging.onBackgroundMessageReceived((message) => {
171
- console.log('Notification clicked:', message);
1794
+ ```typescript
1795
+ // Don't use reserved push event names for non-Zixflow pushes
1796
+ await Zixflow.track({
1797
+ name: 'External Push Received',
1798
+ properties: {
1799
+ 'notification_id': message.messageId ?? '',
1800
+ 'title': message.notification?.title ?? '',
1801
+ 'body': message.notification?.body ?? '',
1802
+ 'source': 'external',
1803
+ },
172
1804
  });
173
1805
  ```
174
1806
 
175
- Follow our [push setup guide](https://zixflow.com/docs/sdk/react-native/push/) to configure your project for push.
1807
+ > **Important:** Push notification event names (`Push Notification Delivered`, `Push Notification Opened`, `Push Notification Action Clicked`) are reserved for Zixflow's delivery pipeline.
176
1808
 
177
1809
  ---
178
1810
 
179
- ## 💬 In-App Messaging
1811
+ ### Testing Push Tracking
180
1812
 
181
- Display in-app messages to your users:
1813
+ #### Verify Tracking Events
182
1814
 
183
- ```ts
184
- import { InAppMessageEvent, InAppMessageEventType } from 'zixflow-reactnative';
1815
+ Enable debug logging to see tracking events:
185
1816
 
186
- // Register event listener
187
- Zixflow.inAppMessaging.registerEventsListener((event: InAppMessageEvent) => {
188
- switch (event.eventType) {
189
- case InAppMessageEventType.MessageShown:
190
- console.log('In-app message shown:', event.message);
191
- break;
192
- case InAppMessageEventType.MessageClicked:
193
- console.log('In-app message clicked:', event.message);
194
- break;
195
- case InAppMessageEventType.MessageDismissed:
196
- console.log('In-app message dismissed:', event.message);
197
- break;
198
- }
199
- });
1817
+ ```typescript
1818
+ const config: ZixflowConfig = {
1819
+ apiKey: 'YOUR_API_KEY',
1820
+ logLevel: 'debug',
1821
+ };
200
1822
 
201
- // Dismiss message programmatically
202
- Zixflow.inAppMessaging.dismissMessage();
1823
+ await Zixflow.setup(config);
203
1824
  ```
204
1825
 
205
- ### Inbox Messages
1826
+ Look for these log messages:
1827
+ - `[Zixflow] Push Notification Delivered tracked`
1828
+ - `[Zixflow] Push Notification Opened tracked`
1829
+ - `[Zixflow] Push Notification Action Clicked tracked`
206
1830
 
207
- Manage inbox messages:
1831
+ #### Check Campaign Analytics
208
1832
 
209
- ```ts
210
- const inbox = Zixflow.inAppMessaging.inbox();
1833
+ 1. Log into Zixflow dashboard
1834
+ 2. Navigate to **Messaging** → **Push Notifications**
1835
+ 3. View campaign metrics:
1836
+ - **Sent** - Total notifications sent
1837
+ - **Delivered** - Arrived on device
1838
+ - **Opened** - User tapped notification
1839
+ - **Clicked** - User tapped action button
211
1840
 
212
- // Get all messages
213
- const messages = await inbox.getMessages();
1841
+ ---
214
1842
 
215
- // Mark message as read
216
- await inbox.markMessageOpened(messageId);
1843
+ ## Location Tracking
217
1844
 
218
- // Delete message
219
- await inbox.markMessageDeleted(messageId);
1845
+ Enable location tracking to send location-based messages:
220
1846
 
221
- // Subscribe to inbox updates
222
- inbox.subscribeToMessages((messages) => {
223
- console.log('Inbox updated:', messages);
224
- });
1847
+ ```typescript
1848
+ import { Zixflow } from 'zixflow-reactnative';
1849
+
1850
+ // Location tracking is configured via the native SDK
1851
+ // Make sure to request location permissions in your app
1852
+
1853
+ // iOS: Add location permission keys to Info.plist
1854
+ // - NSLocationWhenInUseUsageDescription
1855
+ // - NSLocationAlwaysAndWhenInUseUsageDescription
1856
+
1857
+ // Android: Add location permissions to AndroidManifest.xml
1858
+ // - ACCESS_FINE_LOCATION
1859
+ // - ACCESS_COARSE_LOCATION
225
1860
  ```
226
1861
 
227
- ---
1862
+ Request location permissions using a library like `react-native-permissions`:
228
1863
 
229
- ## 📍 Location Tracking
1864
+ ```typescript
1865
+ import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
1866
+ import { Platform } from 'react-native';
230
1867
 
231
- Track user location (optional feature):
1868
+ const requestLocationPermission = async () => {
1869
+ const permission = Platform.select({
1870
+ ios: PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
1871
+ android: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
1872
+ });
232
1873
 
233
- ```ts
234
- Zixflow.location.setLastKnownLocation(latitude, longitude);
235
- ```
1874
+ if (!permission) return;
1875
+
1876
+ const result = await request(permission);
236
1877
 
237
- ### iOS Location Setup
1878
+ if (result === RESULTS.GRANTED) {
1879
+ console.log('Location permission granted');
1880
+ }
1881
+ };
1882
+ ```
238
1883
 
239
- **Important:** iOS requires location permission descriptions in `Info.plist`. Add these keys or location tracking will silently fail:
1884
+ 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:
240
1885
 
241
- ```xml
242
- <key>NSLocationWhenInUseUsageDescription</key>
243
- <string>We need your location to provide personalized experiences</string>
244
- <key>NSLocationAlwaysUsageDescription</key>
245
- <string>We need your location to provide personalized experiences</string>
1886
+ ```swift
1887
+ NativeZixflow.configureAcknowledgedSceneDeepLinkRouting()
246
1888
  ```
247
1889
 
248
- Add the location pod to your `ios/Podfile`:
249
- ```ruby
250
- pod 'zixflow-reactnative/location', :path => '../node_modules/zixflow-reactnative'
1890
+ Register the app's Zixflow deep-link handler before calling `Zixflow.initialize`. Return
1891
+ `true` after routing a URL. Return `false` to let the native SDK try the host AppDelegate, then pass
1892
+ a host-owned custom scheme to React Native `Linking` or open other URLs through the system. If your
1893
+ handler might decline an app-owned custom scheme, keep a `Linking` URL listener registered for that
1894
+ fallback. A thrown error, rejected promise, missing handler, or handler timeout follows the same
1895
+ native fallback. Cold URLs wait up to ten seconds for registration and are replayed once the handler
1896
+ is ready. After delivery, the handler has ten seconds to settle. If it takes longer, native fallback
1897
+ runs; a handler that later routes the URL can cause a second navigation because its acknowledgement
1898
+ cannot cancel the fallback.
1899
+
1900
+ ```typescript
1901
+ const subscription = Zixflow.setDeepLinkHandler(async (url) => {
1902
+ if (!canRouteInApp(url)) {
1903
+ return false;
1904
+ }
1905
+
1906
+ await routeInApp(url);
1907
+ return true;
1908
+ });
1909
+
1910
+ Zixflow.initialize(config);
251
1911
  ```
252
1912
 
253
- ### Android Location Setup
1913
+ Remove the returned subscription when the routing owner is torn down. If no replacement handler
1914
+ registers, later destinations wait for the readiness timeout and then use the native fallback.
254
1915
 
255
- Enable location tracking in `android/gradle.properties`:
256
- ```properties
257
- zixflow_location_enabled=true
1916
+ The existing `Linking` path remains available for backward compatibility. Keep
1917
+ `NativeZixflow.configureSceneDeepLinkRouting()` in your SceneDelegate, then signal readiness
1918
+ after registering the listener:
1919
+
1920
+ ```typescript
1921
+ const subscription = Linking.addEventListener('url', ({ url }) => {
1922
+ // Route the URL in your app.
1923
+ });
1924
+ Zixflow.setDeepLinkRoutingReady();
258
1925
  ```
259
1926
 
1927
+ Cold destinations wait up to ten seconds for this readiness signal. If it does not arrive, the SDK
1928
+ tries the host AppDelegate, passes a host-owned custom scheme to React Native `Linking`, or opens
1929
+ other URLs through the system.
1930
+
1931
+ 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.
1932
+
1933
+ Expo apps keep the `Linking` path. With config-plugin auto-initialization, register the app's
1934
+ `Linking` listener, then call `Zixflow.setDeepLinkRoutingReady()` after the router is ready. The
1935
+ Expo plugin configures its native scene lifecycle automatically, so Expo app code does not call a
1936
+ native configuration method. Apps using JavaScript initialization register the router before
1937
+ `Zixflow.initialize`; initialization marks Linking ready automatically.
1938
+
1939
+ This integration applies after the host has adopted React Native's UIScene lifecycle; the plugin does not replace React Native's root application lifecycle.
1940
+
1941
+ 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.
1942
+
260
1943
  ---
261
1944
 
262
- ## Advanced Features
1945
+ ## Geofence Tracking
263
1946
 
264
- ### Device Attributes
1947
+ Geofence is an optional module, off by default. Enabling it also enables the Location module, which geofence depends on.
265
1948
 
266
- Set custom device attributes:
1949
+ Enable it at build time:
267
1950
 
268
- ```ts
269
- Zixflow.setDeviceAttributes({
270
- deviceModel: 'iPhone 14 Pro',
271
- appVersion: '2.1.0',
272
- customAttribute: 'value',
273
- });
1951
+ ```properties
1952
+ # android/gradle.properties
1953
+ zixflow_geofence_enabled=true
274
1954
  ```
275
1955
 
276
- ### Register Device Token
1956
+ ```ruby
1957
+ # ios/Podfile
1958
+ pod 'zixflow-reactnative', :subspecs => ['geofence']
1959
+ ```
277
1960
 
278
- Register a device token for push notifications:
1961
+ Then opt in by passing a `geofence` config to `initialize`:
279
1962
 
280
- ```ts
281
- Zixflow.registerDeviceToken('your-device-token');
1963
+ ```typescript
1964
+ import { Zixflow, ZixflowGeofenceLocationMode } from 'zixflow-reactnative';
1965
+
1966
+ Zixflow.initialize({
1967
+ apiKey: 'YOUR_API_KEY',
1968
+ geofence: {
1969
+ // AUTOMATIC (default): the SDK acquires location itself on identify and app launch.
1970
+ // MANUAL: drive refreshes yourself via Zixflow.geofence.refreshFromCurrentLocation().
1971
+ locationMode: ZixflowGeofenceLocationMode.Automatic,
1972
+ },
1973
+ ios: {
1974
+ // Whether geofence transitions are delivered in real time on a background cold-wake.
1975
+ // Defaults to on when the geofence module is enabled.
1976
+ allowBackgroundDelivery: true,
1977
+ },
1978
+ });
282
1979
  ```
283
1980
 
284
- ### Clear Identification
1981
+ Request location permissions the same way as for [Location Tracking](#location-tracking) above — geofence monitoring requires them and the SDK never requests permission itself.
285
1982
 
286
- Clear the current user identification:
1983
+ With `MANUAL` location mode, trigger a refresh after permission is granted:
287
1984
 
288
- ```ts
289
- Zixflow.clearIdentify();
1985
+ ```typescript
1986
+ Zixflow.geofence.refreshFromCurrentLocation();
290
1987
  ```
291
1988
 
1989
+ 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.
1990
+
292
1991
  ---
293
1992
 
294
- ## Platform-Specific Setup
1993
+ ## 🔴 Live Activities
295
1994
 
296
- ### iOS Setup
1995
+ 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:
297
1996
 
298
- 1. Add pods to your `ios/Podfile`:
1997
+ ```xml
1998
+ <key>NSSupportsLiveActivities</key>
1999
+ <true/>
2000
+ ```
299
2001
 
300
- ```ruby
301
- pod 'zixflow-reactnative', :path => '../node_modules/zixflow-reactnative'
2002
+ **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.
302
2003
 
303
- # For FCM push:
304
- pod 'zixflow-reactnative/fcm', :path => '../node_modules/zixflow-reactnative'
2004
+ For an AppDelegate host:
305
2005
 
306
- # For APN push:
307
- pod 'zixflow-reactnative/apn', :path => '../node_modules/zixflow-reactnative'
2006
+ ```swift
2007
+ import zixflow_reactnative
2008
+ import React
308
2009
 
309
- # For location tracking:
310
- pod 'zixflow-reactnative/location', :path => '../node_modules/zixflow-reactnative'
2010
+ extension AppDelegate {
2011
+ func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
2012
+ // Reports an `opened` metric and returns the deep link to route to. A non-Zixflow URL comes
2013
+ // back unchanged; `nil` means the activity carried no deep link, so there is nothing to open.
2014
+ guard let routableUrl = NativeLiveActivities.handleWidgetUrl(url) else { return true }
2015
+ return RCTLinkingManager.application(app, open: routableUrl, options: options)
2016
+ }
2017
+ }
311
2018
  ```
312
2019
 
313
- 2. Run `pod install` in the `ios` directory
2020
+ 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`](/example/ios/SampleApp/AppDelegate.swift) for this in context.
314
2021
 
315
- 3. Follow the [iOS push setup guide](https://zixflow.com/docs/sdk/react-native/push/ios)
2022
+ 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`:
316
2023
 
317
- ### Android Setup
2024
+ ```swift
2025
+ import zixflow_reactnative
318
2026
 
319
- #### Requirements
2027
+ reactNativeFactory?.startReactNative(
2028
+ withModuleName: "YourApp",
2029
+ in: window,
2030
+ launchOptions: NativeLiveActivities.reactNativeLaunchOptions(from: connectionOptions)
2031
+ )
2032
+ ```
320
2033
 
321
- - **compileSdkVersion**: 36 or higher
322
- - **Android Gradle Plugin**: 8.9.1 or higher
323
- - **Gradle**: 8.11.1 or higher
324
- - **minSdkVersion**: 21 or higher
325
- - **Kotlin**: 1.9.25 or higher
2034
+ 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`:
326
2035
 
327
- #### Configuration
2036
+ ```swift
2037
+ import zixflow_reactnative
328
2038
 
329
- 1. Update your `android/build.gradle`:
2039
+ func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
2040
+ for context in URLContexts {
2041
+ NativeLiveActivities.handleAndRouteWidgetUrl(context.url)
2042
+ }
2043
+ }
2044
+ ```
330
2045
 
331
- ```gradle
332
- buildscript {
333
- ext {
334
- compileSdkVersion = 36
335
- buildToolsVersion = "36.0.0"
336
- minSdkVersion = 21
337
- targetSdkVersion = 36
338
- }
339
- dependencies {
340
- classpath("com.android.tools.build:gradle:8.9.1")
341
- }
2046
+ Do not also pass those URLs to `RCTLinkingManager`. The helper already routes them through the
2047
+ Zixflow bridge, and forwarding them again can deliver the same URL twice.
2048
+
2049
+ Android needs no equivalent native step.
2050
+
2051
+ For Expo Router, unwrap the URL once in the app's top-level `app/+native-intent.tsx` file:
2052
+
2053
+ ```typescript
2054
+ import { Zixflow } from 'zixflow-reactnative';
2055
+
2056
+ export async function redirectSystemPath({ path }: { path: string }) {
2057
+ return Zixflow.liveActivities.handleWidgetUrl(path);
342
2058
  }
343
2059
  ```
344
2060
 
345
- 2. Update `android/gradle/wrapper/gradle-wrapper.properties`:
2061
+ This reports the opened event, returns the customer's destination, preserves ordinary URLs, and
2062
+ returns `null` for a Zixflow tracking URL without a destination. Do not also call the helper
2063
+ from a `Linking` listener because processing the same tracking URL twice reports two opened events.
2064
+ Expo apps without Expo Router can apply the helper once in their central `Linking` initial-URL and
2065
+ subscription pipeline.
346
2066
 
347
- ```properties
348
- distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
2067
+ ---
2068
+
2069
+ ## Notification Inbox
2070
+
2071
+ The Visual Notification Inbox renders received messages in a list the SDK owns the design of. Two components are available:
2072
+
2073
+ - `NotificationInboxBellView` — a bell icon with an unread badge. Tapping it opens the SDK's own inbox panel; the host presents nothing.
2074
+ - `NotificationInboxView` — the message list itself, embeddable directly in your own screen with no surrounding chrome (no bell, no scrim).
2075
+
2076
+ ```tsx
2077
+ import { NotificationInboxBellView, NotificationInboxView } from 'zixflow-reactnative';
2078
+
2079
+ // Place the bell wherever your layout calls for it. Give it a fixed size for
2080
+ // predictable layout — at least 88 points/dp square.
2081
+ <NotificationInboxBellView
2082
+ style={{ width: 88, height: 88 }}
2083
+ onTap={() => analytics.track('inbox_bell_tapped')}
2084
+ />
2085
+
2086
+ // Or embed the message list directly in a screen of your own.
2087
+ <NotificationInboxView style={{ flex: 1 }} />
349
2088
  ```
350
2089
 
351
- 3. Add Kotlin compiler flag in `android/app/build.gradle`:
2090
+ `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.
352
2091
 
353
- ```gradle
354
- android {
355
- // ... other config
356
- }
2092
+ Remote branding styles the bell and list themselves (colors, icon); the host still owns layout and placement via `style`.
357
2093
 
358
- tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
359
- kotlinOptions {
360
- freeCompilerArgs += ['-Xskip-metadata-version-check']
361
- }
362
- }
2094
+ 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:
2095
+
2096
+ ```typescript
2097
+ Zixflow.initialize({
2098
+ apiKey: 'YOUR_API_KEY',
2099
+ inApp: {
2100
+ notificationInboxAccessibilityLabels: {
2101
+ bell: t('inbox.bell'),
2102
+ bellWithUnreadCount: t('inbox.unread'), // e.g. "{count} unread notifications"
2103
+ loadingIndicator: t('inbox.loading'),
2104
+ emptyState: t('inbox.empty'),
2105
+ },
2106
+ },
2107
+ });
363
2108
  ```
364
2109
 
365
- 4. The SDK is automatically linked via autolinking
2110
+ Register a listener to observe inbox events (shown, opened, dismissed, and non-dismiss actions taken on a message):
366
2111
 
367
- 5. (Optional) Enable location tracking in `android/gradle.properties`:
2112
+ ```typescript
2113
+ import { InboxEventType } from 'zixflow-reactnative';
368
2114
 
369
- ```properties
370
- zixflow_location_enabled=true
2115
+ const subscription = Zixflow.inAppMessaging.registerInboxEventListener((event) => {
2116
+ switch (event.eventType) {
2117
+ case InboxEventType.messageActionTaken:
2118
+ // event.actionName / event.actionValue are only present for this event
2119
+ console.log('Inbox action taken:', event.actionName, event.actionValue);
2120
+ break;
2121
+ case InboxEventType.messageShown:
2122
+ case InboxEventType.messageOpened:
2123
+ case InboxEventType.messageDismissed:
2124
+ console.log(event.eventType, event.message);
2125
+ break;
2126
+ }
2127
+ });
2128
+
2129
+ // Remove listener
2130
+ subscription.remove();
371
2131
  ```
372
2132
 
373
- 6. Follow the [Android push setup guide](https://zixflow.com/docs/sdk/react-native/push/android)
2133
+ You can also fetch and manage inbox messages directly through `Zixflow.inAppMessaging.inbox()`:
374
2134
 
375
- ---
2135
+ ```typescript
2136
+ const inbox = Zixflow.inAppMessaging.inbox();
376
2137
 
377
- ## Configuration Options
2138
+ const messages = await inbox.getMessages();
378
2139
 
379
- | Option | Type | Required | Description |
380
- |--------|------|----------|-------------|
381
- | `cdpApiKey` | `string` | ✅ | Your Zixflow API key |
382
- | `migrationSiteId` | `string` | ❌ | Site ID for migration from older SDKs |
383
- | `logLevel` | `ZixflowLogLevel` | ❌ | Logging verbosity (default: error) |
384
- | `trackApplicationLifecycleEvents` | `boolean` | ❌ | Auto-track app lifecycle events |
385
- | `inApp` | `object` | ❌ | In-app messaging configuration |
386
- | `push` | `object` | ❌ | Push notification configuration |
2140
+ inbox.markMessageOpened(message);
2141
+ inbox.markMessageDeleted(message);
2142
+ ```
387
2143
 
388
2144
  ---
389
2145
 
390
- ## TypeScript Support
2146
+ ## Advanced Configuration
2147
+
2148
+ ### Log Levels
391
2149
 
392
- This SDK is written in TypeScript and includes full type definitions:
2150
+ Control SDK logging for debugging:
393
2151
 
394
- ```ts
395
- import type {
396
- Zixflow,
397
- ZixflowConfig,
398
- ZixflowInAppMessaging,
399
- ZixflowPushMessaging,
400
- ZixflowLocation,
401
- CustomAttributes,
402
- IdentifyParams,
403
- InAppMessage,
404
- InboxMessage,
405
- } from 'zixflow-reactnative';
2152
+ ```typescript
2153
+ import { Zixflow, ZixflowLogLevel } from 'zixflow-reactnative';
2154
+
2155
+ const config = {
2156
+ apiKey: 'YOUR_API_KEY',
2157
+ logLevel: ZixflowLogLevel.debug, // debug, info, error, none
2158
+ };
2159
+
2160
+ Zixflow.initialize(config);
406
2161
  ```
407
2162
 
408
- ---
2163
+ **Log levels**:
2164
+ - `ZixflowLogLevel.debug` - Verbose logging (development)
2165
+ - `ZixflowLogLevel.info` - Informational messages
2166
+ - `ZixflowLogLevel.error` - Errors only
2167
+ - `ZixflowLogLevel.none` - No logging (production)
2168
+
2169
+ ### Auto-Tracking Options
409
2170
 
410
- ## Module APIs
2171
+ Configure automatic tracking features:
411
2172
 
412
- Access specific SDK modules:
2173
+ ```typescript
2174
+ import { Zixflow } from 'zixflow-reactnative';
413
2175
 
414
- ```ts
415
- // In-app messaging
416
- Zixflow.inAppMessaging.registerEventsListener(listener);
2176
+ const config = {
2177
+ apiKey: 'YOUR_API_KEY',
417
2178
 
418
- // Push messaging
419
- Zixflow.pushMessaging.showPromptForPushNotifications();
2179
+ // Automatically track device attributes (OS, model, app version)
2180
+ autoTrackDeviceAttributes: true,
420
2181
 
421
- // Location tracking
422
- Zixflow.location.setLastKnownLocation(lat, lng);
2182
+ // Automatically track app lifecycle events (open, close, background)
2183
+ trackApplicationLifecycleEvents: true,
2184
+
2185
+ // Automatically track screens (requires integration)
2186
+ autoTrackScreenViews: true,
2187
+ };
2188
+
2189
+ Zixflow.initialize(config);
423
2190
  ```
424
2191
 
425
- Note: Due to JavaScript limitations, module properties return the internal implementation instances, but all functionality works as expected.
2192
+ ### Custom API Hosts
2193
+
2194
+ Override API endpoints for testing or custom infrastructure:
2195
+
2196
+ ```typescript
2197
+ import { Zixflow } from 'zixflow-reactnative';
2198
+
2199
+ const config = {
2200
+ apiKey: 'YOUR_API_KEY',
2201
+
2202
+ // Custom tracking API host
2203
+ trackingApiUrl: 'https://custom-track.zixflow.com',
2204
+
2205
+ // Custom in-app messaging API host
2206
+ inApp: {
2207
+ // Override in-app messaging API endpoint if needed
2208
+ },
2209
+ };
2210
+
2211
+ Zixflow.initialize(config);
2212
+ ```
426
2213
 
427
2214
  ---
428
2215
 
429
- ## Example App
2216
+ ## Example Applications
2217
+
2218
+ The Zixflow React Native SDK includes example applications demonstrating best practices:
2219
+
2220
+ ### Sample App (APNs)
430
2221
 
431
- Check out our comprehensive [example app](/example) that demonstrates:
2222
+ Location: `example/`
432
2223
 
433
- - SDK initialization
434
- - User identification
2224
+ **Features**:
2225
+ - User identification and logout
435
2226
  - Event tracking
436
- - Push notifications
437
- - In-app messaging
438
- - Location tracking
439
- - Inbox management
2227
+ - Screen tracking with React Navigation
2228
+ - Push notifications with APNs
2229
+ - In-app messaging with event listeners
2230
+ - Profile and device attributes
440
2231
 
441
- To run the example app:
2232
+ **Running the example**:
442
2233
 
443
2234
  ```bash
2235
+ # Install dependencies
444
2236
  cd example
445
2237
  npm install
446
2238
 
@@ -454,64 +2246,174 @@ npx react-native run-android
454
2246
 
455
2247
  ---
456
2248
 
457
- ## Troubleshooting
2249
+ ## API Reference
458
2250
 
459
- ### Common Issues
2251
+ ### Core SDK
460
2252
 
461
- **Issue: Build fails with "Zixflow pod not found"**
462
- - Run `pod install` in your iOS directory
463
- - Make sure you're using the correct pod name: `zixflow-reactnative`
2253
+ #### `Zixflow.initialize(config: ZixflowConfig): void`
464
2254
 
465
- **Issue: Push notifications not working**
466
- - Verify your Firebase configuration (Android) or APNs certificates (iOS)
467
- - Check that you've requested push permissions
468
- - Ensure you've registered the device token
2255
+ Initialize the SDK with configuration.
469
2256
 
470
- **Issue: In-app messages not showing**
471
- - Verify you've configured `inApp.siteId` in the config
472
- - Check that you've registered an events listener
473
- - Ensure messages are targeted correctly in your Zixflow dashboard
2257
+ ```typescript
2258
+ Zixflow.initialize({
2259
+ apiKey: 'YOUR_API_KEY',
2260
+ });
2261
+ ```
474
2262
 
475
- For more help, see our [troubleshooting guide](https://zixflow.com/docs/sdk/react-native/troubleshooting/) or [open an issue](https://github.com/zixflow/zixflow-reactnative/issues).
2263
+ #### `Zixflow.identify(params: { userId: string; traits?: object }): void`
476
2264
 
477
- ---
2265
+ Identify a user with optional traits.
478
2266
 
479
- ## Requirements
2267
+ ```typescript
2268
+ Zixflow.identify({
2269
+ userId: 'user-123',
2270
+ traits: { email: 'user@example.com' }
2271
+ });
2272
+ ```
480
2273
 
481
- - React Native 0.70+
482
- - iOS 13+
483
- - Android API 21+ (Android 5.0 Lollipop)
484
- - Swift 5.3+
485
- - Kotlin 1.8+
2274
+ #### `Zixflow.clearIdentify(): void`
486
2275
 
487
- ---
2276
+ Clear the current user's identity.
488
2277
 
489
- ## Contributing
2278
+ ```typescript
2279
+ Zixflow.clearIdentify();
2280
+ ```
490
2281
 
491
- We welcome contributions! To get started:
2282
+ #### `Zixflow.track(name: string, properties?: object | Map<string, any>): void`
492
2283
 
493
- 1. Review our [example app](/example) to help with local development
494
- 2. Follow our [Code of Conduct](CODE_OF_CONDUCT.md)
495
- 3. Check out [DEVELOPMENT.md](DEVELOPMENT.md) for development guidelines
496
- 4. Open issues or pull requests on [GitHub](https://github.com/zixflow/zixflow-reactnative)
2284
+ Track a custom event.
497
2285
 
498
- ---
2286
+ ```typescript
2287
+ Zixflow.track('button_clicked', { button_name: 'signup' });
2288
+ ```
499
2289
 
500
- ## Support
2290
+ #### `Zixflow.screen(name: string, properties?: object): void`
501
2291
 
502
- - 📚 [Documentation](https://zixflow.com/docs/sdk/react-native/)
503
- - 💬 [Community Forum](https://community.zixflow.com)
504
- - 🐛 [Issue Tracker](https://github.com/zixflow/zixflow-reactnative/issues)
505
- - 📧 Email: apps@zixflow.com
2292
+ Track a screen view.
506
2293
 
507
- ---
2294
+ ```typescript
2295
+ Zixflow.screen('HomeScreen');
2296
+ ```
508
2297
 
509
- ## License
2298
+ #### `Zixflow.setProfileAttributes(attributes: object): void`
510
2299
 
511
- [MIT](LICENSE)
2300
+ Set attributes on the user profile.
512
2301
 
513
- ---
2302
+ ```typescript
2303
+ Zixflow.setProfileAttributes({ plan: 'premium' });
2304
+ ```
2305
+
2306
+ #### `Zixflow.setDeviceAttributes(attributes: object): void`
2307
+
2308
+ Set attributes on the current device.
2309
+
2310
+ ```typescript
2311
+ Zixflow.setDeviceAttributes({ app_version: '2.0.0' });
2312
+ ```
2313
+
2314
+ ### Push Messaging
2315
+
2316
+ #### `Zixflow.pushMessaging.showPromptForPushNotifications(options): Promise<ZixflowPushPermissionStatus>`
2317
+
2318
+ Request push notification permission.
2319
+
2320
+ ```typescript
2321
+ const status = await Zixflow.pushMessaging.showPromptForPushNotifications({
2322
+ ios: { sound: true, badge: true }
2323
+ });
2324
+ ```
2325
+
2326
+ ### In-App Messaging
2327
+
2328
+ #### `Zixflow.inAppMessaging.registerEventsListener(callback): EventSubscription`
2329
+
2330
+ Register a listener for in-app message events.
2331
+
2332
+ ```typescript
2333
+ const listener = Zixflow.inAppMessaging.registerEventsListener((event) => {
2334
+ console.log('In-app event:', event);
2335
+ });
2336
+
2337
+ // Remove listener
2338
+ listener.remove();
2339
+ ```
2340
+
2341
+ #### `Zixflow.inAppMessaging.dismissMessage(): void`
2342
+
2343
+ Dismiss the currently displayed in-app message.
2344
+
2345
+ ```typescript
2346
+ Zixflow.inAppMessaging.dismissMessage();
2347
+ ```
2348
+
2349
+ ### Types
2350
+
2351
+ #### `ZixflowConfig`
2352
+
2353
+ Configuration object for SDK initialization.
2354
+
2355
+ ```typescript
2356
+ interface ZixflowConfig {
2357
+ apiKey: string;
2358
+ logLevel?: ZixflowLogLevel;
2359
+ inApp?: {
2360
+ };
2361
+ autoTrackDeviceAttributes?: boolean;
2362
+ trackApplicationLifecycleEvents?: boolean;
2363
+ autoTrackScreenViews?: boolean;
2364
+ trackingApiUrl?: string;
2365
+ }
2366
+ ```
2367
+
2368
+ #### `ZixflowLogLevel`
2369
+
2370
+ Log level enum.
2371
+
2372
+ ```typescript
2373
+ enum ZixflowLogLevel {
2374
+ none = 'none',
2375
+ error = 'error',
2376
+ info = 'info',
2377
+ debug = 'debug'
2378
+ }
2379
+ ```
2380
+
2381
+ #### `ZixflowPushPermissionStatus`
2382
+
2383
+ Push notification permission status.
2384
+
2385
+ ```typescript
2386
+ enum ZixflowPushPermissionStatus {
2387
+ Granted = 'granted',
2388
+ Denied = 'denied',
2389
+ NotDetermined = 'notDetermined'
2390
+ }
2391
+ ```
2392
+
2393
+ #### `InAppMessageEventType`
514
2394
 
515
- ## Acknowledgments
2395
+ In-app message event types.
2396
+
2397
+ ```typescript
2398
+ enum InAppMessageEventType {
2399
+ messageShown = 'messageShown',
2400
+ messageDismissed = 'messageDismissed',
2401
+ messageActionTaken = 'messageActionTaken',
2402
+ errorWithMessage = 'errorWithMessage'
2403
+ }
2404
+ ```
2405
+
2406
+ #### `InAppMessageEvent`
2407
+
2408
+ In-app message event object.
2409
+
2410
+ ```typescript
2411
+ interface InAppMessageEvent {
2412
+ eventType: InAppMessageEventType;
2413
+ deliveryId?: string;
2414
+ messageId?: string;
2415
+ actionName?: string;
2416
+ actionValue?: string;
2417
+ }
2418
+ ```
516
2419
 
517
- This SDK is based on the Zixflow React Native SDK and maintains compatibility with the Zixflow platform while providing Zixflow-specific optimizations and branding.