Integrating Push Notifications

Push Notifications are a great way to keep your users engaged with your application. Countly Push Notifications gives product managers, marketers, and developers a simple way to send, manage, and analyze push notifications for applications on the world's most popular platforms - iOS, Android, and Huawei devices.

Countly relies on platform-specific push notification providers to deliver messages:

  • APN (Apple Push Notification service) - for iOS, iPadOS, watchOS, tvOS, and macOS apps
  • FCM (Firebase Cloud Messaging) - for Android apps with Google Play Services
  • HMS (Huawei Mobile Services) - for Huawei devices without Google Play Services

This guide walks you through the complete setup - from acquiring provider credentials and uploading them to your Countly Server, to integrating the SDK in your application.

Availability: Push Notifications are available in Countly Lite, Countly Enterprise, and as an add-on in Flex. Countly Lite has limited feature and view availability. Enterprise Edition includes additional geolocations support.

How Push Notifications Work

When a user opens your app for the first time, the Countly SDK automatically retrieves a device token from the respective push notification provider (Firebase or Huawei Push Kit for Android, APN for iOS) and sends it to your Countly Server for storage. A token is unique to a device, meaning it identifies that particular device.

The high-level flow is:

  1. Your App (SDK) - retrieves a device token from the provider on first launch.
  2. APN / FCM / HMS - issues the token to the device.
  3. Countly Server - stores the token and uses your uploaded credentials to send notification payloads.
  4. APN / FCM / HMS - delivers the notification to the user's device.

Token retrieval and submission to the Countly Server are handled automatically by the Countly SDK. You won't need to worry about this process once you have integrated the Countly SDK properly as shown in the steps below.

Select your provider:

FCM
APN
HMS

Server Side Setup

To send push notifications to Android devices, you need a Firebase project with your Android app registered and the Firebase Cloud Messaging API (V1) enabled. Countly uses the FCM HTTP v1 API, which requires a Service Account JSON file from your Firebase project.

  1. Open the Firebase Console and select your project.
  2. Go to Project Settings (gear icon) > Service accounts tab.
  3. Click Generate new private key and confirm. A JSON file will be downloaded - store it securely.
  4. Ensure that the Firebase Cloud Messaging API (V1) is enabled for your project. You can verify this in the Google Cloud Console API Library.
  5. In the Countly Dashboard, navigate to Management > Applications > Your App > Push Notifications. Upload the Service Account JSON file under the FCM section and click Save changes.

Important: Do not confuse google-services.json (used by the client SDK in your app) with the Service Account JSON (used by the server to send notifications). They are different files. The Service Account JSON is the one downloaded from the Service accounts tab in the Firebase Console.

To send push notifications to iOS devices, you need an active Apple Developer Account. Countly supports two authentication methods for APN: Auth Key (.p8) and Certificate (.p12). We strongly recommend using the Auth Key approach - it does not expire, works for both sandbox and production environments, and is simpler to manage.

Auth Key (.p8) - Recommended Certificate (.p12)
  1. Sign in to the Apple Developer Portal and navigate to Certificates, Identifiers & Profiles > Keys.
  2. Click the + button to create a new key. Enable Apple Push Notifications service (APNs), give it a name, and click Register.
  3. Download the .p8 file. You can only download this file once, so store it securely.
  4. Note the Key ID (shown on the key details page), your Team ID (found under Membership Details), and the Bundle ID of your app.
  5. In the Countly Dashboard, go to Management > Applications > Your App > Push Notifications. Upload the .p8 file, and fill in the Key ID, Team ID, and Bundle ID fields. Click Save changes.

Countly will validate the credentials by initiating a test connection to APN. If validation fails, double-check that the Key ID, Team ID, and Bundle ID are correct.

To send push notifications to Huawei devices, you need a Huawei AppGallery Connect project with Push Kit enabled.

  1. Sign in to Huawei AppGallery Connect, select your project, and navigate to Grow > Push Kit.
  2. Enable Push Kit if it is not already enabled.
  3. Navigate to Project settings > General information to find your App ID and App Secret (under App information).
  4. In the Countly Dashboard, navigate to Management > Applications > Your App > Push Notifications. Enter the App ID and App Secret under the HMS section and click Save changes.

