iOS > Advanced

Intercepting notifications

Intercepting the custom payload of an Batch iOS push is straightforward: You just have to keep using the standard application delegate methods, everything will work automatically.

iOS 10

It's recommended to implement the UNUserNotificationCenterDelegate in a class.
It allows you to:

  • Unify local and remote notifications callbacks
  • Get the same callback for all user interactions with a push (open, dismiss and actions), even for a cold start
  • Get notified of notifications received while your app is in the foreground. This allows you to take immediate action or to tell iOS to display the push as if your app was opened in background.

In iOS 10.0, legacy callbacks still work but they are heavily bugged and differ in behaviour from how they used to work. We suggest you migrate to UNUserNotificationCenter as soon as possible. More info here:

You'll also need to call Batch in its two methods to make sure all of the SDK and dashboard's features work correctly.
Keep in mind that being a delegate, it will need to be retained by a variable, since iOS only weakly retains it.

Here's a sample implementation:

// NotificationDelegate.h

@import Foundation;
@import UserNotifications;

@interface NotificationDelegate : NSObject <UNUserNotificationCenterDelegate>


// NotificationDelegate.m
#import "NotificationDelegate.h"

@import Batch;

@implementation NotificationDelegate

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)())completionHandler {
    [your code]
    [BatchPush handleUserNotificationCenter:center

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    [your code]
    [BatchPush handleUserNotificationCenter:center

    // Since you set willShowSystemForegroundAlert to true, you should call completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound)
    // If set to false, you'd call completionHandler(0)

class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        [your code]
        BatchPush.handle(userNotificationCenter: center, didReceive: response)

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        [your code]
        BatchPush.handle(userNotificationCenter: center, willPresent: notification, willShowSystemForegroundAlert: true)

        // Since you set willShowSystemForegroundAlert to true, you should call completionHandler([.alert, .sound, .badge])
        // If set to false, you'd call completionHandler([])

Note: willShowSystemForegroundAlert should reflect the arguments you call the completion handler with. Batch will use that to detect if it should perform foreground actions, or only perform them when the shown alert will be tapped

Finally, set this class as your default UNUserNotificationCenter delegate:

@interface AppDelegate ()
    NotificationDelegate *notificationDelegate;

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    if ([UNUserNotificationCenter class]) {
        notificationDelegate = [NotificationCenterDelegate new];
        [[UNUserNotificationCenter currentNotificationCenter] setDelegate:notificationDelegate];

class AppDelegate: UIResponder, UIApplicationDelegate {
    let notificationDelegate = NotificationDelegate()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        if #available(iOS 10, *) {
            UNUserNotificationCenter.current().delegate = notificationDelegate

iOS 9 and lower

If your app supports background refresh, it's recommended to implement this method:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
       func application(application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
       fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void)

Don't forget to call the completionHandler with an appropriate value. Batch will only do so for you when it encounters a deeplink.

Otherwise, if you support iOS 6 devices or don't implement background refresh, please implement the older notification delegate method. Note that both can be implemented for retrocompatbility, you'll only be called on one of them.

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])

Your custom payload will be in the userInfo dictionary.

You'll notice the presence of a com.batch key in the userInfo dictionary. This is Batch's internal payload: it is subject to change so you should not rely on parsing it for any of your features.

Overriding Batch's Deeplink Handling

By default, Batch will automatically try to open the deeplink you've set in your push campaigns.

If you'd like to prevent Batch from doing that while still being able to use deeplinks in push campaigns, you can call the following method in applicationDidFinishLaunchingWithOptions:

[BatchPush enableAutomaticDeeplinkHandling:NO];

Then, you can ask Batch to give you the deeplink from the notification when you get it:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    NSString *deeplink = [BatchPush deeplinkFromUserInfo:userInfo];
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
    let deeplink = BatchPush.deeplink(fromUserInfo: userInfo)

Be careful, this method will return nil if a deeplink could not be found.