Push Notifications - Technical Integration Guide

This guide will help you through the process of setting up your app so that Customer.io can dispatch push notifications to it. We’ve worked hard to keep integration super simple. With no required SDK, the integration process requires minimal code changes to your app.

Step 1: Generating & adding certificates

First, you must generate certificates from the Apple and/or Google Push Notification Services and add them to Customer.io, so we can dispatch to your app. We’ve documented how to add these certificates here:

Getting Started with Push Notifications

Step 2: Configure push in your app

Next, you must let iOS and/or Android know that push notifications will be dispatched for your app.

The provided code samples are a minimal checklist to get push notifications up and running. You’ll want to get familiar with your platform to understand the range of configuration options available.

If you already send Push Notifications through your app, then very little needs to change to work with Customer.io. Be aware that we send two custom parameters in the payload of push notification you’ll want to pay attention to: CIO-Delivery-ID & CIO-Delivery-Token. These are used for sending Open events back to us.

iOS App Setup

The following shows an example of how to registering for remote notifications in iOS. The samples provided here are using the Swift language.

  1. Open the project editor and enable Push Notifications under the Capabilities tab

  2. Update the didFinishLaunchingWithOptions callback in the AppDelegate.swift to request the device token
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
         // Configure the user interactions first.
         self.configureUserInteractions()
            
         // Register with APNs may be different based on ios versions you want to support
         UIApplication.shared.registerForRemoteNotifications()
    
         return true
     }
    
  3. Also add the following methods to handle the behavior when the token request succeeds or fails
     // Handle remote notification registration.
     func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data){
         self.enableRemoteNotificationFeatures()
         // Convert token to string
         let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
         // Forward the token to your provider, using a custom method.
         self.forwardTokenToServer(token: deviceTokenString)
     }
        
     func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
         // The token is not currently available.
         print("Remote notification support is unavailable due to error: \(error.localizedDescription)")
         self.disableRemoteNotificationFeatures()
     }
    
  4. The only other method you need to add is to handle the notification
     // Push notification received
     func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {  
         // Print notification payload data
         print("Push notification received: \(data)")
    
         // Customer.io push notifications include data regarding the push
         // message in the data part of the payload which can be used to send
         // feedback into our system.
         var deliveryID: String = "";
         if let value = data["CIO-Delivery-ID"] {
             deliveryID = String(describing: value)
         }
         var deliveryToken: String = "";
         if let value = data["CIO-Delivery-Token"] {
             deliveryToken = String(describing: value)
         }
     }
    

Android App Setup

The following shows an example of how to register with Firebase in Android. The easiest way to integrate Firebase Cloud Messaging into your Android app is to use the Firebase Assistant Tool in Android Studio which will walk you through the required steps.

At the time of writing the steps required were the following:

  1. Add the Firebase SDK as a dependency into your build.gradle file:
     compile 'com.google.firebase:firebase-messaging:12.0.1'
    
  2. Create a new service which extends the FirebaseInstanceIdService class. Within this class you need a onTokenRefresh function in which you can use FirebaseInstanceId.getInstance().getToken() to retrieve the device message token.
     public class FirebaseIdentifierService extends FirebaseInstanceIdService {
         public FirebaseIdentifierService() {
         }
    
         @Override
         public void onTokenRefresh() {
             // Get updated InstanceID token.
             String refreshedToken = FirebaseInstanceId.getInstance().getToken();
             Log.d("firebase", "Refreshed token: " + refreshedToken);
         }
     }
    

Note that this function is only called when the device token changes, so if you need access to it at other activities you may want to save it in a variable for later use.

  1. Next we need to update the AndroidManifest.xml to add the service:
     <service
         android:name=".FirebaseIdentifierService"
         android:enabled="true"
         android:exported="true">
         <intent-filter>
             <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
         </intent-filter>
     </service>
    
  2. Now that we are able to generate the token the next step is to be able to handle messages. For this we will once again create a new service which will extend FirebaseMessagingService.
     public class NotifierService extends FirebaseMessagingService {
         private static final String TAG = "messaging";
    
         public NotifierService() {
         }
    
         @Override
         public void onMessageReceived(RemoteMessage remoteMessage) {
             // Check if message contains a data payload.
             // You can have data only notifications.
             if (remoteMessage.getData().size() > 0) {
                 Log.d(TAG, "Message data payload: " + remoteMessage.getData());
    
                 // Customer.io push notifications include data regarding the push
                 // message in the data part of the payload which can be used to send
                 // feedback into our system.
                 String deliveryId = remoteMessage.getData().get("CIO-Delivery-ID");
                 String deliveryToken = remoteMessage.getData().get("CIO-Delivery-Token");
             }
    
             // Check if message contains a notification payload.
             if (remoteMessage.getNotification() != null) {    
                 handleNotification(remoteMessage.getNotification());
             }
         }
    
         private void handleNotification(RemoteMessage.Notification notification) {
             Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
         }
     }
    
  3. Once more we need to update the AndroidManifest.xml to add the service:
     <service
         android:name=".NotifierService"
         android:enabled="true"
         android:exported="true">
         <intent-filter>
             <action android:name="com.google.firebase.MESSAGING_EVENT"/>
         </intent-filter>
     </service>
    

Step 3: Identify Device Tokens with Customer.io

The core requirement to get up and running with push notifications using Customer.io is identifying users and their devices as they interact with your application. Typically, this should be sent every time the app is launched on a client device.

Our recommendation is to make these calls using one of our client libraries from your backend system rather than directly from your app. If however this is not possible and the calls must be made from within the application you’ll want to ensure they run asynchronously.

To add a device to the customer profile, call this REST endpoint:

Method:  PUT
URL:     https://track.customer.io/api/v1/customers/{customer_id}/devices
JSON Payload: 
{
    "device": {
        "id": "messaging token",
        "platform": "ios/android",
        "last_used": UNIX timestamp when the device was used
    }
}

When we receive this call we will create or update the customers device list.

Note we only store 25 devices per customer and if a new device is being added we remove the device with the oldest last_used timestamp.

You can notify us to remove a device from the customers list by sending the following request:

Method:  DELETE
URL:     https://track.customer.io/api/v1/customers/{customer_id}/devices/{token}

Step 4: Send Events for key customer actions

If you’d like Customer.io to track metrics for when your push notifications have been opened, you need to send an event when your app detects it was opened as result of a customer tapping a notification.

For push deliveries we send meta information along with the message that you can use to notify us when the delivery is used to open the app on the device.

When we delivery a push notification, Customer.io includes CIO-Delivery-ID & CIO-Delivery-Token parameters you can use when sending an event named opened. We will track the push notification as being opened and show it as a metric in your campaigns. To enable this behavior, send the following API request:

Method:  POST
URL:     https://track.customer.io/push/events
JSON Payload: 
{
    "delivery_id": "CIO-Delivery-ID from the notification",
    "event": "opened",
    "device_id": "CIO-Delivery-Token from the notification",
    "timestamp": UNIX timestamp when the event occured
}

Step 5: Send yourself a test push notification

Finally, be sure to verify that you’ve configured everything correctly by sending yourself a test push notification. Our Getting Started with Push Notifications guide shows you how to send test notifications.