iOS In App Notification

Learn how to implement, control, and customize In-App Notifications in CleverTap iOS SDK.

Overview

The CleverTap iOS SDK allows you to show In-App notifications to your users, and it provides the capability to send In-App messages with images, GIFs, video, and audio. You can design In-App notifications directly from the dashboard, without writing a single line of code. You can also run A/B tests on your In-Apps.

📘

Platform Limitation

In-App Notifications are not supported inside App Extensions, tvOS and watchOS apps.

In-App Notification Callbacks

You can track user interactions with In-App Notifications using delegate methods provided by the CleverTap iOS SDK.
These callbacks notify your app when a user views, dismisses, or taps an In-App Notification.

To use callbacks, implement the CleverTapInAppNotificationDelegate protocol in your class and define the following methods:

Implementing these callbacks allows you to control when notifications appear and capture user interactions for analytics or personalization.

shouldShowInAppNotificationWithExtras Callback

This callback is triggered before an In-App Notification is displayed. Use it to decide whether a notification should be shown.

Return false to suppress a notification if specific app conditions are not met (for example, if the user is already on the target screen).

// Called before an In-App Notification is displayed.
// Return false to prevent rendering the notification.
func shouldShowInAppNotification(withExtras extras: [AnyHashable : Any]!) -> Bool {
    if let screen = extras["screen"] as? String, screen == "home" {
        return false
    }
    return true
}
// Called before an In-App Notification is displayed.
// Return NO to prevent rendering the notification.
- (BOOL)shouldShowInAppNotificationWithExtras:(NSDictionary *)extras {
    NSString *screen = extras[@"screen"];
    if ([screen isEqualToString:@"home"]) {
        return NO;
    }
    return YES;
}

inAppNotificationDidShow Callback

This callback is triggered after an In-App Notification is displayed to the user. Use this callback to log impression data or trigger custom analytics events.

// Called when an In-App Notification is displayed.
func inAppNotificationDidShow(_ notification: [AnyHashable : Any]!) {
    print("In-App Notification displayed:", notification ?? [:])
}
// Called when an In-App Notification is displayed.
- (void)inAppNotificationDidShow:(NSDictionary *)notification {
    NSLog(@"In-App Notification displayed: %@", notification);
}

inAppNotificationDismissedWithExtras Callback

This callback is triggered after a notification is dismissed by the user or automatically after a timeout. Use this callback to perform cleanup tasks or record dismissal events.

// Called when an In-App Notification is dismissed.
func inAppNotificationDismissed(
    withExtras extras: [AnyHashable : Any]!,
    andActionExtras actionExtras: [AnyHashable : Any]!
) {
    print("Notification dismissed with extras:", extras ?? [:])
    print("Action extras:", actionExtras ?? [:])
}
// Called when an In-App Notification is dismissed.
- (void)inAppNotificationDismissedWithExtras:(NSDictionary *)extras
                               andActionExtras:(NSDictionary *)actionExtras {
    NSLog(@"Notification dismissed with extras: %@", extras);
    NSLog(@"Action extras: %@", actionExtras);
}

inAppNotificationButtonTappedWithCustomExtras Callback

Available from iOS SDK v3.7.1 and above, this callback is triggered when a user taps a button within an In-App Notification. It provides a dictionary of key-value pairs that you can use to handle button actions or custom payloads.

// Called when a user taps a button in an In-App Notification.
func inAppNotificationButtonTapped(withCustomExtras customExtras: [AnyHashable : Any]!) {
    print("Button tapped with custom extras:", customExtras ?? [:])
}
// Called when a user taps a button in an In-App Notification.
- (void)inAppNotificationButtonTappedWithCustomExtras:(NSDictionary *)customExtras {
    NSLog(@"Button tapped with custom extras: %@", customExtras);
}

Example: Implementing the Delegate

The following examples show how to set and implement the CleverTap In-App Notification delegate in your app.

import UIKit
import CleverTapSDK

class MyViewController: UIViewController, CleverTapInAppNotificationDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Register the delegate
        CleverTap.sharedInstance()?.setInAppNotificationDelegate(self)
    }

    func shouldShowInAppNotification(withExtras extras: [AnyHashable : Any]!) -> Bool {
        return true
    }

    func inAppNotificationDidShow(_ notification: [AnyHashable : Any]!) {
        print("Notification displayed:", notification ?? [:])
    }

    func inAppNotificationButtonTapped(withCustomExtras customExtras: [AnyHashable : Any]!) {
        print("Button tapped with extras:", customExtras ?? [:])
    }
}
#import "MyViewController.h"
#import <CleverTapSDK/CleverTap.h>

