Context Push
This page explains how to use ContextSDK to increase the open-rate of your mobile push notifications.
Overview
- Step 1: Add ContextSDK to your app
- Step 2: Ship app into production in Calibration Mode
- Step 3: Once the model is ready, you'll get a message and can choose the Over-The-Air rollout
How does it work?
- Your existing push notification provider / engagement platform sends a background push notification
- Your app briefly wakes up for a few seconds to detect the user's real-world context
- During calibration phase, your notifications will always be delivered the moment it's received
- Once your custom model is ready, we deploy a CoreML machine learning model to your app
- From that moment on, your notifications will be shown at the optimal time for the highest open-rate
- You have control over the time span in which the notification is shown (e.g. best moment within 12 hours)
- Use Context Push for non-time-sensitive notifications, such as news, promotions, or reminders
Impact on your app
Less than 0.2% CPU Usage
0.6 MB Memory Usage
Adds less than 700kb to your app's binary size
No PII processed or stored
No app permissions required
Operates without ATT
Installation
Register here to get your license key, then add the SDK to your app:
Add https://github.com/context-sdk/context-sdk-releases
as dependency.
- Download the latest release: https://storage.googleapis.com/de73e410-context-sdk-releases/latest/ContextSDK.zip
- Drag & Drop the
ContextSDK.xcframework
folder into the Xcode file list - Go to your project settings, scroll down to
Frameworks, Libraries, and Embedded Content
, addContextSDK.xcframework
, and selectEmbed & Sign
If you want to download a specific version, you can replace latest
with the desired version number, e.g. https://storage.googleapis.com/de73e410-context-sdk-releases/3.1.0/ContextSDK.zip
Usage
In your AppDelegate.swift
, the following changes are needed:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
// Update the CustomerIO profile attribute to set if background processing is allowed
// (replace this with your existing `identify` call, if you have this somewhere else, that is okay also)
CustomerIO.shared.identify(userId: email, traits: ["ctx_background_push_allowed": UIApplication.shared.backgroundRefreshStatus == .available])
// If you don't already have this line
UNUserNotificationCenter.current().delegate = self
// Your other code here
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
{
let userInfo = response.notification.request.content.userInfo
// You can call this for every notification, we automatically filter out the ones not relevant
ContextManager.handleNotificationClicked(userInfo: userInfo)
completionHandler()
}
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
{
// Update the CustomerIO profile attribute "ctx_last_processed" to be the current date
CustomerIO.shared.identify(userId: email, traits: ["ctx_last_processed": round(Date().timeIntervalSince1970)])
if application.applicationState == .background || application.applicationState == .inactive {
if let title = userInfo["ctx_title"] as? String,
let body = userInfo["ctx_body"] as? String,
let collapseId = userInfo["ctx_collapse_id"] as? String,
let flowName = userInfo["ctx_flow_name"] as? String,
let notificationDeadlineH = userInfo["ctx_notification_deadline_h"] as? Int
{
let pushContent = UNMutableNotificationContent()
pushContent.title = title
pushContent.body = body
ContextManager.deliverNotificationIfGoodMoment(
flowName: flowName,
collapseId: collapseId,
notificationContent: pushContent,
notificationDeadlineH: notificationDeadlineH,
completionHandler: completionHandler
)
} else {
print("Error parsing userInfo of notification: \(userInfo)")
completionHandler(.failed)
}
} else {
// Your app is already running, you can still decide to show the notification
}
}
Enable Remote Notification
entitlement
In your Xcode project, go to Signing & Capabilities
and enable the Remote Notification
capability in the Background Modes
section.
Update your push notification payload
Update your push notification payload of your push notification provider to include the following details:
{
"aps": {
"alert": {
},
"content-available": 1
},
"ctx_title": "Daily Reminder",
"ctx_body": "Get back to learning, {{ customer.email }} 4",
"ctx_flow_name": "daily_reminder",
"ctx_collapse_id": "{{ 'now' | date: "%B %-d, %Y" }}",
"ctx_notification_deadline_h": 12
}
Explanation of the fields:
ctx_title
&ctx_body
: The title and body of the notification. This isn't used by ContextSDK directly, but is used by you in thedidReceiveRemoteNotification
method to create theUNMutableNotificationContent
. You can add any other fields you need to create your notification (e.g. attachments, sound, etc.)ctx_flow_name
: The name of the flow (e.g.daily_reminder
) describing what type of notification this is. You will get a custom model for eachctx_flow_name
you use in your appctx_collapse_id
: The collapse ID of the notification, which is used to only show a single notification perctx_collapse_id
at the perfect time. For a daily reminder you'd change this every day, for re-engagement campaigns you may change this every time you change your content.ctx_notification_deadline_h
: The time span in which the notification should be shown in hours. The latest time the notification will be shown isctx_notification_deadline_h
hours after the first background push notification was received on the users device. Keep in mind that this still doesn't guarantee the user will see the notification.
For example, if you want to leverage context-aware push notifications for your daily reminders, you should use the current date as the ctx_collapse_id
and the ctx_flow_name
to daily_reminder
. If your logic is to show the notification anytime between 9am to 9pm, you'd set ctx_notification_deadline_h
to 12 and start sending the notifications hourly at 9am.
Things to consider
- The message will be delayed by around 5 seconds, due to the app detecting the real-world context
- Due to the nature of iOS push notifications, there is no guarantee that your app gets woken up for every notification. We recommend setting a
ctx_last_processed
attribute in your user profile to track the last time a notification was processed. This way, you can fallback to static notifications if the user hasn't opened the app in a while.
Go Live
Now all that's left is to ship your update to the App Store to start calibrating your model