Configure app cards

Prev Next

The App Cards module provides a complete API for accessing and managing the Insider platform's app cards campaigns. It allows you to fetch marketing messages and notifications, track read/unread status, handle interactive buttons within messages, and observe app cards events in real time.

Messages can contain rich content, including text, images, and interactive buttons with deeplink actions.

The InsiderAppCards class cannot be instantiated directly. Access it through the main Insider SDK via appCards / Insider.appCards().

Prerequisites

  • Insider iOS SDK (InsiderMobile), integrated and initialized in your app

  • Minimum iOS deployment target: 11.0

Access

Obtain the InsiderAppCards instance from the main SDK:

InsiderAppCards *appCards = [Insider appCards];
let appCards = Insider.appCards()

API Reference

Core Types

InsiderAppCardCampaignsResponseModel

Root container for app cards data.

Name

Type

Description

Required

appCards

[InsiderAppCardModel]

Array of all app cards in the campaigns

Yes

InsiderAppCardModel

Represents a single app card.

Name

Type

Description

Required

appCardId

String

Yes

Unique identifier for the app card

type

InsiderAppCardType

Yes

Type of the app card (.message or .image)

isRead

Bool

Yes

Whether the app card has been read

content

InsiderAppCardContentModel?

No

Text content (title and subtitle)

images

[InsiderAppCardImageModel]?

No

Array of images associated with the app card

buttons

[InsiderAppCardButtonModel]?

No

Array of action buttons

deeplink

InsiderAppCardDeeplinkActionModel?

No

Deeplink action for app card tap

App card types

Constant

Description

InsiderAppCardTypeMessage

Text-based message

InsiderAppCardTypeImage

Image-based message

InsiderAppCardContentModel

Textual content of an app card.

Name

Type

Description

Required

title

String

Main title text

Yes

subtitle

String

Subtitle or description text

Yes

InsiderAppCardImageModel

Image associated with an app card.

Name

Type

Description

Required

url

URL

URL of the image

Yes

title

String?

Optional title for the image

No

subtitle

String?

Optional subtitle or caption

No

InsiderAppCardButtonModel

An interactive button within an app card.

Name

Type

Description

Required

buttonId

String

Unique identifier for the button

Yes

appCardId

String

Unique identifier of the parent app card

Yes

text

String

Display text shown on the button

Yes

action

InsiderAppCardActionModel?

Action executed when the button is tapped

No

InsiderAppCardActionModel (Protocol)

Protocol defining the interface for app card actions.

Name

Type

Description

Required

type

InsiderAppCardActionType

Type of the action

Yes

Action types

Constant

Description

InsiderAppCardActionTypeDeeplink

Deeplink navigation

InsiderAppCardActionTypeAppReview

Prompt app store review

InsiderAppCardActionTypeAppSettings

Open app settings

InsiderAppCardDeeplinkActionModel

Deeplink action that navigates to a specific location.

Name

Type

Description

Required

JSONObject

[String: Any]?

JSON object containing deeplink data

No

keysAndValues

[[String: Any]]?

Array of key-value dictionaries for deeplink data

No

Deeplink URL types

Constant

Description

InsiderAppCardDeeplinkURLTypeExternal

External browser URL

InsiderAppCardDeeplinkURLTypeInternal

Internal webview URL

InsiderAppCardDeeplinkURLTypeCustomScheme

Custom URL scheme

InsiderAppCardDeeplinkURLTypeUnknown

Unknown or invalid URL

InsiderAppCardsObserver (Protocol)

Observer protocol for receiving app cards events. All methods are optional.

Method

Parameters

Description

appCardsDidMarkAsRead

Set<String>

Called when app cards are marked as read

appCardsDidMarkAsUnread

Set<String>

Called when app cards are marked as unread

appCardsDidDeleteAppCards

Set<String>

Called when app cards are deleted

appCardsDidViewAppCardWithId

String

Called when an app card is viewed

appCardsDidClickAppCardWithId

String

Called when an app card is clicked

appCardsDidClickButtonWithId:inAppCardWithId

String, String

Called when a button in an app card is clicked

Campaigns Management

getCampaigns

Retrieves the user's app cards campaigns with all available messages.

Name

Type

Description

Required

completion

(InsiderAppCardCampaignsResponseModel, Error?) -> Void

Completion handler with campaigns model and optional error

Yes

The completion handler is called on the main thread. Any in-flight campaigns requests are cancelled when this method is called.

