Push notifications
Deliver push tokens to the SDK, configure native iOS and Android push handling, track notification clicks, and handle deeplinks. Setup spans three layers: JavaScript for token forwarding and deeplink listening, native iOS for APNs, and native Android for Firebase.
Integrating push notifications involves forwarding device tokens to the SDK from JavaScript, setting up native push services, and handling notification clicks and deep links. This guide will walk you through the process.
On this page
- How delivery and click tracking work
- Forward the device token in JavaScript
- Configure iOS native push setup
- Re-register the token after iOS app updates
- Configure Android native push setup
- Rich notification support
- Handle notification clicks in JavaScript (Android)
- Configure deep linking and navigation
- Handle Android deep links
How delivery and click tracking work
Push delivery and click tracking are handled by the underlying native SDKs. ZMP sends the notification through APNs (iOS) or FCM (Android); the native SDK reports an on-device delivery receipt back to ZMP and attributes clicks to the originating campaign. The React Native layer's job is narrow: forward the device token to the SDK, and surface click and deep-link events to your JavaScript so you can route the user.
flowchart TB
subgraph JS["JavaScript Layer"]
APP["Your React Native App"]
end
subgraph Bridge["React Native Bridge"]
RN["zetakit_reactnative"]
end
subgraph Native["Native SDK Layer"]
direction LR
IOS["Zeta iOS SDK"]
ANDROID["Zeta Android SDK"]
end
subgraph Providers["Push Providers"]
direction LR
APNs
FCM
end
ZMP["Zeta Marketing Platform"]
%% Token registration (solid)
APP -- "updateDeviceToken()" --> RN
RN --> IOS & ANDROID
IOS & ANDROID -- "register token" --> ZMP
%% Notification delivery (dashed) — native-only, no bridge
ZMP -. "send push" .-> APNs & FCM
APNs -. "deliver" .-> IOS
FCM -. "deliver" .-> ANDROID
%% Click/deeplink events (thick) — after user tap
IOS == "click / deeplink" ==> RN
ANDROID == "click / deeplink" ==> RN
RN == "event" ==> APP
Solid lines (→): token registration through the bridge. Dashed lines (⇢): notification delivery at the native layer — the bridge is not involved. Thick lines (⇒): click and deeplink events routed to JavaScript after a user tap.
Note: Notification delivery and display are handled entirely at the native layer by
ZTPushService(Android) and the Notification Service Extension (iOS). The React Native bridge is only involved for token forwarding and for routing click/deeplink events to your JavaScript code after a user taps a notification.
For the full delivery lifecycle, the event matrix, and native diagnostics, see the platform push guides and their FAQs:
- iOS Push Notifications and iOS Push Troubleshooting.
- Android Push Notifications and Android Push Troubleshooting.
Tip: After an app update, re-forward the device token on the next launch (see Forward the device token) so ZMP continues to target the device.
Forward the device token in JavaScript
To target your device with push notifications from ZMP, you must forward the native push token to the SDK from your JavaScript code:
ZetaClient.user.updateDeviceToken('your-device-push-token-string');Receive the token via the bridge (Android)
On Android, instead of reading the token from native code, you can let the SDK emit it to JavaScript. Call ZetaClient.push.fetchToken() and listen for ZetaCoreEvents.DeviceTokenDelegate, which delivers the current push token as { deviceToken }:
import { DeviceEventEmitter } from 'react-native';
import ZetaClient, { ZetaCoreEvents } from 'zetakit_reactnative';
const tokenListener = DeviceEventEmitter.addListener(
ZetaCoreEvents.DeviceTokenDelegate,
({ deviceToken }) => {
ZetaClient.user.updateDeviceToken(deviceToken);
}
);
// Ask the SDK to emit the current token to the listener above.
ZetaClient.push.fetchToken();iOS:
fetchToken()is a no-op on iOS. Obtain the APNs token natively in yourAppDelegateand forward it withZetaClient.user.updateDeviceToken(). See Configure iOS native push setup.
Tip: On iOS, and on Android 13+, notifications require the user's explicit permission. Call
ZetaClient.push.requestNotificationPermissions()to prompt the user before you rely on token delivery.
Configure iOS native push setup
The iOS side of your React Native application requires native configuration in the ios/ directory to handle APNs registration, token forwarding, and rich notification delivery tracking.
Add CocoaPods Dependencies
To support rich push notifications (images, videos, GIFs) and delivery tracking, add the ZetaNotificationService pod to your Notification Service Extension target in your ios/Podfile:
target 'NotificationServiceExtension' do
pod 'ZetaNotificationService'
endRun pod install in your ios directory after updating the Podfile.
Complete Native APNs Setup
All APNs registration, device token formatting, and Notification Service Extension code are implemented in native Swift.
For the complete, native setup guides, refer to:
- iOS Push Notifications Guide — Covers APNs registration, AppDelegate token forwarding, and rich media extension setup.
Re-register the token after iOS app updates
During an app update, application(_:didRegisterForRemoteNotificationsWithDeviceToken:) is not guaranteed to fire automatically, so the SDK may not receive the current token after the update.
To ensure the SDK receives the latest token, explicitly re-register for remote notifications at launch in your native iOS code:
if UIApplication.shared.isRegisteredForRemoteNotifications {
UIApplication.shared.registerForRemoteNotifications()
}When the refreshed token arrives, forward it to the SDK from JavaScript with ZetaClient.user.updateDeviceToken() so ZMP continues to target the device.
Configure Android native push setup
The Android side of your React Native application requires native configuration in the android/ directory to handle Firebase Cloud Messaging (FCM) and customize notification appearance.
Add Firebase Dependencies
Add the Firebase Messaging dependency to your android/app/build.gradle file:
dependencies {
implementation("com.google.firebase:firebase-messaging:24.1.0")
}Complete Native FCM Setup
The SDK includes a built-in push service that automatically captures and registers device tokens. If you need to customize notification channels, colors, icons, or integrate a custom FirebaseMessagingService, you will configure these in your native Kotlin code.
For the complete, native setup guides, refer to:
- Android Push Notifications Guide — Covers FCM registration, custom push service configuration, and background action callbacks.
Rich notification support
Rich notifications display images, GIFs, or videos in the notification banner.
- iOS: Rich media requires a Notification Service Extension with the
ZetaNotificationServicepod. See Configure iOS native push setup and the iOS Push Notifications Guide. - Android: The native SDK renders rich media automatically — no additional configuration is required.
Handle notification clicks in JavaScript (Android)
On Android, when a user taps a push notification, you can process the payload and track the click directly from your JavaScript code using the Promise-based handleNotificationsMessage API:
const handled = await ZetaClient.push.handleNotificationsMessage(response);
if (handled) {
// The Zeta SDK successfully processed the notification click.
}iOS: On iOS, track notification clicks natively via
UNUserNotificationCenterDelegate. See Configure iOS native push setup and the iOS Push Notifications Guide.
Configure deep linking and navigation
ZMP campaigns can deliver deep links to navigate users to specific screens when they tap a notification.
Register the Deeplink Delegate
Set up the deep link delegate in your JavaScript code after the SDK initializes:
ZetaClient.initialize(config, () => {
ZetaClient.push.setDeeplinkDelegate();
});Platform Behavior:
setDeeplinkDelegate()andnotifyReactNativeNavigationReady()are iOS-only. On Android, handle deep links through the intent-based flow described in Handle Android deep links.
Signal Navigation Readiness
If you are using a navigation library like React Navigation, notify the SDK when your navigation container is fully loaded and ready to handle routing:
<NavigationContainer onReady={() => ZetaClient.push.notifyReactNativeNavigationReady()}>Listen for Deeplink Events
Set up an event listener to receive deep link events and route the user to the target screen:
import { Platform, NativeEventEmitter, DeviceEventEmitter } from 'react-native';
import ZetaClient, { ZetaCoreEvents } from 'zetakit_reactnative';
const eventEmitter = Platform.select({
ios: new NativeEventEmitter(ZetaClient.bridge),
android: DeviceEventEmitter,
});
const deeplinkListener = eventEmitter?.addListener(
ZetaCoreEvents.DeeplinkDelegate,
(event) => {
const { deeplink, extraInfo } = event;
console.log('Navigate to:', deeplink);
console.log('Additional campaign data:', extraInfo);
// Perform your app's custom navigation routing here
}
);Handle Android deep links
On Android, deep links arrive as Android intents rather than through the DeeplinkDelegate flow. Read the intent that launched the app, and listen for intents that arrive while the app is already running.
When the app is launched from a notification (cold start), read the launching intent once with the Promise-based getInitialIntent():
const intent = await ZetaClient.push.getInitialIntent();
if (intent?.data) {
// Route to the screen described by intent.data / intent.extras
}When a notification is tapped while the app is already running, the SDK emits the intent as an event. Listen for both the initial and subsequent intents:
import { DeviceEventEmitter } from 'react-native';
import ZetaClient, { ZetaCoreEvents } from 'zetakit_reactnative';
const initialIntentListener = DeviceEventEmitter.addListener(
ZetaCoreEvents.AndroidInitialIntent,
(intent) => {
// Same shape as getInitialIntent(): { action, type, data, scheme, extras }
}
);
const newIntentListener = DeviceEventEmitter.addListener(
ZetaCoreEvents.AndroidNewIntent,
(intent) => {
// Fired when a notification is tapped while the app is running
}
);Note:
AndroidInitialIntentandAndroidNewIntentare Android-only. Use theDeeplinkDelegateflow above for iOS.
Next
Now that push notifications are configured, continue your journey:
- In-App Messaging — Display foreground-only messages and collect user emails.
- Push Troubleshooting — Diagnose bridge-specific push failures.
- Testing and QA — Verify your push integration before release.
- User Guide: Push Notifications — Campaign setup and targeting from ZMP.
See also
- Platform support -- feature availability by platform and SDK version.

