Supporting Re-engagement Tracking using Push Notifications
Singular supports push notification tracking to enhance re-engagement measurement. By integrating Firebase Cloud Messaging (FCM) with the Singular SDK, you can track users who interact with push notifications and attribute them accordingly.
To ensure accurate tracking, follow the implementation guidelines below and make sure that notification data is correctly passed to the Singular SDK.
Why is Push Notification Tracking Important?
Push notifications are a key re-engagement tool, but tracking them requires correct integration. Singular ensures that users who interact with notifications are properly attributed, helping optimize marketing campaigns and engagement strategies.
Implementation Guide
Step 1: Handling Firebase Cloud Messaging (FCM) Notifications
When your app receives a push notification from Firebase, the onMessageReceived() method is triggered. To track notifications in Singular, update this method to process the notification data.
Example:
@Override
public void onMessageReceived(@NonNull RemoteMessage message) {
super.onMessageReceived(message);
String title = "";
String body = "";
if (message.getNotification() != null) {
Log.d("===singular-app", message.getNotification().toString());
title = message.getNotification().getTitle();
body = message.getNotification().getBody();
}
Map<String, String> data = message.getData(); // Fixed the incorrect Map generic type
if (!data.isEmpty()) {
Log.d("===singular-app", data.toString());
}
// Implement processNotification method to forward payload data to intent
processNotification(title, body, data);
}
override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)
var title = ""
var body = ""
message.notification?.let {
Log.d("===singular-app", it.toString())
title = it.title ?: ""
body = it.body ?: ""
}
val data: Map<String, String> = message.data
if (data.isNotEmpty()) {
Log.d("===singular-app", data.toString())
}
// Implement processNotification method to forward payload data to intent
processNotification(title, body, data)
}
This ensures that all relevant push data is captured and passed forward for processing.
Step 2: Processing Push Notifications and Passing Data to Singular
Once the notification is received, it's crucial to pass its data to an intent that launches the main activity where Singular is initialized.
Example:
private void processNotification(String title, String body, Map<String, String> data) {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// Attach notification data to the intent
for (Map.Entry<String, String> entry : data.entrySet()) {
intent.putExtra(entry.getKey(), entry.getValue());
}
PendingIntent pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE // Added FLAG_IMMUTABLE for API 31+
);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "your_channel_id")
.setSmallIcon(R.drawable.info_btn)
.setContentTitle(title)
.setContentText(body)
.setPriority(NotificationCompat.PRIORITY_HIGH) // Optional: Set priority for better visibility
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.notify(0, notificationBuilder.build());
}
}
private fun processNotification(title: String, body: String, data: Map<String, String>) {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
// Attach notification data to the intent
data.forEach { (key, value) ->
putExtra(key, value)
}
}
val pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // For Android 12+
)
val notificationBuilder = NotificationCompat.Builder(this, "your_channel_id")
.setSmallIcon(R.drawable.info_btn)
.setContentTitle(title)
.setContentText(body)
.setPriority(NotificationCompat.PRIORITY_HIGH) // Optional for better visibility
.setAutoCancel(true)
.setContentIntent(pendingIntent)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
notificationManager?.notify(0, notificationBuilder.build())
}
This ensures that when the user taps the notification, they are directed to the appropriate activity with the correct tracking data.
Step 3: Integrating Push notification payloads with the Singular SDK
Finally, update your Singular SDK configuration to ensure that push notification payloads are correctly passed and processed.
Example:
String[][] pushSelectors = {
{"sng_link"},
{"rootObj", "nestedObj", "anotherNested", "singularLink"}
};
config.withPushNotificationPayload(intent, pushSelectors);
Singular.init(context, config);
val pushSelectors = arrayOf(
arrayOf("sng_link"),
arrayOf("rootObj", "nestedObj", "anotherNested", "singularLink")
)
config.withPushNotificationPayload(intent, pushSelectors)
Singular.init(context, config)
This step ensures that Singular correctly tracks push notification engagements for attribution purposes.
Validation Guide
The Singular SDK API call ensures that the push notification payload link is correctly passed under the singular_link reserved parameter in the start session call.
Example:
https://sdk-api-v1.singular.net/api/v1/start?a=<SDK-Key>&ab=arm64-v8a&aifa=180f63a1-0955-47b4-896a-d75ae3d35955&apc=Marchv7&apg=1&aps=Intex&asid_scope=1&asid_timeinterval=0.112&av=20.0&br=samsung&c=wifi¤t_device_time=1740905574088&de=m15x&device_type=phone&device_user_agent=Dalvik/2.1.0 (Linux; U; Android 14; SM-E156B Build/UP1A.231005.007)&dnt=0&event_index=3&fi=e5bRZuVddO8:APA91bHXI3OmFZv3-r8f03zyji2kvKWbIngwf8KBDHk4Rj5q5MEeEm6EtzC-if1vpJRmuYLyGdAcSz9-nc49eIjD86xwj-n9J4jKucqMVt9mP8ICifP0arA&i=net.singular.singularsampleapp&install_time=1740905507036&is=false&k=SDID&lag=0.067&lc=en_IN&ma=samsung&mo=SM-E156B&n=Singular-TestApp-Debug&p=Android&pr=m15xnndins&pu=1&rt=json&s=1740905574084&sdk=Singular/v12.6.2&singular_install_id=2dc5dfc2-a2a8-484a-aad1-fed6cb7a3023&singular_link=https://singularassist2.sng.link/C4nw9/r1m0?_dl=singular://test&_smtype=3&src=com.android.shell&u=75f7b911-5a77-597d-8892-56f5e0e210ff&update_time=1740905507036&v=14&h=1e723fd90344d5d037059f110611ed1d84fbba88
Alternatively, you can use the Singular SDK Console to verify the push notification tracking link under the Deeplink URL, as demonstrated below.
By verifying this, you can confirm that push notification engagements are correctly tracked within the Singular SDK.
Notes:
- Please note that, unlike the withSingularLink handler code, the Singular SDK does not provide push payload callbacks for this feature. It is the responsibility of the app developer to read the push notification data and implement the deep linking logic to redirect users to specific product pages within the app. In this solution, Singular retrieves the push notification payload when the user taps on the notification and includes this payload in the SDK start session event triggered by Singular.init(). This data is then processed on the Singular backend to attribute the push notification touchpoint/click and register it for re-engagement tracking.
-
We have a safety mechanism in place that allows only Singular link domains from the custom key value pair passed in the push notification payload. Specifically, only sng.link domains predefined in the Singular Manage Links page are permitted.
For example:
https://prod_test.sng.link/B0s2a/51oi?_dl=singular%3A%2F%2Fmain
If you intend to wrap Singular links within a different domain (e.g., an ESP domain for email service providers), you must explicitly configure the domain by adding the following option in your setup: This ensures that the external domain is recognized and allowed within the Singular framework. please refer to the below configuration example. config.withESPDomains(Arrays.asList("sl.esp.link"));
-
If you need to trigger different deep links based on user actions from a single push notification, you can use a single Singular tracking link and dynamically modify redirects.
Example:
A push notification for breaking news may offer multiple deep link options! Instead of creating multiple tracking links, configure one Singular tracking link and adjust redirects dynamically based on user selection.
Read Latest News →
Trending Topics →newsapp://article?id=12345
Sports →newsapp://trending
newsapp://sports
Learn more about overriding redirects in Singular tracking links.
Success!
By following these steps, your app is now set up to track push notification interactions using Singular. This helps improve campaign performance insights and ensures accurate re-engagement attribution.