InsiderAppCards *appCards = [Insider appCards];

[appCards getCampaigns:^(InsiderAppCardCampaignsResponseModel *campaigns, NSError *error) {
    if (error) {
        NSLog(@"Failed to fetch campaigns: %@", error.localizedDescription);
        return;
    }

    for (InsiderAppCardModel *appCard in campaigns.appCards) {
        NSLog(@"App Card ID: %@, Read: %d", appCard.appCardId, appCard.isRead);
    }
}];
let appCards = Insider.appCards()

appCards.getCampaigns { campaigns, error in
    if let error = error {
        print("Failed to fetch campaigns: \(error.localizedDescription)")
        return
    }

    for appCard in campaigns.appCards {
        print("App Card ID: \(appCard.appCardId), Read: \(appCard.isRead)")
    }
}

markAsRead

Marks specified app cards as read. Synchronizes with the Insider backend.

Name

Type

Description

Required

appCardIds

Set<String>

Set of app card identifiers to mark as read

Yes

completion

(Error?) -> Void

Completion handler with optional error

Yes

InsiderAppCards *appCards = [Insider appCards];

NSSet *ids = [NSSet setWithArray:@[@"card_123", @"card_456"]];
[appCards markAsRead:ids completion:^(NSError *error) {
    if (error) {
        NSLog(@"Failed: %@", error.localizedDescription);
    } else {
        NSLog(@"App cards marked as read");
    }
}];
let appCards = Insider.appCards()

appCards.markAsRead(appCardIds: ["card_123", "card_456"]) { error in
    if let error = error {
        print("Failed: \(error.localizedDescription)")
    } else {
        print("App cards marked as read")
    }
}

markAsUnread

Marks specified app cards as unread. Synchronizes with the Insider backend.

Name

Type

Description

Required

appCardIds

Set<String>

Set of app card identifiers to mark as unread

Yes

completion

(Error?) -> Void

Completion handler with optional error

Yes

InsiderAppCards *appCards = [Insider appCards];

NSSet *ids = [NSSet setWithArray:@[@"card_123"]];
[appCards markAsUnread:ids completion:^(NSError *error) {
    if (error) {
        NSLog(@"Failed: %@", error.localizedDescription);
    } else {
        NSLog(@"App cards marked as unread");
    }
}];
let appCards = Insider.appCards()

appCards.markAsUnread(appCardIds: ["card_123"]) { error in
    if let error = error {
        print("Failed: \(error.localizedDescription)")
    } else {
        print("App cards marked as unread")
    }
}

deleteAppCards

Permanently deletes specified app cards. Synchronizes with the Insider backend.

Name

Type

Description

Required

appCardIds

Set<String>

Set of app card identifiers to delete

Yes

completion

(Error?) -> Void

Completion handler with optional error

Yes

InsiderAppCards *appCards = [Insider appCards];

NSSet *ids = [NSSet setWithArray:@[@"card_123", @"card_456"]];
[appCards deleteAppCards:ids completion:^(NSError *error) {
    if (error) {
        NSLog(@"Failed: %@", error.localizedDescription);
    } else {
        NSLog(@"App cards deleted successfully");
    }
}];
let appCards = Insider.appCards()

appCards.delete(appCardIds: ["card_123", "card_456"]) { error in
    if let error = error {
        print("Failed: \(error.localizedDescription)")
    } else {
        print("App cards deleted successfully")
    }
}

App Card Interaction

viewAppCard

Records a view event for an app card. Call this when a user views an app card in the UI.

Name

Type

Description

Required

appCard

InsiderAppCardModel

The app card model that was viewed

Yes

InsiderAppCards *appCards = [Insider appCards];
[appCards viewAppCard:appCard];
let appCards = Insider.appCards()
appCards.view(appCard: appCard)

You can also call view directly on the app card model: [appCard view] / appCard.view()

clickAppCard

Records a click event for an app card. Executes the app card's deeplink action (if present).

Name

Type

Description

Required

appCard

InsiderAppCardModel

The app card model that was clicked

Yes

InsiderAppCards *appCards = [Insider appCards];
[appCards clickAppCard:appCard];
let appCards = Insider.appCards()
appCards.click(appCard: appCard)

You can also call click directly on the app card model: [appCard click] / appCard.click()

clickAppCardButton

Records a click event for a button within an app card. Executes the button's action (if present).

Name

Type

Description

Required

button

InsiderAppCardButtonModel

The button model that was clicked

