Android Push

Learn how to deliver push notifications to your Android application.

Overview

CleverTap allows you to send push notifications to your applications from our dashboard. The following are the two ways to implement push notifications on an Android device:

Configure Push Notifications

The following are the steps to configure push notifications for your Android app:

  1. Find FCM Credentials.
  2. Set Up FCM Credentials.
    OR
    Safeguard Admin Credentials and Upload Credentials File to CleverTap.

πŸ“˜

FCM Update: Migrate to HTTP v1 API

Firebase will deprecate its legacy APIs starting June 20, 2023, and discontinue them from June 2024. To avoid disruptions in push notifications, you must migrate to the new HTTP v1 API by June 20, 2024. Failure to do so may result in all push notifications not being delivered to users and result in errors instead.

For detailed migration steps, refer to Configure Push Notifications. CleverTap has already completed this migration to ensure uninterrupted service.

To ensure uninterrupted delivery of the push notifications, you must migrate to the latest FCM APIs.

Discover the following video tutorial for migrating to HTTP v1 API:

Explore FAQs for detailed information about Android Push Notifications.

Find FCM Credentials

Firebase Cloud Messaging is a service that allows you to send notifications to your applications and receive information from them. Your FCM Sender ID and API key authenticate against CleverTap, enabling you to send notifications to your users from CleverTap.

To find the FCM credentials:

  1. Log in to the Firebase Developer Console and go to Open Settings > Service Accounts.
  2. To obtain the FCM Credential File, click Generate new private key.
Generate New Private Key

Generate New Private Key

  1. Confirm your action by clicking Generate Key.

Set Up FCM Credentials on CleverTap

To ensure your campaigns are delivered, you must set up FCM Credentials on the CleverTap dashboard:

  1. Log in to the CleverTap dashboard and go to Settings > Channels > Mobile Push.
  2. Click the FCM credentials section and click Upload FCM Credential File, as shown in the following image:
Upload FCM Credential File

Upload FCM Credential File

  1. Click Save.
Push Notifications Credentials

FCM Credentials Saved to CleverTap Dashboard

  1. Send a personalized Push campaign to internal users to verify if the configuration is successful.

Safeguard Admin Credentials

If your privacy policy requires safeguarding your admin credentials shared in the JSON file with CleverTap, follow the steps listed below:

  1. Open your Firebase project and go to the Service accounts tab.
  2. Click the service accounts list, as shown in the following figure:
Click Service Accounts List

Click Service Accounts List

  1. Select your project from the Service Accounts page and click + CREATE SERVICE ACCOUNT.
Create Service Account

Create Service Account

  1. Add the Service account name and Grant Firebase Cloud Messaging API Admin role to the service account and click Done, as shown in the following figure:
Assign Role to Service Account

Assign Role to Service Account

  1. Download your Credentials File:
    1. Navigate to the Keys tab from your service account and click ADD KEY.
    2. Select the Key type as JSON and click Create. The credentials file is downloaded.
Download Credential File

Download Credential File

  1. Use these credentials on a test account. Once you have validated it, you can use the same process for live account key generation and upload it to the CleverTap dashboard.

πŸ“˜

Prerequisite

To enable Firebase Cloud Messaging API, do the following:

  1. Go to console.cloud.google.com and click API & Services.
  1. Click Cloud Messaging API link from the left menu.
  2. Click ENABLE if it is not already enabled.

HTTP v1 API Rate Limits

With the new HTTP v1 API, the rate at which FCM sends requests per minute has changed. Each project now has a strictly enforced threshold for the number of requests allowed. The HTTP v1 API allocates 600,000 tokens per 1-minute token bucket, which replenishes completely at the end of each 1-minute interval.

Verify API Rate Limits

