React Native Mobile SDK 0.1.0
SDK Support and Compatibility
- React Native version: 0.76 and above.
- iOS: Minimum deployment target is iOS 15.1
- Android: Minimum supported version is Android 7.0 (API level 24). Set minSdkVersion to 24 or higher in your android/app/build.gradle file.
- Android Compile SDK: No special requirements besides including the plugin (which includes Zeta’s Android libraries). Ensure your Android project has Google Play Services and Firebase Messaging set up if using push notifications.
Native SDK compatibility
Installation
Add the zetakit_reactnative
package as a dependency in your project's package.json
. For example:
"dependencies": {
"react": "19.0.0",
"react-native": "0.79.2",
"zetakit_reactnative":"^0.1.0"
}
After updating package.json
, run the installation command to install all dependencies(yarn install or npm install):
Alternatively, you can directly add the zetakit_reactnative
package using one of the following commands, which will update package.json
and install the package:
yarn add zetakit_reactnative
or
npm install zetakit_reactnative
Mobile App Registration
Please follow the instructions outlined in the provided link to register your app with the ZMP platform: https://knowledgebase.zetaglobal.com/kb/mobile-app-registration
Initializing the SDK
Before using Zeta features, initialize the SDK with your configuration. Do this once when the app starts
import ZetaCore from "zetakit_reactnative";
const App = () => {
useEffect(() => {
const config = { "isLoggingEnabled": true,
"clientSiteId": "", // platform specific android and iOS client Site ID
"clientSecret": "", // platform specific android and iOS client Secret.
"region": "US",
"appGroupId": "group.com.zetaglobal.Zeta-Sample-App",
"optIn": true ,
"appEnvironment": "PRODUCTION"
}
ZetaCore.initialize(config, () => { })
}, []);
return (
<UI Components />
)
}
export default App;
ZTConfig parameters
- clientSiteId / clientSecret: Obtain these from the Zeta Marketing Platform (ZMP) console when you register your app. They authenticate your app with Zeta’s servers.
- isLoggingEnabled - Enable (true) to see verbose SDK logs in the console (useful for debugging); default is off.
- optIn- A boolean controls whether the SDK should actively track events (true to track, false to start in an opted-out state). If you set optIn: false, the SDK will not send or store events until you opt-in later.
- region- The SDK supports region configuration; currently we support either “US“ or “EU”. Regions cannot be interchanged for the same ZMP account. Based on the region, the clientSecret and clientSiteId may change.
- appGroupId (optional): appGroupId is used to track notification delivery status, please look into Push Notification for more details
- appEnvironment (optional): representing the application environment for the SDK , by default the parameter value will be Production. appEnvironment is used to decide the respective APNS environment for push notifications from iOS.
How to initialize the ZetaCoreReactNative
The ZetaCore initialize should be called in a standard application at the beginning of the lifecycle.
During this initialization, siteId, optIn and region are mandatory fields, and by default, logging will be disabled.
For the SDK to communicate with the server, clientSecretKey is required. The auth key can be provided either during the SDK initialization or through a late setClientSecret method.
ZetaCore.setClientSecret(clientSecret)
Native Initialization
We can also initialize the SDK natively as per below documentation for android and iOS host applications of React Native app.
Android:
inside Application.kt onCreate we can add the initialization
import ZetaCore
override fun onCreate() {
val config = ZTConfig(
clientSiteId = "YOUR_SITE_ID",
clientSecret = "YOUR_CLIENT_SECRET",
isLoggingEnabled = true,
optIn = true,
region = ZTRegion.US,
appEnvironment: ZTAppEnvironment.PRODUCTION
)
ZetaClient.initialize(this, config)
}
iOS:
inside AppDelegate.swift didFinishLaunchingWithOptions we can add the initialization
import ZetaCore
func initializeSDK() {
let config = ZTConfig(isLoggingEnabled: true,
clientSiteId: "YOUR_SITE_ID",
clientSecret: "YOUR_CLIENT_SECRET",
region: ZTRegion.US,
appGroupId: "group.com.zetaglobal.Zeta-Sample-App",
optIn: true,
appEnvironment: ZTAppEnvironment.PRODUCTION)
ZetaClient.shared.initialize(config: config) {}
}
BSIN and User Session Management
Zeta uses a BSIN (Browser/Session Identification Number) to uniquely identify a user’s session. In React Native:
- To listen to lifecycle changes of BSIN, you can set listener as below
import ZetaCore, {ZetaCoreEvents} from 'zetakit_reactnative'
const eventEmitter = Platform.select({
ios: new NativeEventEmitter(ZetaCore.bridge),
android: DeviceEventEmitter
});
const identityEventListener = eventEmitter?.addListener(ZetaCoreEvents.IdentityDelegate, (event) => {
console.log(event.bsin)
});
- To listen to lifecycle changes of BSIN, you can set delegate use ZetaCore.setIdentityDelegate()
- Get cached BSIN: Retrieve the current BSIN at any time.
ZetaCore.getCachedBsin();
Note: we can call these two methods after SDK is initialized as per example below.
ZetaCore.initialize(config, () => {
// callback
ZetaCore.setIdentityDelegate()
ZetaCore.getCachedBSIN()
})
Tracking Opt-in and Opt-out
When the application does not require the SDK to track events and user properties, it can utilize the opt-out feature. The application sends the opt-out configuration as part of its initialization or can call a separate opt-out method. If the application is using SDK-exposed methods for opting in or out, the same status should be sent through the SDK initialization configuration during the next launch. Otherwise, the configuration value may overwrite the opt-in/out status. Once the SDK receives the opt-out request, it will immediately stop all communication with the back end, and any data cached in the database will also be cleared. Until the application opts back in, the SDK will neither collect data from the application nor send data to the server. The application can opt in or out at any time during its lifecycle. After opting out, if the application opts back in, the SDK will consider it a fresh launch.
Tracking opt-out
Tracking of SDK can be disabled in two ways:
- Pass opt-in as false during initialization
import ZetaCore from 'zetakit_reactnative' const config = { "isLoggingEnabled": true, "clientSiteId": "", "clientSecret": "", "region": "US", "appGroupId": "group.com.zetaglobal.Zeta-Sample-App", "appEnvironment": "PRODUCTION", "optIn": false } ZetaCore.initialize(config, () => { })
- Call stop tracking method
ZetaCore.optOutFromTracking()
Tracking opt-in
To start tracking again you can pass optin as true in config during ZetaCore.initialize() or call ZetaCore.optInForTracking(uid)
uid: At the time of opt-in, the uid field is optional for identifying the user from the SDK's perspective. If the application does not provide a user ID, the SDK will consider the user as an anonymous user.
If the application is using SDK-exposed methods for opting in or out, the same status should be sent through the SDK initialization configuration during the next launch. Otherwise, the configuration value may overwrite the opt-in/out status.
User Identification
Update User Properties
The client app can update the user data using the builder pattern or by creating a ZTUser object at the app level and calling the updateUser method to pass the data to the SDK.
// Update user via builder method
const user = {
'firstName': first_Name,
'lastName': last_Name,
'name': name,
'signedUpAt': signedUpAt,
'source': source,
'email': {'email': ''},
'phone': {'phone': ''},
'additionalProperties': {"zt_test_string": "zt_test_value",
"zt_test_number": 123,
"zt_test_boolean": true,
"zt_test_array": ["zt_test_value1",
"zt_test_value2",
"zt_test_value3"],
"zt_test_dict": ["zt_test_dict_key": "zt_test_dict_value"}
}
ZetaCore.build(user)
//Update user via passing ZTUser object to update user
ZetaCore.updateUser({"name": "John Wick"})
For contact information (email, phone number), the client app can also pass the additional info to the SDK.
// we can update contacts with additional properties if needed
const user = {{
"email": "",
"additionalInfo": {
"inactivityReason": "",
"signedUpAt": "",
"doubleOptInStatus": "",
"phoneType": "",
"lastSent": "",
"lastOpened": "",
"lastClicked": "",
"preference": "",
"subscriptionStatus": "",
"properties": {}
}}
ZetaCore.build(user)
//ZTContactAdditionalInfo values
preference: [String] - the default value will be "standard"
subscriptionStatus: ZTContactSubscriptionStatus - value can be NEW, ACTIVE,INACTIVE, NONE
properties: Additioncal contact properties can be added through this dictionary
Notes
- All date-time should be in ISO 8601 format in UTC
- preference of contact defaults to standard but other preferences can be added/customized within the settings menu in ZMP. Only those defined values can be passed in preference
- double_opt_in_status optional field to track double opt ins - default value is null, but will accept single or double values
- phone_type optional field for phone contact types. default value is null, accepts mobile or landline values
- additionalProperties field is an optional field that can be used to include any custom key-value pairs as part of the user data payload. These custom attributes will appear under the User Properties section in ZMP.
How to start the User Identity Session
The SDK supports tracking user session-specific properties and events. Setting the uid property will facilitate session tracking.
//update uid via builder pattern
ZetaCore.build({ 'uid': "john123" })
//update uid via ZTUser
ZetaCore.updateUser({"uid": "john123"})
How to clear the User Identity Session
clear() method removes the currently stored user session.
ZetaCore.clear()
Note: It is recommended to invoke the clear() method whenever there is a change in the user profile within the application.
Set App Set ID and Set Advertising ID (IDFA/AAID):
//Google AdvertisementId(GAID) or IDFA
ZetaCore.updateIDFA(idfa)
//App Set Id or IDFV
ZetaCore.updateIDFV(idfv)
Location Tracking
location: This method can be called by passing the location coordinates along with foreground / background state. The foreground / background state indicates whether the location data is collected when the app is in the foreground or background.The provided location will be cached in memory, and for subsequent events, the location details will be added as a property.
ZetaCore.updateLocation({
"latitude": 12.933663251837913,
"longitude": 77.62168405034637,
"isForeground": true
})
Event Tracking
Auto Tracked Events
- app_installed: This event is generated only once when the app is launched for the first time.
- app_opened: This event is generated whenever the app transitions from the background to the foreground.
- app_closed: This event is generated whenever the app transitions from the foreground to the background.
Auto Tracked Event for iOS Only:
- app_terminated: This event is generated whenever the app is closed.
Defined Events
Screen Name Tracking
- screen: This event is used for tracking user screen navigation. The provided screen name will be cached in memory, and for subsequent events, the screen will be added as a property.
- deeplink: An optional field for specifying that this screen is opened through a deeplink URL.
- properties: An optional field for specifying additional properties.
ZetaCore.trackScreenName({"screen": "Events Screen", "deeplink": "app://home", "properties": {"screen" : "Home"}})
Custom Events
The SDK accepts custom events. To send custom events, the application needs to pass the event name and properties to the SDK.
- eventName: A meaningful name that describes the event.
- properties: properties is a dictionary, properties should be JSON encodable and decodable.
ZetaCore.send({
"name": "eventName",
"properties": {
"events-array": ["screen1", "screen2"],
"events-dict": { "screen": "events" }
}
})
If any property value is not serializable to JSON, the entire event data will be silently discarded.
Push Notification
To update device token
ZetaCore.updateDeviceToken("my Device Token")
Note: We shall require Native iOS and android SDK methods for push notifications setup in the React Native app’s iOS and android folders.
iOS:
For processing push notifications. we shall need to add below dependencies in React Native iOS directory.app/ios
We need to add below dependencies with CocoaPods.
// required for rich push notifications
target 'Notification Service Extension' do
pod 'ZetaNotificationService'
end
To track Zeta notification clicked by user
- Call ZetaClient.shared.push?.userNotificationCenter from did receive response delegate function of UNUserNotificationCenterDelegate
- This helps in tracking of user click events
- When it returns true than do not call completion handler as this is taken care by SDK
import ZetaCore
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
ZetaClient.shared.waitForInitialization {
if ZetaClient.shared.push?.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) == true {
// return without calling completion handler
return
}
DispatchQueue.main.async {
completionHandler()
}
}
}
}
We can also track notification clicked by directly calling below function
import ZetaCore
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
ZetaClient.shared.waitForInitialization {
ZetaClient.shared.push?.trackNotificationClicked(response: response)
DispatchQueue.main.async {
completionHandler()
}
}
}
}
To get notified when zeta notification with deeplink is clicked
If your app uses deep links (e.g. custom URI schemes) to navigate, you can integrate Zeta’s deeplink tracking:
- We shall need to call below function after zeta sdk is initialized to receive deep links.
ZetaCore.setDeeplinkDelegate()
- We shall need to notify zetakit_reactnative that app navigation is ready for processing deeplinks using below method.
ZetaCore.notifyReactNativeNavigationReady()
Example
const App = () => {
const onNavigationReady = () => {
// Notify zetakit_reactnative that React Native navigation is ready
ZetaCore.notifyReactNativeNavigationReady();
};
return (
<NavigationContainer onReady={onNavigationReady}>
// rest of the app.
</NavigationContainer>
);
we can set the listener as below:
import ZetaCore, {ZetaCoreEvents} from 'zetakit_reactnative'
const eventEmitter = Platform.select({
ios: new NativeEventEmitter(ZetaCore.bridge),
android: DeviceEventEmitter
});
const deeplinkDelegateEventListener = eventEmitter?.addListener(ZetaCoreEvents.DeeplinkDelegate, (event) => {
console.log(event.deeplink)
console.log(event.extraInfo)
});;
- deeplink: param will be the deeplink in notification payload passed from Zeta Campaign
- extraInfo: param will be the extraInfo in notification payload passed from Zeta Campaign
To get delivery status of notification
- Create notification service extension, Import ZetaNotificationService from ZetaKit Package and add it to notification service extension target.
- Add ZetaNotificationService pods to notification service extension target in Podfile
-
target 'Notification Service Extension' do pod 'ZetaNotificationService' end
-
- add ZetaNotificationService.xcframework to notification service extension target
-
- use ZTNotificationService as suggested below in documentation
- you can use ZTNotificationService.canHandle to check if ZetaNotificationService can handle notification.
- Create a app group id and pass it in ZTNotificationService.trackNotificationDelivered
ZTNotificationService is used to provide rich notification extension and track delivery of notification . There are 2 ways to use ZTNotificationService.
-
Make ZTNotificationService super class of NotificationService extension class
-
import ZetaNotificationService import UserNotifications class NotificationService: ZTNotificationService { public override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { if ZTNotificationService.canHandle(request, withContentHandler: contentHandler) { //If Zeta SDK can handle the notification //call ZTNotificationService.trackNotificationDelivered to track delivery //super.didreceive to handle rich notification ZTNotificationService.trackNotificationDelivered(request, appGroupId: "group.com.xyzapp") super.didReceive(request, withContentHandler: contentHandler) return } //handle non Zeta notification contentHandler(request.content) } }
-
-
Use ZTNotificationService directly in your NotificationService class
-
import ZetaNotificationService import UserNotifications class NotificationService: UNNotificationServiceExtension { public override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { if ZTNotificationService.canHandle(request, withContentHandler: contentHandler) { ZTNotificationService.trackNotificationDelivered(request, appGroupId: "group.com.abc.xyzproduct") ZTNotificationService.handleNotification(request, withContentHandler: contentHandler) return } //handle non Zeta notification contentHandler(request.content) } }
-
Android
To set up push notifications, the application needs to manage Firebase registration and ensure that the google-services.json file is placed in the correct path (project/app).
The push notification service will not work without Google Play services, so the application must ensure that the device has Google Play services installed.
For Android 13 and above, user permission is required to show notifications, and the application must handle this permission appropriately.
Firebase dependency
Application needs to add the firebase dependency inside app/build.gradle file
implementation("com.google.firebase:firebase-messaging:24.1.0")
Before using the library ensure we are using the latest version Firebase.
How to configure push service?
The SDK includes a built-in push service that has been already registered in the React Native SDK’s manifest file.
If the application wants to customize the push notification and channel information:
ZTPush.setNotificationConfig(
ZTNotificationConfig(
smallIcon = applicationInfo.icon,
color = Color.GREEN,
enableAppLaunch = true,
notificationChannel = ZTNotificationChannel(
id = "ApplicationTestChannel",
name = "Application Test Channel",
description = "Test Channel Description",
showBadge = true,
autoCancel = true,
notificationSound = R.raw.test_ring_tone_1
)
)
)
ZTNotificationConfig parameters
- smallIcon : Set the small icon to use in the notification layouts.
- color : Accent color to be applied to the notification.
- enableAppLaunch : Enable SDK launch the application when user tap on it, when notification actions are missing in payload(By default this flag will be true).
- notificationChannel : Notification channel info. If this configuration is not provided, the SDK will create a DEFAULT channel.
ZTNotificationChannel parameters
- id: Channel id
- name: Channel Name
- description: Channel description
- showBadge: Enable/Disable badge icon for the channel(By default this flag will be true).
- autoCancel : Setting this flag will make it so the notification is automatically canceled when the user clicks it in the panel(By default this flag will be true)
- notificationSound : Resource id for the explicit sound file(Optional field)
Intent Listening
Zeta supports listening to Android intents delivered to your app. To retrieve the launch intent data, the host app must call the ZetaCore.getInitialIntent() method, after the SDK initialization. The SDK will then process the intent and return the data. When the app is in the active state, the SDK automatically captures the intent and delivers the data through the device emitter.
- To retrieve the launch intent data, the host app must call the ZetaCore.getInitialIntent() method after the SDK initialization.
import ZetaCore, {IntentData} from 'zetakit_reactnative'
//Initial intent
//Ensure ZetaCore initialized, before accessing 'getInitialIntent' method
ZetaCore.getInitialIntent()
.then((intent) => {
console.log('Initial intent received:', intent);
})
.catch((error) => {
console.error('Error getting initial intent:', error);
});
- When the app is in the active state, the SDK automatically captures the new intent and delivers the data through the device emitter.
//App instance active
const eventEmitter = Platform.select({
ios: new NativeEventEmitter(ZetaCore.bridge),
android: DeviceEventEmitter
});
const newIntentEventListener = DeviceEventEmitter.addListener(
ZetaCoreEvents.AndroidNewIntent,
(intent: IntentData) => {
console.log('New Intent received:', intent);
},
);
Setting Up Push Notification Deep Linking
When a user taps on the notification, the intent will be delivered to the application. In the AndroidManifest.xml, the deep link URL must be registered to launch the activity. For example:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="com.zeta.android.demo" />
<data android:host="home" />
</intent-filter>
Tracking Foreground Notification Deep Link Clicks
The notification payload will be delivered to the registered activity through the intent. The deep link URI value can be retrieved from IntentData. Please refer to the Intent Listening section for handling the intent
Setting Up Push Notification Action Callback
Foreground Action
When a user taps on a notification action button while in the foreground, the respective action will be delivered to the application. The application should register the specified action in the activity's configuration section in the AndroidManifest.xml. For example:
<intent-filter>
<action android:name="com.zeta.demoapp.open_notification" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Tracking Foreground Action Button Clicks
The notification payload will be delivered to the registered activity through the intent. Intent can be retrieved from IntentData, which can then be used for tracking. Please refer to the Intent Listening section for handling the intent
Background Action button
When a user taps on a background action button, the SDK will pass the callback to the method below. Once this method is invoked, the application can process it. For this action, the SDK will automatically create the event:
//Android native method
ZTPush.setActionBackgroundCallback { data ->
//Process the noticiation background action click
}
Custom Push Service
If you want to use your own custom PushService, implement the following method to send the device token to the server in the onNewToken method:
override fun onNewToken(token: String) {
super.onNewToken(token)
ZetaClient.updatePushToken(applicationContext, token)
}
Processing Push Notifications
To process the push notifications, use the following method:
ZTPush.handleMessage(
context = applicationContext,
remoteMessage = message
)
If the above method returns true, the SDK is able to process the notification. If it returns false, the application needs to handle the notification accordingly.
Delivery Status of Push Notifications
The SDK automatically captures the delivery status of push notifications in both cases(in service/Custom Service).
How to handle non zeta notification?
For handling unfamiliar notifications, the application can register a callback lambda method in ZTPush.
ZTPush.setNonZtNotificationCallback {remoteMessage->
Log.d("ZTDemoApp", "Unknown notification received:$remoteMessage")
}
Rich Notification Support
Rich Notifications allow for more customization in your push notifications by adding additional content.This capability allows the marketer to send media-enabled push messages without developer support.
A ZMP user can upload a single media file or specify a URL for upload into their app. The media is then shown in the preview window of campaign builder. Upon receiving , the SDK downloads the media and displays it in a standard push notification.
iOS push notifications can include GIFs, images, videos.
Supported Media Types for Rich Notification:
- Image files formats: JPG, GIF and PNG
- Video files formats: MP4
Guidelines
We recommend a 2:1 aspect ratio (landscape) for expanded push notifications.
Images will always span the full width of the notification, and the height will adjust accordingly.
In App Message
In-app push messaging allows marketers to queue up toaster-style messages within their app that will display when users open the app. Opt-in/consent is not required, so deliverability is near 100% of app install base. This message type is great for highly contextual, low urgency messages.
In-app messages are displayed within mobile app without requiring any additional permissions.
The SDK uses a polling mechanism to fetch in-app messages. Once a message is received, the SDK evaluates the app state to determine if it should display the in-app message. If conditions are met, an in-app message dialog will be shown.
To monitor in-app messages, the SDK provides an in-app message lifecycle callback that can be configured from the application.
Start and Stop In App Messages
In App message is enabled by default, but if the app needs to stop in app message the app can call:
ZetaCore.stopInApp()
To restart In App message again, the app can call:
ZetaCore.startInApp()
Note: The SDK does not persist the stop state; the application must manage this state. By default, the SDK will start displaying in-app messages on app launch.
Check status: You can query whether in-app messaging is active:
ZetaCore.getInAppStatus((value: boolean) => {
console.log('In-app status:', value);
})
In App Message Delegate
The SDK provides In App Message listeners which informs about the lifecycle of In App Message when presented
Event Listener for inApp Messages:
- Note: We shall need to call ZetaCore.setInAppMessageDelegate() to listen for inApp Messages lifecycle events.
import ZetaCore, {ZetaCoreEvents} from 'zetakit_reactnative'
const eventEmitter = Platform.select({
ios: new NativeEventEmitter(ZetaCore.bridge),
android: DeviceEventEmitter
});
const inAppMessageDelegateEvent = eventEmitter?.addListener(ZetaCoreEvents.InAppMessageDelegate, (event) => {
if (event.inAppMessageOnClicked != null) {
console.log('inAppMessageOnClicked' + event.inAppMessageOnClicked)
}
if (event.inAppMessageWillAppear != null) {
console.log('inAppMessageWillAppear' + event.inAppMessageWillAppear)
}
if (event.inAppMessageDidAppear != null) {
console.log('inAppMessageDidAppear' + event.inAppMessageDidAppear)
}
if (event.inAppMessageOnDimissed != null) {
console.log('inAppMessageOnDimissed' + event.inAppMessageOnDimissed)
}
Note:objects have information like title, body, messsageUID, deeplink, webLink, imageURls, additionalValues
});
Note:
Please make sure to call ZetaCore.setInAppMessageDelegate only after we add above inAppMessageDelegateEvent listener
- This helps to make sure that we have active listener before we start sending events from bridge layer.
How to Create an In-App Message
- Access the ZMP Portal
- Log in to the ZMP portal.
- Configure the Campaign
- Navigate to the campaign window.
- Select the channel as 'Mobile InApp Push'.
- Compose the Message
- Click on the In-App Messaging Setup content area to begin composing your message.
- Message Composition Steps
- Title: Provide a title for your message.
- Body: Provide the body of your message
- OnClick Options: Choose one of the following actions for when a user taps on the message:
- Deep Link: When the user taps on the message, the SDK will deliver the deep link URL to the application through a delegate method. The application must handle internal redirection.
- Dismiss: No action will be performed when the message is clicked.
- Web Link: The specified URL will open in a browser view when tapped.
- In-App Web View: The specified URL will open inside the SDK in SFSafariViewController
- External Browser: The specified URL will open in the device's default browser.
- In-App Message Image (Optional): An image can be specified through available options
- Finalize Your Message
- After composing your message, click on the Done button.
- Activate the Campaign
- Activate your campaign from the portal to start displaying in-app messages.


Privacy & Data Collection
Google Play Data Safety: https://knowledgebase.zetaglobal.com/gswz/google-play
Zeta SDK Android Data Collection: https://knowledgebase.zetaglobal.com/gswz/zeta-sdk-android-data-collection
iOS Privacy Nutrition Label: https://knowledgebase.zetaglobal.com/gswz/ios-privacy-nutrition-label
Zeta SDK iOS Data Collection: https://knowledgebase.zetaglobal.com/gswz/zeta-sdk-ios-data-collection
Handle Deeplinks / Universal Links: https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app
Updated about 17 hours ago