@interface MyViewController () <CleverTapInAppNotificationDelegate>
@end

@implementation MyViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Register the delegate
    [[CleverTap sharedInstance] setInAppNotificationDelegate:self];
}

- (BOOL)shouldShowInAppNotificationWithExtras:(NSDictionary *)extras {
    return YES;
}

- (void)inAppNotificationDidShow:(NSDictionary *)notification {
    NSLog(@"Notification displayed: %@", notification);
}

- (void)inAppNotificationButtonTappedWithCustomExtras:(NSDictionary *)customExtras {
    NSLog(@"Button tapped with extras: %@", customExtras);
}

@end

❗️

Warning

Always register the delegate before an In-App Notification is triggered. Otherwise, callbacks may not be received.

Troubleshooting

IssuePossible CauseSuggested Fix
Callback not triggeredDelegate not registeredEnsure setInAppNotificationDelegate(self) is called in viewDidLoad() or earlier.
Empty extras dictionaryNo key–value pairs configuredAdd custom key–value pairs when creating the campaign in the dashboard.
Button tap not detectedUsing an older SDK versionUpgrade to iOS SDK v3.7.1 or higher.

Control In-App Notifications

For CleverTap iOS SDK 3.10.0 and above, you can suspend, discard, or resume in-app notifications.

📘

Note

The CleverTap SDK automatically resumes displaying the in-app notification after every new session.

You can control the in-app notifications in the following ways:

Suspend

The suspendInAppNotifications method suspends and saves in-app notifications until the resumeInAppNotifications method is called for the current session.

CleverTap.sharedInstance()?.suspendInAppNotifications()
#import <CleverTapSDK/CleverTap+InAppNotifications.h>
[[CleverTap sharedInstance] suspendInAppNotifications];

Discard

The discardInAppNotifications method discards in-app notifications until the resumeInAppNotifications method is called for the current session.

CleverTap.sharedInstance()?.discardInAppNotifications()
#import <CleverTapSDK/CleverTap+InAppNotifications.h>
[[CleverTap sharedInstance] discardInAppNotifications];

Resume

The resumeInAppNotifications method resumes displaying in-app notifications.
If you call this method after the discardInAppNotifications() method, it resumes the in-app notifications for events raised after the call is performed.

However, if you call the resumeInAppNotifications method after the suspendInAppNotifications() method, then it displays all queued in-app notifications and also resumes in-app notifications for events raised after the call is performed.

CleverTap.sharedInstance()?.resumeInAppNotifications()
#import <CleverTapSDK/CleverTap+InAppNotifications.h>
[[CleverTap sharedInstance] resumeInAppNotifications];

📘

Note

The showInAppNotificationIfAny method will be deprecated soon. Use the resumeInAppNotifications method to manually display the pending in-app notifications.

Custom Handling Deeplink

For CleverTap iOS SDK 3.10.0 and above, you can implement custom handling for URLs of in-app notification CTAs, push notifications, and app Inbox messages.

Check that your class conforms to the CleverTapURLDelegate protocol by first calling setURLDelegate. Use the following protocol method shouldHandleCleverTap(_ : forChannel:) to handle URLs received from channels such as in-app notification CTAs, push notifications, and app Inbox messages:

// Set the URL Delegate
CleverTap.sharedInstance()?.setUrlDelegate(self)


 // CleverTapURLDelegate method
public func shouldHandleCleverTap(_ url: URL?, for channel: CleverTapChannel) -> Bool {  
    print("Handling URL: \(url!) for channel: \(channel)") 
    return true 
}
#import <CleverTapSDK/CleverTapURLDelegate.h>

// Set the URL Delegate
[[CleverTap sharedInstance]setUrlDelegate:self];

// CleverTapURLDelegate method 
- (BOOL)shouldHandleCleverTapURL:(NSURL *)url forChannel:(CleverTapChannel)channel {
    NSLog(@"Handling URL: \(%@) for channel: \(%d)", url, channel);
    return YES;
}

Javascript support in In-App Notifications

CleverTap iOS SDK v3.5.0 and above supports embedding Javascript code inside Custom In-Apps. To make sure your Javascript code works on the app, while creating the InApp campaign, select the checkbox for Enabling javascript during the In-App campaign creation

2870

Custom HTML Templates in In-App Notification

Include JavaScript in In-App Notifications

Include JavaScript in In-App Notifications