Yes

InsiderAppCards *appCards = [Insider appCards];

for (InsiderAppCardButtonModel *button in appCard.buttons) {
    // Handle button tap in your UI
    [appCards clickAppCardButton:button];
}
let appCards = Insider.appCards()

for button in appCard.buttons ?? [] {
    // Handle button tap in your UI
    appCards.click(appCardButton: button)
}

You can also call click directly on the button model: [button click] / button.click()

App Card Model Methods

markAsRead (on app card)

Marks an individual app card as read. For bulk operations, use InsiderAppCards.markAsRead:completion: instead.

[appCard markAsRead:^(NSError *error) {
    if (!error) {
        NSLog(@"App card marked as read");
    }
}];
appCard.markAsRead { error in
    if error == nil {
        print("App card marked as read")
    }
}

markAsUnread (on app card)

Marks an individual app card as unread. For bulk operations, use InsiderAppCards.markAsUnread:completion: instead.

[appCard markAsUnread:^(NSError *error) {
    if (!error) {
        NSLog(@"App card marked as unread");
    }
}];
appCard.markAsUnread { error in
    if error == nil {
        print("App card marked as unread")
    }
}

Deeplink Methods

deeplinkURL

Constructs and returns the deeplink URL from the action model's data.

deeplinkURLType

Returns the type classification of the deeplink URL.

InsiderAppCardDeeplinkActionModel *deeplink = appCard.deeplink;

if (deeplink) {
    NSURL *url = [deeplink deeplinkURL];
    InsiderAppCardDeeplinkURLType urlType = [deeplink deeplinkURLType];

    if ([urlType isEqualToString:InsiderAppCardDeeplinkURLTypeExternal]) {
        [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
    }
}
if let deeplink = appCard.deeplink {
    let url = deeplink.deeplinkURL()
    let urlType = deeplink.deeplinkURLType()

    if urlType == InsiderAppCardDeeplinkURLTypeExternal, let url = url {
        UIApplication.shared.open(url)
    }
}

Error Handling

The InsiderAppCardsError domain provides typed error codes for app cards operations.

Error domain: InsiderAppCardsErrorDomain

Error Code

Value

Description

InsiderAppCardsErrorCodeUnknown

0

Unknown error

InsiderAppCardsErrorCodeSdkNotInitialized

1

SDK is not initialized

InsiderAppCardsErrorCodeInvalidParameter

2

Invalid parameter provided

InsiderAppCardsErrorCodeNetworkError

3

Network request failed

InsiderAppCardsErrorCodeServerError

4

Server returned an error

InsiderAppCardsErrorCodeParseError

5

Response parsing failed

Observer

InsiderAppCards inherits from InsiderObservable, providing a type-safe observer mechanism for reacting to app cards events.

addObserver / removeObserver

Method

Parameter

Description

addObserver

InsiderAppCardsObserver

Registers an observer (weak reference)

removeObserver

InsiderAppCardsObserver

Unregisters a previously added observer

Observer Protocol Methods

All methods in InsiderAppCardsObserver are optional.

@protocol InsiderAppCardsObserver <NSObject>

@optional

- (void)appCardsDidMarkAsRead:(NSSet<NSString *> *)appCardIds;
- (void)appCardsDidMarkAsUnread:(NSSet<NSString *> *)appCardIds;
- (void)appCardsDidDeleteAppCards:(NSSet<NSString *> *)appCardIds;
- (void)appCardsDidViewAppCardWithId:(NSString *)appCardId;
- (void)appCardsDidClickAppCardWithId:(NSString *)appCardId;
- (void)appCardsDidClickButtonWithId:(NSString *)buttonId inAppCardWithId:(NSString *)appCardId;

@end
@objc protocol InsiderAppCardsObserver: NSObjectProtocol {

    @objc optional func appCardsDidMarkAsRead(_ appCardIds: Set<String>)
    @objc optional func appCardsDidMarkAsUnread(_ appCardIds: Set<String>)
    @objc optional func appCardsDidDeleteAppCards(_ appCardIds: Set<String>)
    @objc optional func appCardsDidViewAppCard(withId appCardId: String)
    @objc optional func appCardsDidClickAppCard(withId appCardId: String)
    @objc optional func appCardsDidClickButton(withId buttonId: String, inAppCardWithId appCardId: String)
}

Observer example

@interface MyViewController () <InsiderAppCardsObserver>
@end

@implementation MyViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [[Insider appCards] addObserver:self];
}