SDK Side Setup

All code samples assume you have already integrated the Countly SDK into your project. If you haven't, please refer to the Getting Started with SDKs guide first.

Select an SDK:

Android Flutter React Native Unity

Make sure you have followed Google's guide for adding Firebase to your project. Then add the Firebase Messaging dependency to your app-level build.gradle:

// app/build.gradle
// use the latest firebase-messaging version that is available
implementation 'com.google.firebase:firebase-messaging:LATEST_VERSION'

Add a service definition to your AndroidManifest.xml:

<service android:name=".DemoFirebaseMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Add a class for the service:

public class DemoFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onNewToken(@NonNull String token) {
        super.onNewToken(token);
        CountlyPush.onTokenRefresh(token);
    }

    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        CountlyPush.Message message = CountlyPush.decodeMessage(remoteMessage.getData());
        if (message != null) {
            message.recordAction(getApplicationContext());
            CountlyPush.displayMessage(getApplicationContext(), message, R.drawable.ic_message, null);
        }
    }
}

Initialize CountlyPush in your Application class. Then initialize the Countly SDK as usual:

// In your Application.onCreate()
CountlyConfigPush countlyConfigPush = new CountlyConfigPush(this);
CountlyPush.init(countlyConfigPush);

CountlyConfig config = new CountlyConfig(this, "APP_KEY", "https://YOUR_SERVER");
Countly.sharedInstance().init(config);

Intent Redirection Security

By default, the Countly Android SDK enables additional intent redirection checks to protect against Intent Redirection Vulnerability. You can allowlist specific intents if needed:

CountlyConfigPush countlyConfigPush = new CountlyConfigPush(this)
    .setAllowedIntentClassNames(allowedClassNames)
    .setAllowedIntentPackageNames(allowedPackageNames);
CountlyPush.init(countlyConfigPush);

Select an SDK:

iOS Flutter React Native Unity

Xcode Configuration

Under the Signing & Capabilities section of Xcode, enable the following for your target:

  1. Click + Capability and add Push Notifications.
  2. Click + Capability again and add Background Modes. Enable Remote notifications.

SDK Initialization

Start Countly in the application:didFinishLaunchingWithOptions: method of your app. Do not forget to specify CLYPushNotifications in the features array on the CountlyConfig object:

#import "Countly.h"

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    CountlyConfig* config = CountlyConfig.new;
    config.appKey = @"APP_KEY";
    config.host = @"https://YOUR_COUNTLY_SERVER";
    config.features = @[CLYPushNotifications];
    [Countly.sharedInstance startWithConfig:config];

    return YES;
}

Note: Make sure you start Countly iOS SDK on the main thread.

The Countly iOS SDK handles everything automatically - requesting notification permission, retrieving the device token, processing incoming notifications, and managing Notification Service Extensions for rich push (media attachments and custom action buttons).

The Unity SDK does not support Huawei Push Kit.

Select an SDK:

Android Flutter React Native

Assuming you have already integrated HMS Core into your app, add the Huawei Push Kit dependency to your app-level build.gradle (use the latest dependency version):

implementation 'com.huawei.hms:push:LATEST_VERSION'

Add a service definition to AndroidManifest.xml:

<service
    android:name=".DemoHuaweiMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.huawei.push.action.MESSAGING_EVENT" />
    </intent-filter>
</service>

Add the service class:

public class DemoHuaweiMessagingService extends HmsMessageService {

    @Override
    public void onNewToken(String token) {
        super.onNewToken(token);
        CountlyPush.onTokenRefresh(token, Countly.CountlyMessagingProvider.HMS);
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        CountlyPush.Message message = CountlyPush.decodeMessage(remoteMessage.getDataOfMap());
        if (message != null) {
            message.recordAction(getApplicationContext());
            CountlyPush.displayMessage(getApplicationContext(), message, R.drawable.ic_message, null);
        }
    }
}

Initialize CountlyPush with HMS as the preferred provider, then initialize the Countly SDK:

// In your Application.onCreate()
CountlyConfigPush countlyConfigPush = new CountlyConfigPush(this)
    .setProvider(Countly.CountlyMessagingProvider.HMS);
CountlyPush.init(countlyConfigPush);