All methods are explained with examples below:

//Recording a User Event called Product Viewed with properties, in JS enabled custom In-Apps
var props = {foo: 'xyz', lang: 'French'};
var message = { action:'recordEventWithProps', event:'Product Viewed', properties: props};
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Updating profile properties of the User in JS enabled custom In-Apps
const props = { name: 'John', email: '[email protected]' , score: 0};
const message = { action:'profilePush', properties: props };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Adding user property for the User in JS enabled custom In-Apps
const message = { action: 'profileAddMultiValue', value: 'coat', key: 'myStuff' };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Adding multiple user properties for the User in JS enabled custom In-Apps
const message = { action: 'profileAddMultiValues', values: ['bag', 'kitkat'], key: 'myStuff' };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Removing a unique value from a multi-value profile in JS enabled custom In-Apps
const message = { action: 'profileRemoveMultiValue', value:'scarf', key: 'myStuff' };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Removing multiple unique values from a multi-value profile in JS enabled custom In-Apps
const message = { action: 'profileRemoveMultiValues', values:['scarf', 'knife'], key: 'myStuff' };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Removing a user property by specifying a key in JS enabled custom In-Apps
const message = { action: 'profileRemoveValueForKey', key: 'myStuff' };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Setting a user property by specifying the key in JS enabled custom In-Apps
const message = { action: 'profileSetMultiValues', values:['scarf', 'knife'], key: 'myStuff' };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

// Increment user property value by specifying the key in JS enabled custom In-Apps
const message = { action: 'profileIncrementValueBy', value: 1, key: 'score' };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

// Decrement user property value by specifying the key in JS enabled custom In-Apps
const message = { action: 'profileDecrementValueBy', value: 1, key: 'score' };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Calling onUserLogin 
const props = { name: 'JohnWeb', email: '[email protected]' };
const message = { action:'onUserLogin', properties: props };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Recording a Charged Event in JS enabled custom In-Apps
const chargeDetails = { "Amount" : 300, "Payment mode": "Credit Card", "Charged ID": 24052013 };
const items = [{"Category": "books","Book name": "The Millionaire next door","Quantity": 1}, 
               {"Category": "books","Book name": "The Millionaire previous door","Quantity": 5}];
const message = { action:'recordChargedEvent', chargeDetails: chargeDetails, items: items };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

//Prompt for push permission
const message = { action:'promptForPushPermission', showFallbackSettings:true };
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {
  window.webkit.messageHandlers.clevertap.postMessage(message);
}

📘

Inline Media

To add inline media support in custom HTML for in-app notifications, add the key playsinline with value as 1 or true as a query parameter in your media URL. For example, watch this YouTube video. This functionality is available for CleverTap iOS SDK 3.7.2 and above.

Dismissing JS-Enabled Custom In-App Notifications

If your In-App Notification supports JavaScript, you can dismiss it by calling the JS method when you set the action dismissInAppNotification in the CleverTap dashboard. Use the following code:

// Dismissing JS-enabled custom In-Apps
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.clevertap) {  
    var message = { action: 'dismissInAppNotification' };  
    window.webkit.messageHandlers.clevertap.postMessage(message);  
}

System In-App Functions

The CleverTap iOS SDK (v7.2.0 and above) supports a set of built-in system in-app functions. These can be triggered either via in-app notification button actions or launched as stand-alone campaigns. For more information about the implementation flows, refer to CleverTap Github Repository. For more information about using the App Functions from the dashboard, refer to App Functions.

Open URL

The Open URL function opens a specific URL or deep link on iOS, configured via the CleverTap Dashboard when using a stand-alone in-app template. It is typically used to redirect users to destinations such as product pages, help centers, or feedback forms, seamlessly within the app experience. When a valid URL is launched, the system automatically raises the Notification Viewed event.

Push Permission

The Push Permission function triggers the iOS system prompt to request notification permissions. It can be launched as a stand-alone campaign or invoked via an in-app notification button. This function is ideal for prompting users at relevant moments, such as after a key engagement, rather than during app launch.

App Rating

The App Rating function invokes the native iOS app rating prompt. It helps gather user feedback within the app experience by prompting users at contextually relevant moments, such as after a successful transaction or a positive interaction. When displayed, it automatically records the Notification Viewed event to measure user engagement with the prompt.

📘

Apple Rating Prompt Limits

Apple limits rating prompts to three per user per year. Avoid prompting immediately on app launch.
For more information, refer to Apple’s App Review documentation.


//kapa search bot