- (void)dealloc {
    [[Insider appCards] removeObserver:self];
}

- (void)appCardsDidMarkAsRead:(NSSet<NSString *> *)appCardIds {
    NSLog(@"App cards marked as read: %@", appCardIds);
}

- (void)appCardsDidClickAppCardWithId:(NSString *)appCardId {
    NSLog(@"App card clicked: %@", appCardId);
}

@end
class MyViewController: UIViewController, InsiderAppCardsObserver {

    override func viewDidLoad() {
        super.viewDidLoad()
        Insider.appCards().addObserver(self)
    }

    deinit {
        Insider.appCards().removeObserver(self)
    }

    func appCardsDidMarkAsRead(_ appCardIds: Set<String>) {
        print("App cards marked as read: \(appCardIds)")
    }

    func appCardsDidClickAppCard(withId appCardId: String) {
        print("App card clicked: \(appCardId)")
    }
}

A complete example

A complete example showing how to fetch, display, and interact with app cards.

@interface AppCardsViewController () <InsiderAppCardsObserver>

@property (nonatomic, strong) InsiderAppCards *appCards;
@property (nonatomic, strong) NSArray<InsiderAppCardModel *> *cards;

@end

@implementation AppCardsViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.appCards = [Insider appCards];
    [self.appCards addObserver:self];
    [self fetchCampaigns];
}

- (void)dealloc {
    [self.appCards removeObserver:self];
}

- (void)fetchCampaigns {
    [self.appCards getCampaigns:^(InsiderAppCardCampaignsResponseModel *campaigns, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error.localizedDescription);
            return;
        }

        self.cards = campaigns.appCards;
        [self.tableView reloadData];
    }];
}

- (void)didSelectAppCard:(InsiderAppCardModel *)appCard {
    // Track view
    [self.appCards viewAppCard:appCard];

    // Mark as read
    [appCard markAsRead:^(NSError *error) {
        if (!error) {
            [self.tableView reloadData];
        }
    }];

    // Handle deeplink if present
    if (appCard.deeplink) {
        NSURL *url = [appCard.deeplink deeplinkURL];
        if (url) {
            [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
        }
    }
}

- (void)didTapButton:(InsiderAppCardButtonModel *)button {
    [self.appCards clickAppCardButton:button];
}

- (void)deleteAppCard:(InsiderAppCardModel *)appCard {
    NSSet *ids = [NSSet setWithObject:appCard.appCardId];
    [self.appCards deleteAppCards:ids completion:^(NSError *error) {
        if (!error) {
            [self fetchCampaigns];
        }
    }];
}

#pragma mark - InsiderAppCardsObserver

- (void)appCardsDidMarkAsRead:(NSSet<NSString *> *)appCardIds {
    [self.tableView reloadData];
}

- (void)appCardsDidDeleteAppCards:(NSSet<NSString *> *)appCardIds {
    [self.tableView reloadData];
}

@end
class AppCardsViewController: UIViewController, InsiderAppCardsObserver {

    private let appCards = Insider.appCards()
    private var cards: [InsiderAppCardModel] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        appCards.addObserver(self)
        fetchCampaigns()
    }

    deinit {
        appCards.removeObserver(self)
    }

    private func fetchCampaigns() {
        appCards.getCampaigns { campaigns, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            self.cards = campaigns.appCards
            self.tableView.reloadData()
        }
    }

    func didSelectAppCard(_ appCard: InsiderAppCardModel) {
        // Track view
        appCards.view(appCard: appCard)

        // Mark as read
        appCard.markAsRead { error in
            if error == nil {
                self.tableView.reloadData()
            }
        }

        // Handle deeplink if present
        if let deeplink = appCard.deeplink, let url = deeplink.deeplinkURL() {
            UIApplication.shared.open(url)
        }
    }

    func didTapButton(_ button: InsiderAppCardButtonModel) {
        appCards.click(appCardButton: button)
    }

    func deleteAppCard(_ appCard: InsiderAppCardModel) {
        appCards.delete(appCardIds: [appCard.appCardId]) { error in
            if error == nil {
                self.fetchCampaigns()
            }
        }
    }

    // MARK: - InsiderAppCardsObserver

    func appCardsDidMarkAsRead(_ appCardIds: Set<String>) {
        tableView.reloadData()
    }

    func appCardsDidDeleteAppCards(_ appCardIds: Set<String>) {
        tableView.reloadData()
    }
}