To verify the API Limits for your account:

  1. Navigate to the Firebase Cloud Messaging API Management menu:

    1. Go to console.cloud.google.com and select your project from the dropdown if not already selected.
    2. Search and select Firebase Cloud Messaging API.
    3. Click Manage.

    Navigate to Firebase Cloud Messaging API Management Menu

    Navigate to Firebase Cloud Messaging API Management Menu

  2. Find your Send Requests per Minute Quota:

    1. Navigate to the Quotas and System Limits tab.
    2. Check your Send Requests per Minute Quota, as shown in the following image:
    Find Send Requests per Minute Quota For Your Account

    Find Send Requests per Minute Quota For Your Account

API Rate Limit Exceeded

Consider an example where your account is granted a quota of 1000 requests per minute, and your target segment consists of 5000 users. FCM expects the throttle rate to adhere strictly to this limit. Failure to comply with this throttle rate may result in push notifications not being delivered to users and instead resulting in errors. It also triggers a non-compliance email from the FCM support team. However, CleverTap attempts to resend the request up to three times before marking it as a failed delivery and raises the FCM Rate limit exceeded error.

To optimize this, you can use CleverTap's throttle feature under the Campaign Limits section to help you stay within your allocated quota. This limit is set globally and can be configured by navigating to Settings > Setup > Campaign Limits and modifying the throttle limit.

Set Up Throttle Limit

Set Up Throttle Limit

If you encounter any issues, refer to the frequently asked questions section.

🚧

Campaign Throttle Limit

The FCM quota limit applies only to Android push notifications. However, CleverTap's campaign throttle limit applies at the campaign level. If there are multiple campaigns or if you want to deliver notifications to both Android and iOS devices, or use other FCM services, the campaign throttle limit must be set below the FCM quota limit to ensure efficient delivery.

Add CleverTap's FcmMessageListenerService

Inside the tags, register the following services:

<service
    android:name="com.clevertap.android.sdk.pushnotification.fcm.FcmMessageListenerService"
android:exported="true">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

For CleverTap SDK v3.4.3 and above, the CleverTap SDK supports specifying a custom FCM Sender ID. The SDK will request a token with the specified FCM Sender ID if it is present in the AndroidManifest.xml. If the FCM Sender ID is not available in the AndroidManifest.xml file, the SDK will request the token in the default manner, which uses the app's google-services.json file. To use a custom FCM Sender ID, add the following field in your app's AndroidManifest.xml:

❗️

Custom FCM Sender ID Feature Discontinued

The Custom FCM Sender ID feature has been discontinued in the versions of the CleverTap Android SDK after v4.3.1. CleverTap Android SDK only fetches the FCM token from the google-services.json file.

Opening a notification using CleverTap’s implementation launches your app. If you send a deeplink, the link will be opened.

Custom Android Push Notification Handling

Step 1. Using Your Custom Implementation
If you have your custom implementation for managing Android push notifications, you can inform CleverTap about the user’s FCM registration ID.

Follow the instructions below if you are using FCM.

String fcmRegId = FirebaseInstanceId.getInstance().getToken();
clevertapDefaultInstance.pushFcmRegistrationId(fcmRegId,true);
val fcmRegId = FirebaseInstanceId.getInstance().token
clevertapDefaultInstance?.pushFcmRegistrationId(fcmRegId, true)

Step 2: Using Multiple Android Push Notification Providers
CleverTap plays well with other Android push notification providers. You can configure your app to work with multiple push notification providers.

If you are using FCM, please follow these instructions:

  1. Subclass FirebaseMessagingService as shown below:
