Rich push notifications
UpdatedThere's a new version available!
These pages cover version 1 of our SDK, but a newer version is available. In general, we suggest that you update to the latest version to take advantage of new features and fixes.
- Are you new to our SDKs? Check out the latest docs.
- Otherwise, learn about updating to the latest version
With rich push, you can do more than just send a simple notification; you can send an image, open a deep link when someone taps your message, and more!
This page is part of a setup flow for the SDK. Before you continue, make sure you've implemented previous features—i.e. you can't receive in-app notifications before you identify people!
Device Token) register-token -.-> push(Receive push) register-token -.-> rich-push(Receive Rich Push) track-events --> test-support(Write tests) push --> test-support rich-push --> test-support identify -.-> in-app(Receive in-app) in-app --> test-support click getting-started href "/sdk/ios/getting-started/#install" click B href "/sdk/ios/getting-started/#initialize-the-sdk" click identify href "/sdk/ios/identify" click track-events href "/sdk/ios/track-events/" click register-token href "/sdk/ios/push" click push href "/sdk/ios/push" click rich-push href "/sdk/ios/rich-push" click in-app href "/sdk/ios/in-app" click test-support href "/sdk/ios/test-support" style rich-push fill:#B5FFEF,stroke:#007069
Before you begin
You should set up APN or FCM push notifications and make sure that you can send yourself a test push notification before you start implementing rich push.
While rich push generally entails a number of features, our SDK only supports deep links and images right now. If you want to include action buttons or other rich push features, you need to add your own custom code.
When writing your own custom code, we recommend that you use our SDK as it is much easier to extend than writing your own code from scratch. Read below for tips on how to extend the functionality of the SDK with features we do not yet support.
Check out our sample apps!
Set up rich push
You should now see a new file added to your Xcode project. The file is probably named
NotificationService
and looks similar to this.import UserNotifications class NotificationService: UNNotificationServiceExtension { override func didReceive( _ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { } override func serviceExtensionTimeWillExpire() { } }
Modify this file by selecting the push package you want to import and calling the appropriate Customer.io functions. Your code changes if:
- Customer.io is your only push/rich push provider
- Customer.io is not your only provider
- You want to take advantage of push features outside the Customer.io, like action buttons; in this case, you’ll need to set your own completion handler.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// Keep the import for your push provider—FCM or APN, and // remove the other import statement import CioMessagingPushFCM import CioMessagingPushAPN import UserNotifications import CioTracking class NotificationService: UNNotificationServiceExtension { override func didReceive( _ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { // Because of the behavior of Notification Service Extensions in iOS, you need to // initialize the Customer.io SDK in your host app and in your Notification Service. CustomerIO.initialize(siteId: "YOUR SITE ID", apiKey: "YOUR API KEY", region: Region.EU) MessagingPush.shared.didReceive(request, withContentHandler: contentHandler) } override func serviceExtensionTimeWillExpire() { MessagingPush.shared.serviceExtensionTimeWillExpire() } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// Keep the import for your push provider—FCM or APN, and // remove the other import statement import CioMessagingPushFCM import CioMessagingPushAPN import UserNotifications import CioTracking class NotificationService: UNNotificationServiceExtension { override func didReceive( _ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { // Because of the behavior of Notification Service Extensions in iOS, you need to // initialize the Customer.io SDK in your host app and in your Notification Service. CustomerIO.initialize(siteId: "YOUR SITE ID", apiKey: "YOUR API KEY", region: Region.EU) // If you use a service other than Customer.io to send rich push, // you can check if the SDK handled the rich push for you. If it did not, you // know that the push was *not* sent by Customer.io and you can try another way. let handled = MessagingPush.shared.didReceive(request, withContentHandler: contentHandler) if !handled { // Rich push was *not* sent by Customer.io. Handle the rich push in another way. } } override func serviceExtensionTimeWillExpire() { MessagingPush.shared.serviceExtensionTimeWillExpire() } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
// Keep the import for your push provider—FCM or APN, and // remove the other import statement import CioMessagingPushFCM import CioMessagingPushAPN import UserNotifications import CioTracking class NotificationService: UNNotificationServiceExtension { override func didReceive( _ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { // Because of the behavior of Notification Service Extensions in iOS, you need to // initialize the Customer.io SDK in your host app and in your Notification Service. CustomerIO.initialize(siteId: "YOUR SITE ID", apiKey: "YOUR API KEY", region: Region.EU) // If you need to add features, like showing action buttons in your push, // you can set your own completion handler. MessagingPush.shared.didReceive(request) { notificationContent in if let mutableContent = notificationContent.mutableCopy() as? UNMutableNotificationContent { // Modify the push notification like adding action buttons! } contentHandler(notificationContent) } } override func serviceExtensionTimeWillExpire() { MessagingPush.shared.serviceExtensionTimeWillExpire() } }
Your app can now display rich push notifications in your app, including images, etc. However, if you want to enable deep links, you should continue to the Deep links section below.
Deep links
After you set up rich push notifications you can enable deep links in rich push notifications.
Modify your
AppDelegate
with the following information. This enables your app to launch a deep link URL when someone taps a notification.import CioMessagingPushAPN import CioTracking import Foundation import UIKit class AppDelegate: NSObject, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { CustomerIO.initialize(siteId: "YOUR SITE ID", apiKey: "YOUR API KEY", region: Region.US) // Must call this function in order for `UNUserNotificationCenterDelegate` functions // to be called. UNUserNotificationCenter.current().delegate = self // It's good practice to always register for remote push when the app starts. // This asserts that the Customer.io SDK always has a valid APN device token to use. UIApplication.shared.registerForRemoteNotifications() return true } } extension AppDelegate: UNUserNotificationCenterDelegate { func userNotificationCenter( _ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void ) { let handled = MessagingPush.shared.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) // If the Customer.io SDK does not handle the push, it's up to you to handle it and call the // completion handler. If the SDK did handle it, it called the completion handler for you. if !handled { completionHandler() } } // OPTIONAL: If you want your push UI to show even with the app in the foreground, override this function and call // the completion handler. @available(iOS 10.0, *) func userNotificationCenter( _ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void ) { completionHandler([.list, .banner, .badge, .sound]) } }
Setup deep linking in your app. There are two ways to do this, and you can do both if you choose.
- Universal Links: universal links are great if you want to open your mobile app instead of a web browser when your goes to a page on your website. However, universal links take more time to setup. Follow this guide to set up Universal Links in your app.
- App scheme: app scheme deep links are quick and easy to setup. However, they do not work if the mobile app is not installed, which is where universal links provide an advantage. To enable app scheme deep links. See the section below to enable app scheme deep links.
Setup App Scheme Deep Links
App scheme deep links only work if your audience has your mobile app installed. If you want to support cases where your audience might not already have your app, you can set up universal links.
Open your Xcode project and go to your project’s settings. Select your app Target, click the Info tab, and then click URL Types > to create a new URL Type.
Test Rich Push
After you set up rich push, you should test your implementation. Use the payloads below to send a push in the Customer.io web app with a Custom Payload.
In both of the test payloads below, you should:
- Set the
link
to the deep link URL that you want to open when your tester taps your notification. - Set the
image
to the URL of an image you want to show in your notification. It’s important that the image URL starts withhttps://
and nothttp://
or the image might not show up.
{
"CIO": {
"push": {
"link": "remote-habits://deep?message=hello&message2=world",
"image": "https://thumbs.dreamstime.com/b/bee-flower-27533578.jpg"
}
},
"aps": {
"mutable-content": 1,
"alert": {
"title": "Title of your push goes here!",
"body": "Body of your push goes here!"
}
}
}
{
"message": {
"apns": {
"payload": {
"CIO": {
"push": {
"link": "remote-habits://deep?message=hello&message2=world",
"image": "https://thumbs.dreamstime.com/b/bee-flower-27533578.jpg"
}
},
"aps": {
"mutable-content": 1,
"alert": {
"title": "Title of your push goes here!",
"body": "Body of your push goes here!"
}
}
}
}
}
}
Rich push payloads
To send a rich push in Customer.io, you need to use our Custom Payload editor, which takes a JSON structure. In the editor, you’ll select the type of device you want to send your message to: you can have separate payloads for Android and iOS. In our case, you’ll click iOS.
The top level of the payload changes slightly depending on your push provider, APNS or FCM. Otherwise, your JSON is split into two major objects:
- an
aps
object, which contains the standard aspects of a push—thealert.title
andalert.body
of your message—and Apple’s push options. - a
CIO
object containing the rich aspects of your message that the SDK will interpret. At present, it containslink
andimage
strings.
{
"aps": {
// basic iOS message and options go here
"mutable-content": 1,
"alert": {
"title": "string", //(optional) The title of the notification.
"body": "string" //(optional) The message you want to send.
}
},
"CIO": {
"push": {
"link": "string", //generally a deep link, i.e. my-app:://...
"image": "string" //HTTPS URL of your image, including file extension
}
}
}
-
-
- image stringThe URL of an HTTPS image that you want to use for your message.
- link stringA deep link (to a page in your app), or a link to a web page.
-
-
- alertstringA simple alert message.
- badge integerThe number you want to display on your app’s icon. Set to 0 to remove the current badge, if any.
- category stringThe notification’s type. This string must correspond to the identifier of one of the
UNNotificationCategory
objects you register at launch time. - content-available integerThe background notification flag. Use
1
without analert
to perform a silent update.0
indicates a normal push notification. - interruption-level stringIndicates the importance and delivery timing of a notification.
Accepted values:
passive
,active
,time-sensitive
,critical
- mutable-content integerIf you use the Customer.io SDK, you must set this value to
1
to support images and “delivered” metrics from your push notifications. When the value is 1, your notification is passed to your notification service app extension before delivery. Use your extension to modify the notification’s content. - relevance-score numberA number between 0 and 1. The highest score is considered the “most relevant” and is featured in the notification summary.
- soundstringThe name of a sound file in your app’s main bundle or in the Library/Sounds folder of your app’s container directory. Use “default” to play the system sound. For critical alerts, you’ll pass an object instead.
- target-content-id stringThe identifier of the window brought forward.
- thread-id stringAn identifier to group related notifications.
{
"message": {
"apns": {
"payload": {
"aps": {
// basic iOS message and options go here
"mutable-content": 1,
"alert": {
"title": "string", //(optional) The title of the notification.
"body": "string" //(optional) The message you want to send.
}
},
"CIO": {
"push": {
"link": "string", //generally a deep link, i.e. my-app://... or https://yourwebsite.com/...
"image": "string" //HTTPS URL of your image, including file extension
}
}
},
"headers": {
// (optional) headers to send to the Apple Push Notification Service.
"apns-priority": 10
}
}
}
}
-
-
-
-
-
- body stringThe body of your push notification.
- image stringThe URL of an HTTPS image that you want to use for your message.
- link stringA deep link (to a page in your app), or a link to a web page.
- title stringThe title of your push notification.
-
-
- alertstringA simple alert message.
- badge integerThe number you want to display on your app’s icon. Set to 0 to remove the current badge, if any.
- category stringThe notification’s type. This string must correspond to the identifier of one of the
UNNotificationCategory
objects you register at launch time. - content-available integerThe background notification flag. Use
1
without analert
to perform a silent update.0
indicates a normal push notification. - interruption-level stringIndicates the importance and delivery timing of a notification.
Accepted values:
passive
,active
,time-sensitive
,critical
- mutable-content integerIf you use the Customer.io SDK, you must set this value to
1
to support images and “delivered” metrics from your push notifications. When the value is 1, your notification is passed to your notification service app extension before delivery. Use your extension to modify the notification’s content. - relevance-score numberA number between 0 and 1. The highest score is considered the “most relevant” and is featured in the notification summary.
- soundstringThe name of a sound file in your app’s main bundle or in the Library/Sounds folder of your app’s container directory. Use “default” to play the system sound. For critical alerts, you’ll pass an object instead.
- target-content-id stringThe identifier of the window brought forward.
- thread-id stringAn identifier to group related notifications.
- Custom key-value pairs* any typeAdditional properties that you've set up your app to interpret outside of the Customer.io SDK.
-
-