Ometria helps your marketing department understand and better engage with your customers by delivering personalised emails and push notifications.
The app has two key objectives:
- Getting information about customers (what do they like?)
- Reaching out to customers (saying the right thing to the right people).
For your mobile app, this means:
- Tracking customer behaviour through events - a subset of events is automatically handled by the Ometria SDK, but you have to customize it to your needs, see Creating an event tracking plan for your mobile app.
- Sending and displaying push notifications - requires the app developers.
App developers integrating with this SDK should follow the guide below. You can also look at the Sample app we have included for a reference implementation.
See Setting up your mobile app with Firebase credentials in the Ometria help centre and follow the steps there to get an API key.
The easiest way to get Ometria into your ReactNative project is by using npm install
or yarn add
.
Please note that this library does not support the new React Native architecture yet. If you created a new project with the new architecture, you need to switch back to the old one by running RCT_NEW_ARCH_ENABLED=0 pod install
when installing pods on iOS and by setting newArchEnabled=false
in android/gradle.properties
.
- Install Ometria ReactNative package from
react-native-ometria
usingnpm install react-native-ometria
oryarn add react-native-ometria
Note: If you have issues with installing the library, please consider excluding the example from typescript config eg:
{
...,
"exclude": ["example"]
}
-
For
iOS
you need to install Podspod install
to create a local CocoaPods spec mirror. -
If you encounter
The Swift pod 'Ometria' depends upon 'FirebaseMessaging'
error when running pod install, please consider addinguse_frameworks! :linkage => :static
.
To initialise the Ometria SDK, you need to enter the API key from 2. Before you begin.
import Ometria from 'react-native-ometria';
await Ometria.initializeWithApiToken('API_KEY', {
notificationChannelName: 'Example Channel Name', // optional, only for Android
appGroupIdentifier: 'group.com.ometria.sampleRN', // optional, only for iOS
});
ℹ️ Since version 2.3.0, the SDK allows for reinitialization of the Ometria instance. So you can call this method again later in the app if you need to.
-
You can specify a custom name of the Android notification channel in the second optional options parameter. Default channel name is
<blank>
. -
You can also specify an app group identifier in the second optional options parameter. See this section for iOS.
Ometria logs any errors encountered during runtime by default, these logs are accessible in your development environment's console.
You can enable advanced logging if you want more information on what’s happening in the background. Just add the following line after initialising the library:
Ometria.isLoggingEnabled(true);
You need to be aware of your users’ behaviour on your platforms in order to understand them. Some behaviour is automatically detectable, other events need work from the app developer to track.
Many of these methods have analogous events in our website tracker.
E.g., the customer identified event takes a customer ID or an email - these identifiers must be the same here as it is in the data API. If you specify both email and customer id, both need to match.
The events are merged on Ometria's side into one big cross-channel view of your customer behaviour. If you use inconsistent email/customer ids, this could result in duplicate profiles created or data loss.
Once the SDK is initialised, you can track an event by calling its dedicated method.
An app user has just identified themselves, i.e. logged in.
Ometria.trackProfileIdentifiedByCustomerIdEvent('test_customer_id');
Their customer ID is their user ID in your database. Sometimes a user only supplies their email address without fully logging in or having an account. In that case, Ometria can profile match based on email:
Ometria.trackProfileIdentifiedByEmailEvent('[email protected]');
Having a customerId makes profile matching more robust.
It’s not mutually exclusive with sending an email event; for optimal integration you should send either event as soon as you have the information. These two events are pivotal to the functioning of the SDK, so make sure you send them as early as possible. Reiterating here that these identifiers must be the same here as the ones you use in your e-commerce platform and you send to Ometria (via the data API or other ways). If you specify both email and customer id, both need to match. A typical error we see at integrations is that the app generates a new customer id on each login (that doesn't match the customer id stored in Ometria). To avoid this, generate these ids centrally on your servers and send consistent ones through the Ometria mobile SDK and the Ometria Data API. If it is impractical to generate consistent ids, we suggest only using email to identify contacts.
Undo a profileIdentified event. You can use this if an user logs out.
Ometria.trackProfileDeidentifiedEvent();
Currently this event clears the stored ids (email and/or customer id) from the phone's local storage. It has no other effect within Ometria.
Ometria supports multiple stores for the same ecommerce platform (e.g. separate stores for different countries). There are three different methods for interacting with the store identifier for the current app installment.
trackProfileIdentifiedEvent(email: String, storeId?: String)
trackProfileIdentifiedEvent(customerId: String, storeId?: String)
When omitting the storeId
parameter, the store identifier will not be affected in any way. Only sending a valid parameter will cause the store identifier to be updated to that value.
updateStoreId(storeId: String | null)
- with a null
storeId
parameter, the method resets the store identifier. - with a non null
storeId
parameter, the method sets the store identifier to the provided value.
Tracking a profile deidentified event, will reset the customerId
, the email
, and the storeId
for the current app installment.
A visitor clicks/taps/views/highlights or otherwise shows interest in a product.
E.g. the visitor searches for a term and selects one of the product previews from a set of results, or browses a category of clothes, and clicks on a specific shirt to see a bigger picture.
This event is about capturing interest from the visitor for this product.
Ometria.trackProductViewedEvent('product_id');
The visitor has viewed a dedicated page, screen or modal with the contents of the shopping basket:
Ometria.trackBasketViewedEvent();
The visitor has changed their shopping basket:
const items: OmetriaBasketItem[] = [
{
productId: 'product-1',
sku: 'sku-product-1',
quantity: 1,
price: 12.0,
variantId: 'variant-1',
},
{
productId: 'product-2',
sku: 'sku-product-2',
quantity: 2,
price: 9.0,
variantId: 'variant-2',
},
{
productId: 'product-3',
sku: 'sku-product-3',
quantity: 3,
price: 20.0,
variantId: 'variant-3',
},
];
Ometria.trackBasketUpdatedEvent({
totalPrice: 12.0,
id: 'basket_id_eg',
currency: 'USD',
items,
link: 'link_eg',
});
This event takes the full current basket as a parameter - not just the updated parts.
This helps recover from lost or out of sync basket events: the latest update is always authoritative.
OmetriaBasketItem is an object that describes the contents of a shopping basket item. It can have its own price and quantity based on different rules and promotions that are being applied. It has the following properties:
- productId: (
String
, required) - A string representing the unique identifier of this product.- sku: (
String
, optional) - A string representing the stock keeping unit, which allows identifying a particular item.- quantity: (
Int
, required) - The number of items that this entry represents.- price: (
Float
, required) - Float value representing the price for one item. The currency is established by the OmetriaBasket containing this item- variandId: (
String
, optional) - An identifier for a variant product associated with this line item.
OmetriaBasket is an object that describes the contents of a shopping basket and has the following properties:
- id: (
String
, optional) - A unique identifier for this basket- currency: (
String
, required) - A string representing the currency in ISO 4217 three-letter currency code, e.g."USD"
,"GBP"
- totalPrice: (
float
, required) - A float value representing the pricing.- items: (
Array[OmetriaBasketItem]
) - An array containing the item entries in this basket.- link: (
String
) - A deeplink to the web or in-app page for this basket. Can be used in a notification sent to the user, e.g. "Forgot to check out? Here's your basket to continue: 'https://eg.com/basket_url'". Following that link should take them straight to the basket page.
Track when the user has started the checkout process. This is currently only used to count page views, and has no other effect in Ometria.
Ometria.trackCheckoutStartedEvent('order_id');
The order has been completed and paid for:
const items: OmetriaBasketItem[] = [
{
productId: 'product-1',
sku: 'sku-product-1',
quantity: 1,
price: 12.0,
},
];
Ometria.trackOrderCompletedEvent('order_id', {
totalPrice: 12.0,
id: 'basket_id_eg',
currency: 'USD',
items,
link: 'link_eg',
});
The second parameter (basket object) is optional.
Use the guide for Handling interaction with notifications that contain URLs to manually track this event when you have enough information regarding the screen (or other destination) that the app will open.
Ometria.trackDeepLinkOpenedEvent('/profile', 'ProfileScreen');
The visitor views the ‘home page’ or landing screen of your app.
Ometria.trackHomeScreenViewedEvent();
The visitor clicks/taps/views/highlights or otherwise shows interest in a product listing. This kind of screen includes search results, listings of products in a group, category, collection or any other screen that presents a list of products.
E.g., A store sells clothing, and the visitor taps on "Women's Footwear" to see a list of products in that category, or they search for "blue jumper" and see a list of products in that category.
This event should be triggered on:
- search results
- category lists
- any similar screens
Ometria.trackProductListingViewedEvent();
Tracking a visitor’s independent screen views helps us track their engagement with the app, as well as where they are in a journey.
An analogous event on a website would be to track independent page views.
The common eCommerce screens all have their own top-level event: basket viewed, list of products viewed, etc.
Your app may have a specific type of page that is useful for marketers to track engagement with.
E.g. if you’re running a promotion, and viewing a specific screen indicates interest in the promotion, which marketing might later want to follow up on.
To track these custom screens, use the Screen viewed event:
Ometria.trackScreenViewedEvent('OnboardingScreen', { a: '1', b: '2' });
The second parameter is optional and can be used to send additional data about the screen.
Your app might have specific flows or pages that are of interest to the marketing team.
E.g. Marketing might want to send an email or notification to any user who signed up for a specific promotion, or interacted with a button or specific element of the app.
If you send a custom event corresponding to that action, they will be able to trigger an automation campaign on it.
Check with the marketing team about the specifics, and what they might need. Especially if they're already using Ometria for email, they will know about automation campaigns and custom events.
Ometria.trackCustomEvent('my_custom_type', {});
The second parameter is optional and can be used to send additional data about the event.
The following events are automatically tracked by the SDK.
Initialising the SDK is enough to take advantage of these; no further integration is required (unless mentioned otherwise).
Event | Description |
---|---|
Application installed | The app was just installed. Usually can't be sent when the app is actually installed, but instead only sent the first time the app is launched. |
Application launched | Someone has just launched the app. |
Application foregrounded | The app was already launched, but it was in the background. It has just been brought to the foreground. |
Application backgrounded | The app was in active use and has just been sent to the background. |
Notification received in quit state of the app | A Push notification was received by the system while the app was in quit state. (needs a Notification Service Extension on iOS) |
Error occurred | An error occurred on the client side. We try to detect any problems with actual notification payload on our side, so we don't expect any errors which need to be fed back to end users. |
In order to reduce power and bandwidth consumption, the Ometria library doesn’t send the events one by one unless you request it to do so.
Instead, it composes batches of events that are sent to the backend during application runtime when the one of the following happened:
- it has collected 10 events or
- there was a firebase token refresh (
pushtokenRefreshed
event) - a
notificationReceived
event - an
appForegrounded
event - an
appBackgrounded
event
You can request the library to send all remaining events to the backend whenever you want by calling:
Ometria.flush();
You can completely clear all the events that have been tracked and not yet flushed.
To do this, call the following method:
Ometria.clear();
To see what events were captured, you can check the logs coming from the Ometria SDK, if logging is enabled. You can filter for the word "Ometria". The SDK logs all events as they happen, and also logs the flushing i.e. when they are sent to the Ometria mobile events API. Any potential errors with the sending (API issues or event validation issues) would be visible here too.
Ometria uses Firebase Cloud Messaging to send push notifications to the mobile devices.
You will therefore have to add ‘React-Native Firebase’ as a dependency of Ometria, using the following lines:
import firebase from '@react-native-firebase/app';
import messaging from '@react-native-firebase/messaging';
For Android follow the Firebase ReactNative tutorial Firebase for Android For iOS follow the Firebase ReactNative tutorial Firebase for iOS
To use push notifications, you also need to follow the steps in Push Notifications ReactNative Guide
When correctly set up, Ometria can send personalised notifications for your mobile application.
Follow these steps:
- Enable your app to receive push notifications by creating an appId and enabling the push notifications entitlement.
- Set up a Firebase account and connect it to Ometria.
- Enable Cloud Messaging on your Firebase account and provide your application’s SSL push certificate.
- Configure push notifications in your application.
- Add a Notification Service Extension to your app in order to enable receiving rich content notifications and to track notifications received in quit state of the app on iOS.
Before continuing, you must have already configured:
- The Ometria SDK must be initialised
- Firebase must be configured and added to your project
Read more about those steps in section 4. Initialise the library
For Android 13 (API level 33) and higher you first have to declare the permission in your AndroidManifest.xml file:
<manifest ...>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application ...>
...
</application>
</manifest>
You have to request permissions for notifications. You can use react-native-permissions.
import {requestNotifications, RESULTS } from 'react-native-permissions';
...
await requestNotifications(['alert', 'sound', 'badge']).then(({ status }) => {
if (status === RESULTS.GRANTED) {
console.log('🔔 Push Notification permissions granted!');
}
});
Find more about Notification runtime permissions on Android here.
After Ometria initialisation, you must forward the Firebase Push Notification token (both iOS and Android).
You also have to forward the push notification token to Ometria every time it is refreshed.
import Ometria from 'react-native-ometria';
import messaging from '@react-native-firebase/messaging';
await Ometria.initializeWithApiToken('API_KEY', {
notificationChannelname: 'Example Channel Name', // optional, only for Android
appGroupIdentifier: 'group.com.ometria.sampleRN', // optional, only for iOS
});
messaging()
.getToken()
.then((pushToken) => Ometria.onNewToken(pushToken));
messaging().onTokenRefresh((pushToken) => Ometria.onNewToken(pushToken));
Subscribe to remote messages that your app gets while in foreground app state. You can do this by using the onMessage
method from the @react-native-firebase/messaging
package.
In the callback, you can use Ometria.onNotificationReceived
to let the Ometria SDK know that a remote message has been received and the notificationReceived
event will be fired. Use Ometria.parseNotification
if you want to extract Ometria data from the remote message.
messaging().onMessage(async (remoteMessage) => {
Ometria.onNotificationReceived(remoteMessage);
const ometriaData = Ometria.parseNotification(remoteMessage);
// Use ometriaData
});
ℹ️ If you implement such a custom solution, don't forget to call Ometria.onNotificationOpenedApp
to let the SDK the notification has been interacted with when handling the notification interaction event for foreground notifications.
In order for Ometria to accurately track all the notifications that were received in quit and background state of the app on iOS, it needs to leverage the power of a background service, that has access to all notifications.
For a complete guide on how to set up a Notification Service Extension, see Adding Notification Service Extension Target.
In order for Ometria to accurately track all the notifications that were received in quit and background state of the app on Android you need to subscribe early (in index.js
) to remote messages that your app gets while being in quit and background state.
Ometria.onAndroidBackgroundMessage
will let the Ometria SDK know that a remote message has been received and the notificationReceived event will be fired. It needs the Ometria token in order to initialize the SDK in background.
Platform.OS === 'android' &&
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
Ometria.onAndroidBackgroundMessage({
ometriaToken: 'OMETRIA_KEY'
ometriaOptions: {},
remoteMessage,
});
});
ℹ️ As of version 2.4.0 Ometria.setBackgroundMessageHandler
is a deprecated method. Use Ometria.onAndroidBackgroundMessage
instead.
When a user interacts with a notification in background or quit state, you have to let the Ometria SDK know that the notification has been interacted with and the app has been opened. You can do this by calling Ometria.onNotificationOpenedApp
with the remote message as a parameter.
// Check if the app was opened from quit state by a notification
messaging()
.getInitialNotification()
.then((remoteMessage) => {
if (remoteMessage) {
Ometria.onNotificationOpenedApp(remoteMessage);
}
});
// Subscribe to the app being opened from background state by a notification
messaging().onNotificationOpenedApp((remoteMessage) =>
Ometria.onNotificationOpenedApp(remoteMessage)
);
ℹ️ As of version 2.4.0 Ometria.onNotificationInteracted
is a deprecated method. Use Ometria.onNotificationOpenedApp
instead.
Ometria allows you to send URLs and tracking info alongside your push notifications and allows you to handle them on the device. When a notification opened the app, you can parse the notification remote message and check if it contains a deeplink URL.
const notif = await Ometria.parseNotification(remoteMessage);
if (notif?.deepLinkActionUrl) {
Ometria.trackDeepLinkOpenedEvent(notif.deepLinkActionUrl, 'Browser');
Linking.openURL(notif.deepLinkActionUrl);
}
Ometria.parseNotification
returns an object with OmetriaNotificationData
type that looks like this:
type OmetriaNotificationData = {
campaignType?: 'trigger; // represents automation campaigns
deepLinkActionUrl?: string;
externalCustomerId?: string;
imageUrl?: string;
sendId?: string;
tracking: { // Can be overridden / added in your automation campaign's settings
utm_medium?: string; // default is "push"
utm_source: string;
utm_campaign: string; // generated from campaign hash and title
om_campagin: string; // generated from campaign hash, campaign version and node id
[key: string]: string | undefined; // additional tracking data you add
};
};
The Notification Service Extension has two purposes:
- Starting with iOS 12.0, Apple enabled regular applications to receive and display notifications that contain media content such as images. In order to be able to display the rich content, notifications have to be processed by the Notification Service Extension before being shown to the user.
- There are lots of users that forget to open their apps. In order for Ometria to accurately track all the notifications that were received in quit state, it needs to leverage the power of a background service, that has access to all notifications.
In order to add the extension, go to File > New > Target, and select Notification Service Extension > Next.
A new item is displayed in your target list:
Next, make sure that the Ometria SDK is also available to this new target by updating your podfile to include your newly added target and specify Ometria as a dependency.
# move this line before the App target
pod 'GoogleUtilities', : modular_headers => true
use_frameworks! :linkage => :static
target 'sampleApp' do
# Pods for sampleApp
end
# Add the following lines
target 'NotificationService' do
use_frameworks! :linkage => :static
pod 'Ometria'
end
At this point the main application and the extension function as two separate entities with the only shared component being the code. In order for the extension to obtain read and write access to data that is relevant for the SDK, it requires to be in the same App Group as the main target. This will allow the main target and the extension to share data.
In your project navigator, select your project, then go to Signing & Capabilities and select + Capability in the top left corner.
Once you have done so, a new section will be displayed below Signing. It will allow you to add a new app group. Make sure you select a relevant identifier (e.g.group.[BUNDLE_IDENTIFIER]
), and retain the value, as you will need it when instantiating Ometria.
Repeat the process for the Notification Service Extension target, and you should be good to go.
To allow Ometria to intercept notifications, open the NotificationService
class that was automatically created alongside the extension, and replace the content with the following:
import UserNotifications
import Ometria
class NotificationService: OmetriaNotificationServiceExtension {
override func instantiateOmetria() -> Ometria? {
Ometria.initializeForExtension(appGroupIdentifier: "group.[BUNDLE_IDENTIFIER]")
}
}
Finally, you have to use the app group identifier when initialising Ometria in the ReactNative application.
import Ometria from 'react-native-ometria';
// Ometria init
await Ometria.initializeWithApiToken('API_KEY', {
notificationChannelName: 'Example Channel Name', // optional, only for Android
appGroupIdentifier: 'group.[BUNDLE_IDENTIFIER]', // optional, only for iOS
});
Now your app will emit a notificationReceived
event every time a notification is received in quit state and you will be able to display rich content notifications on iOS.
💡 For a complete example and use case please consult the Sample app.
Ometria sends personalised emails with URLs that point back to your website. In order to open these URLs inside your application, make sure you follow this guide.
First, make sure you have an SSL-enabled Ometria tracking domain set up for your account. You may already have this for your email campaigns, but if not ask your Ometria contact to set one up, and they should provide you with the domain.
Please follow the ios documentation for associated domains, then create an apple-app-site-association file and send it to your Ometria contact.
The final step is to process the URLs in your app and take the user to the appropriate sections of the app. Note that you need to implement the mapping between your website's URLs and the screens of your app.
See also Linking push notifications to app screens.
If you are dealing with normal URLs pointing to your website, you can decompose it into different path components and parameters. This will allow you to source the required information to navigate through to the correct screen in your app.
In order for ReactNative to identify that an url is opening the app you need to adjust AppDelegate.m file from ios folder add the following code to AppDelegate.m from ./ios/ProjectName
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [RCTLinkingManager application:application openURL:url
sourceApplication:sourceApplication annotation:annotation];
}
// Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
For Android please add the following:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="clickom.omdemo.net"
android:scheme="https" />
</intent-filter>
to /android/app/src/main/AndroidManifest.xml
However, Ometria emails contain obfuscated tracking URLs, and these need to be converted back to the original URL, pointing to your website, before you can map the URL to an app screen. To do this, the SDK provides a method called processUniversalLink
:
processUniversalLink(url: string): Promise<string>
If you have done everything correctly, the app should now be able to open app links and allow you to handle them inside the app.