public class MyFcmMessageListenerService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage message){
        try {
            if (message.getData().size() > 0) {
                Bundle extras = new Bundle();
                for (Map.Entry<String, String> entry : message.getData().entrySet()) {
                    extras.putString(entry.getKey(), entry.getValue());
                }

                NotificationInfo info = CleverTapAPI.getNotificationInfo(extras);

                if (info.fromCleverTap) {
                    CleverTapAPI.createNotification(getApplicationContext(), extras);
                } else {
                    // not from CleverTap handle yourself or pass to another provider
                }
            }
        } catch (Throwable t) {
           Log.d("MYFCMLIST", "Error parsing FCM message", t);
        }
    }
}
class MyFcmMessageListenerService : FirebaseMessagingService() {

override fun onMessageReceived(message: RemoteMessage) {

    message.data.apply {
        try {
            if (size > 0) {
                val extras = Bundle()
                for ((key, value) in this) {
                    extras.putString(key, value)
                }
                val info = CleverTapAPI.getNotificationInfo(extras)
                if (info.fromCleverTap) {
                    CleverTapAPI.createNotification(applicationContext, extras)
                } else {
                    // not from CleverTap handle yourself or pass to another provider
                }
            }
        } catch (t: Throwable) {
            Log.d("MYFCMLIST", "Error parsing FCM message", t)
        }
    }
    }
}

If you are using CleverTap Android SDK v4.4.0 and above, you can add the following code instead of the above code:

public class MyFcmMessageListenerService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage message){
        CTFcmMessageHandler()
                .createNotification(getApplicationContext(), message);
    }
}
class MyFcmMessageListenerService : FirebaseMessagingService() {

    @Override
    public void onMessageReceived(RemoteMessage message){
        CTFcmMessageHandler()
                .createNotification(applicationContext, message)
    }
}

πŸ“˜

Note

From CleverTap Android SDK v5.1.0 onwards, the following API now runs on the caller's thread. Ensure to call it in onMessageReceive() of messaging service:

  • CTFcmMessageHandler().createNotification(getApplicationContext(), message)
  • CleverTapAPI.createNotification(getApplicationContext(),extras);
  1. Add your service to the AndroidManifest.xml in place of the CleverTap FcmMessageListenerService.
<service
    android:name="com.your.package.MyFcmMessageListenerService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>
  1. Replace com.your.package with the correct package name which contains the newly created class, MyFcmMessageListenerService.

  2. To track the push notification events and deeplinks add the following receiver in your AndroidManifest.xml:

<receiver
    android:name="com.clevertap.android.sdk.pushnotification.CTPushNotificationReceiver"
    android:exported="false"
    android:enabled="true">
</receiver>

Step 3: Structure of CleverTap FCM Payload

Here is the structure of the payload with a CleverTap FCM push notification.

KeyTypeDescription
wzrk_pnN/AIf present, this notification is sent from CleverTap.
wzrk_idstringOpen rate tracking ID (can be empty or it might not be present).
wzrk_bpstringIf present, the value will be the URL of an image that needs to be displayed in the notification.
wzrk_soundboolean or stringIf present, it signifies that the default or custom Android notification sound must be played.
ntstringNotification Title, if absent or empty, falls back to the app name.
nmstringNotification Body, if absent or empty, ignore this notification.
wzrk_dlstringIf present, this is a deeplink that must be followed at the time of notification open.
wzrk_dN/AIf present, ignore this notification.
icostringIf present and not empty, it contains the URL of an image that must be used as the small notification icon.
wzrk_pivotstringIf present and not empty, it signifies the type of variant in A/B campaigns.
wzrk_rnvstringIf present and not empty, it will raise the Push Impressions event.
wzrk_nmsstringIf present and not empty, it contains the summary text to be displayed along with the image.
wzrk_ststringIf present and not empty, it contains the subtitle text, which is displayed next to the App name.
wzrk_clrstringIf present and not empty, it contains the Hex value of the color to be applied on the small icon (and app name for Android versions below Pie)
wzrk_bpdsstringIf present and not empty, indicate the image rendering status in the push notification. Its values indicate the following statuses:
-NO_IMAGE: The push payload does not include an image.
-SUCCESS: The push payload contains an image that was downloaded successfully.
-NO_NETWORK: The push payload includes an image, but the user's device does not have network connectivity.
-DOWNLOAD_FAILED: The push payload contains an image that could not be downloaded due to an external error.