CountlyConfig config = new CountlyConfig(this, "APP_KEY", "https://YOUR_SERVER");
Countly.sharedInstance().init(config);

Customizing Notification Sound

Countly supports custom notification sounds on every platform that exposes a native sound API. The sound file must be present on the device — push payloads can reference it by name or URI, but cannot link to an audio file on the internet. The device-side setup is described below per platform; sending the sound is then done from the Countly Dashboard Send sound field when creating a push notification.

Custom sound files must ship inside the app bundle (iOS) or under the Android res/raw resource folder. They cannot be downloaded at notification time.

Android iOS Flutter React Native Unity

Place the sound file in your Android project's res/raw folder, then build the resource URI:

String soundUri = ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getApplicationContext().getPackageName() + "/" + R.raw.notif_sound;

Send this URI in the Send sound field of the Countly Dashboard when creating a push notification. This covers devices running Android with SDK version below 26.

For Android SDK 26 and above, the sound is bound to the notification channel rather than the individual notification. Provide the same URI when you create the notification channel:

AudioAttributes audioAttributes = new AudioAttributes.Builder()
    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
    .setUsage(AudioAttributes.USAGE_NOTIFICATION)
    .build();

channel.setSound(soundUri, audioAttributes);

If your app requires GDPR compliance or uses Countly's consent management feature, you must grant the push consent for push notifications to function. Without this consent, the SDK will not send the device token to the server.

Android iOS Flutter React Native Unity
// Give push consent during initialization
config.setConsentEnabled(new String[]{"push"});

// Or after initialization
Countly.sharedInstance().consent().giveConsent(new String[]{"push"});

// Revoke consent
Countly.sharedInstance().consent().removeConsent(new String[]{"push"});

The Countly SDK does not persistently store the status of given consents except for push notifications. You are expected to handle receiving consent from end-users using proper UIs depending on your app's context, and call the giveConsent method on each app launch depending on the permissions you managed to get from the end-users.

Separating Marketing and Informative Push Notifications

SDK consent acts as a channel-wide gate. When the push consent is not granted, no notifications reach the device, including informative ones such as transaction receipts or service status updates. To deliver informative push to every user while reserving marketing pushes for opted-in users, grant SDK consent unconditionally and segment campaigns on the server through a custom user property.

  1. Grant SDK consent unconditionally. Regardless of the user's marketing preference, grant the push consent shown above. This keeps the device eligible to receive any push notification, whether informative or marketing.
  2. Track the marketing preference as a custom user property. When the user accepts or declines marketing communications in your app, record that decision as a user property such as marketing_consent:

    // Android
    Countly.sharedInstance().userProfile().setProperty("marketing_consent", "true");
    Countly.sharedInstance().userProfile().save();

    Equivalent user-profile methods exist in every Countly SDK. See the User Profile section of the SDK documentation for your platform.

  3. Segment campaigns in Countly. Use marketing_consent as a segmentation filter when creating a push notification:
    • Informative campaigns (transactional messages, service updates): no filter on marketing_consent, so every push-enabled user is reachable.
    • Marketing campaigns (promotions, news): filter by marketing_consent = "true", so only opted-in users receive them.

Set marketing_consent explicitly for every user during onboarding, even when the user skips the consent prompt. If the property is never recorded, those users may unintentionally pass through marketing filters depending on how the dashboard condition is configured.

Testing Push Notifications

After completing both the server-side credential upload and SDK integration, follow these steps to verify everything is working:

  1. Run your app on a physical device (push notifications do not work on most simulators/emulators). On iOS, accept the notification permission prompt when it appears.
  2. Check the Countly Dashboard. Navigate to Push Notifications. You should see at least 1 push-enabled user for your platform. This confirms that the device token was successfully sent to the Countly Server.
  3. Send a test notification. Click + New Message, select the platform, compose a message, and choose Send to test users. The notification should appear on your test device within seconds.

Test users can be defined in the Countly Dashboard under Management > Applications > Your App > Push Notifications settings. This allows you to send test push notifications to specific devices before targeting your full audience.

Troubleshooting & FAQ

For common issues, error codes, and frequently asked questions about push notifications, see our dedicated troubleshooting page:

Was this page helpful?
Reach out to us for any other questions.
Helpful?

Looking for more Help?