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);
}
@endclass 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];
}
@endclass 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()
}
}