If the field nm is empty, ignore the notification. CleverTap sends out a dummy notification with the nm field empty to test for app uninstalls. In addition to the above, attach all keys starting with wzrk to your notification extras (For example, wzrk_id is used to track notification opens).

Set the Small Notification Icon

The small icon is a notification bar icon displayed in the push notifications, as shown in the image below:

1080

Set the Small Notification Icon

With the release of Android 5 (Lollipop), the notification icons are rendered differently in the notification bar at the top. By default, our SDK uses the app's icon for both the notification icon and the notification bar icon; however, since Android 5, all non-alpha channels are ignored while drawing the main notification icon. For more information, refer to Android Notification Guide in the Android documentation.

The small icon must be an alpha only image, which means it must have only one color and be transparent for the rest. The alpha only icon image combines the colored and transparent regions.

In general, the logo displayed on the icon has a single color, and the background is transparent. The alpha channel provides the ability to embed transparency within an image. This can be accomplished with tools such as Adobe Photoshop, Illustrator, and so on. You can also change the colored region of the small icon from the CleverTap dashboard.

The CleverTap SDK fills the transparent section of the small icon with the selected color:

2736

Set Small App Icon Color

Following is a small icon sample:

Example of a Small Icon

Example of a Small Icon

After creating an icon with the alpha channel, you can use it for your project in Android Studio. Save the icon file in the Drawable folder of your project.

To set a custom notification icon (only for the small icon), add the following metadata entry in your AndroidManifest.xml.

<meta-data
    android:name="CLEVERTAP_NOTIFICATION_ICON"
    android:value="ic_stat_red_star"/> <!-- name of your file in the drawable directory without the file extension. -->

❗️

Warning

Use only the file name. Do not use the path such as @drawable/ic_stat_red_star .

πŸ“˜

Device and Android Limitation

Push notification icons may be displayed in black and white on OnePlus, Oppo, and Realme devices due to support limitations of these device manufacturers for Android 12 and 13 versions.

Push Notification Callback

The CleverTap Android SDK v3.8.1 and above gives you a callback when a Push Notification is clicked along with the entire payload. Implement the CTPushNotificationListener in your Application class or Main Activity to receive this payload.

To set the listener, use the following code -

CleverTapAPI cleverTapAPI = CleverTapAPI.getDefaultInstance(getApplicationContext());
cleverTapAPI.setCTPushNotificationListener(this);
CleverTapAPI.getDefaultInstance(applicationContext)?.apply {
	ctPushNotificationListener = this@YourAndroidActivity
}

Implement the following override method to receive the payload as a Map on the click of a notification -

@Override
public void onNotificationClickedPayloadReceived(HashMap<String, Object> payload) {
   //Use your custom logic for  the payload 
}
override fun onNotificationClickedPayloadReceived(payload: HashMap<String, Any>?) {
    //Use your custom logic for  the payload 
}

Push Impressions

You can raise and record push notifications delivered to your users’ Android devices.

  1. Navigate to Settings > Schema > Events.
  2. Search for Push Impressions, then click on the vertical ellipsis.
Push Impressions

Push Impressions

  1. Click on Setup push impressions. A new window displays.
  2. Click on Save to enable the option.

If you are custom-handling push notifications, add the following code after you render the push notifications:

CleverTapAPI.getDefaultInstance(this).pushNotificationViewedEvent(extras);
CleverTapAPI.getDefaultInstance(this@YourAndroidActivity)?.pushNotificationViewedEvent(extras)

Pull Notification

Starting with v3.4.0, the SDK supports Pull Notification. This feature provides the capability to reach users on devices that suppress notifications via GCM/FCM.

To allow your app to use CleverTap's Pull Notification via background ping service, add the following fields in your app's AndroidManifest.xml:

<meta-data
    android:name="CLEVERTAP_BACKGROUND_SYNC"
    android:value="1"/>

🚧

Custom Handling

Additional integration is required if the app is rendering push notifications and not the CleverTap SDK. For more information, see custom handling of pull notification.

Custom Handling of Pull Notification

  1. In your custom FCM Receiver class, add the following code snippet when you receive the RemoteMessage object from Firebase. This method allows you to ensure that duplicate notification is not rendered on your device via Pull Notification.
if (message.getData().size() > 0) {
                Bundle extras = new Bundle();
                Iterator var = message.getData().entrySet().iterator();

                while(var.hasNext()) {
                    Map.Entry entry = (Map.Entry)var.next();
                    extras.putString((String)entry.getKey(), (String)entry.getValue());
                }
                    CleverTapAPI.processPushNotification(getApplicationContext(),extras);
                }
            }
if (message.getData().size() > 0)
{
  val extras = Bundle()
  val `var` = message.getData().entrySet().iterator()
  while (`var`.hasNext())
  {
    val entry = `var`.next() as Map.Entry
    extras.putString(entry.getKey() as String, entry.getValue() as String)
  }
  CleverTapAPI.processPushNotification(getApplicationContext(), extras)
}
  1. In your Application class, implement the CTPushAmpListener interface.
public class MyApplication extends Application implements CTPushAmpListener {

// your application class code
}
class MyApplication:Application(), CTPushAmpListener// your application class code
  1. In the onCreate() method of your Application class, create an instance of CleverTapAPI and set the CTPushAmpListener as following:
CleverTapAPI cleverTapAPI = CleverTapAPI.getDefaultInstance(getApplicationContext());
cleverTapAPI.setCTPushAmpListener(this);
val cleverTapAPI = CleverTapAPI.getDefaultInstance(getApplicationContext())
cleverTapAPI.setCTPushAmpListener(this)
  1. After the listener is set, whenever a notification is sent to the device via Pull Notification, the app will receive the payload in the onPushPayloadReceived method. Implement this method as follows and ensure that your rendering logic of the Push Notification is written here:
@Override
public void onPushPayloadReceived(Bundle bundle) {
  CTFcmMessageHandler()
                .createNotification(getApplicationContext(), message);
  //OR
  //write push notification rendering logic here
}
fun onPushPayloadReceived(bundle:Bundle) {
  CTFcmMessageHandler()
                .createNotification(getApplicationContext(), message)
 //OR
 //write push notification rendering logic here
}

FAQs

What are the steps to migrate from Legacy API to FCM v1 APIs?

For detailed steps, refer to Configure Push Notifications. You can also check our video, which gives a quick walkthrough of the steps for migrating to the new FCM APIs.

What is the new API Rate Limit? How does it impact the push notification deliverability?

Each Firebase project using the HTTP v1 APIs is strictly limited to a specific number of requests per minute. For more information, refer to HTTP v1 API Rate Limits.

How do I resolve the "Wrong FCM API Key" error?

Ensure that you create a new Service Account from the correct Firebase project on the Firebase Console and assign it the Firebase Cloud Messaging API Admin role, not the Firebase Cloud Messaging Admin role. For more information, refer to Safeguard Admin Credentials.

Do we need to update the CleverTap SDK to migrate to HTTP v1 API?

No, you need not update CleverTap SDK update. You just need to upload the FCM Credentials on the CleverTap Dashboard.

I have already uploaded the credentials. Is there anything else I need to do to migrate to the HTTP v1 API?

No. If you have added credentials, CleverTap automatically transitions from legacy APIs to v1 APIs. Ensure that you always add throttle for Push Notification to keep the rate limit in check.

What happens if I fail to migrate to new v1 APIs before June 2024?

You will not be able to send Push Notifications via legacy credentials; instead, it results in an error.

How can I increase the rate limit for my account?

To request an increase in the rate limit, contact Firebase Support.