The App Cards module provides a complete API for accessing and managing Insider One’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.
This documentation covers the App Cards API (Insider.appCards) and the current architecture. The legacy Insider.getMessageCenterData(...) method is a separate, older interface for retrieving push notification payloads as a notification center. If you are building a new integration, use the App Cards API.
The InsiderAppCards instance cannot be constructed directly. Access it through the main Insider plugin: Insider.appCards.
Prerequisites
cordova-plugin-insider 4.0.1 or later
Cordova 7.0.0 or later, cordova-android 6.3.0 or later, cordova-ios 4.3.0 or later (per plugin.xml)
Plugin is available after the Cordova deviceready event fires. Call window.Insider.init(...) on deviceready before accessing App Cards.
Access
The plugin is clobbered onto the global Insider object by Cordova, so Insider.appCards is directly reachable from anywhere in your JavaScript once the plugin is ready:
const appCards = Insider.appCards;Insider.appCards is a frozen namespace object and is always safe to reference after deviceready. The native SDK itself (Android/iOS) returns a no-op instance when it is not initialized or is frozen (e.g., after GDPR consent is revoked). In that state, every asynchronous call resolves with an InsiderAppCardsError whose code is SDK_NOT_INITIALIZED (the native bridge maps AppCardsException.SDK_NOT_INITIALIZED / InsiderAppCardsErrorCodeSdkNotInitialized to the string "sdkNotInitialized"), and every void method (view, click, clickButton) silently returns.
Error handling
App Cards operations can fail with a typed InsiderAppCardsError. In callback form, the error is delivered as the first argument; in Promise form, it is thrown by await.
InsiderAppCardsError
Extends the standard Error class with a structured code that maps to native SDK error codes on both Android and iOS. The class is exposed on the plugin as Insider.AppCardsError.
Name | Type | Required | Description |
|---|---|---|---|
name | 'InsiderAppCardsError' | Yes | Always 'InsiderAppCardsError' |
code | InsiderAppCardsErrorCodeType | Yes | Error code identifying the type of error |
message | string | Yes | A human-readable error description |
Static methods:
Name | Signature | Description |
|---|---|---|
from | (error: { code: string; message: string } | string | unknown) => InsiderAppCardsError | Normalizes a native bridge error into a typed InsiderAppCardsError |
InsiderAppCardsErrorCode
Exposed on the plugin as Insider.AppCardsErrorCode.
Constant | Value | Description |
|---|---|---|
UNKNOWN | "unknown" | An unknown or unexpected error occurred. |
SDK_NOT_INITIALIZED | "sdkNotInitialized" | The Insider SDK is not initialized, frozen, or not GDPR compliant. |
INVALID_PARAMETER | "invalidParameter" | An invalid parameter was provided (e.g., empty or non-string IDs). |
NETWORK_ERROR | "networkError" | A network error occurred during the request. |
SERVER_ERROR | "serverError" | The server returned an error response. |
PARSE_ERROR | "parseError" | The server response could not be parsed. |
Method example:
try {
const response = await window.Insider.appCards.getCampaigns();
console.log("Campaigns:", response.appCards.length);
} catch (error) {
if (error instanceof Insider.AppCardsError) {
switch (error.code) {
case Insider.AppCardsErrorCode.NETWORK_ERROR:
console.warn("Network issue, please try again");
break;
case Insider.AppCardsErrorCode.SDK_NOT_INITIALIZED:
console.warn("SDK not ready");
break;
default:
console.warn(
"App Cards error:",
error.code,
error.message
);
break;
}
}
}Core types
InsiderAppCardsCampaignResponse
Root container returned from getCampaigns. Holds the full list of app cards retrieved for the current user.
Name | Type | Required | Description |
|---|---|---|---|
appCards | InsiderAppCard[] | Yes | Array of all app cards in the campaigns |
InsiderAppCard
Represents a single app card. Contains all data for the card: content, images, buttons, and associated action.
Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier for the app card |
type | InsiderAppCardType | Yes | Type of the app card ("message" or "image") |
isRead | boolean | Yes | Whether the app card has been read by the user |
content | InsiderAppCardContent | No | Text content (title and description) |
images | InsiderAppCardImage[] | No | Array of images associated with the app card |
buttons | InsiderAppCardButton[] | No | Array of action buttons that can be displayed with the app card |
action | InsiderAppCardAction | No | Action to be executed when the app card is tapped |
App Card types:
Constant | Description |
|---|---|
"message" | Text-based app card |
"image" | Image-based app card |
Convenience methods:
Method | Description |
|---|---|
markAsRead(completion) | Marks this single card as read. Also available as a Promise (omit completion). |
markAsUnread(completion) | Marks this single card as unread. Also available as a Promise. |
delete(completion) | Deletes this card permanently. |
click() | Handles a click event (executes action + logs click conversion). |
view() | Handles a view event (logs view conversion). |
InsiderAppCardContent
Textual content of an app card.
Name | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Main title text of the app card |
description | string | Yes | Description text of the app card |
InsiderAppCardImage
Image associated with an app card.
Name | Type | Required | Description |
|---|---|---|---|
url | string | Yes | URL of the image to be displayed |
InsiderAppCardButton
An interactive button within an app card.
Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier for the button |
appCardId | string | Yes | Unique identifier of the parent app card |
text | string | Yes | Display text shown on the button |
action | InsiderAppCardAction | No | Action executed when the button is tapped |
Convenience methods:
Method | Description |
|---|---|
click() | Handles a click event (executes action + logs button click event). |
InsiderAppCardAction (Abstract)
Base type for app card actions. Subtypes represent different actions executed when a user interacts with an app card or a button, such as opening a deeplink, showing feedback, or navigating to system settings.
Name | Type | Required | Description |
|---|---|---|---|
type | InsiderAppCardActionType | Yes | Type of the action |
Action types:
Constant | Description |
|---|---|
"deep_link" | Deeplink navigation |
"feedback" | Feedback action |
"open_settings" | Open system app settings |
The concrete runtime type is one of InsiderAppCardDeeplinkAction | InsiderAppCardFeedbackAction | InsiderAppCardOpenSettingsAction. Check action.type before narrowing to a subtype.
InsiderAppCardDeeplinkAction
Deeplink action that navigates to a specific location in the app or to an external URL. Extends InsiderAppCardAction with type === 'deep_link'.
Name | Type | Required | Description |
|---|---|---|---|
url | string | null | No | The resolved deeplink URL (URL scheme > internal browser > external browser). Returns null when none is configured. |
deeplinkType | InsiderAppCardDeeplinkType | Yes | Identifies which URL family was resolved. |
json | any | null | No | Parsed JSON payload attached to the deeplink, or null if no JSON was supplied |
keysAndValues | { key: string; value: string }[] | No | Array of key-value pairs defining additional deeplink parameters |
Deeplink types:
Constant | Description |
|---|---|
"url_scheme" | Custom URL scheme (e.g., myapp://...) |
"internal" | Internal webview URL |
"external" | External browser URL |
"unknown" | Unknown or missing URL |
InsiderAppCardFeedbackAction
Marker type for a feedback action. Extends InsiderAppCardAction with no additional fields; type is always "feedback".
InsiderAppCardOpenSettingsAction
Marker type for opening the app's system settings. Extends InsiderAppCardAction with no additional fields; type is always "open_settings".
InsiderAppCardCategory
Represents a single category assigned to an app card.
Name | Type | Required | Description |
|---|---|---|---|
id | number | Yes | Unique identifier of the category |
name | string | Yes | Category name as entered in the panel, e.g., "promotion" |
Match on name for app logic: It is the human-readable value configured in the panel. id is stable and useful as a key.
InsiderAppCard.categories
Name | Type | Required | Description |
|---|---|---|---|
categories | InsiderAppCardCategory[] | Yes | Categories attached to the card. Always an array. Empty when the card has none. |
Unlike images and buttons, which are undefined when absent, and content, which is null when absent, categories is never undefined or null. It is always safe to iterate directly:
appCard.categories.forEach(category => {
console.log(category.id, category.name);
});
Access categories
Categories arrive on the getCampaigns response on every card. No extra call is needed.
Promise style:
const appCards = Insider.appCards;
try {
const campaignResponse = await appCards.getCampaigns();
campaignResponse.appCards.forEach(appCard => {
const names = appCard.categories.map(category => category.name);
console.log('App Card:', appCard.id, 'Categories:', names.join(', '));
});
} catch (error) {
console.warn('Failed to fetch campaigns:', error.code, error.message);
}
Callback style:
const appCards = Insider.appCards;
appCards.getCampaigns((error, campaignResponse) => {
if (error) {
console.warn('Failed to fetch campaigns:', error.code, error.message);
return;
}
campaignResponse.appCards.forEach(appCard => {
appCard.categories.forEach(category => {
console.log('Category:', category.id, category.name);
});
});
});
Filter cards by category
Show only the cards belonging to a given category. E.g., a "Promotions" tab in an inbox screen.
function cardsInCategory(appCards, categoryName) {
return appCards.filter(appCard =>
appCard.categories.some(category => category.name === categoryName)
);
}
const campaignResponse = await Insider.appCards.getCampaigns();
const promotions = cardsInCategory(campaignResponse.appCards, 'promotion');Group cards by category
Build a sectioned list. A card with multiple categories appears in each of its groups; a card with none is collected under a default bucket.
function groupByCategory(appCards) {
const groups = {};
appCards.forEach(appCard => {
if (appCard.categories.length === 0) {
groups['other'] = groups['other'] || [];
groups['other'].push(appCard);
return;
}
appCard.categories.forEach(category => {
groups[category.name] = groups[category.name] || [];
groups[category.name].push(appCard);
});
});
return groups;
}The plugin ships type definitions for the new model.
import type {
InsiderAppCard,
InsiderAppCardCategory,
} from 'cordova-plugin-insider/types/InsiderAppCard';
function categoryNames(appCard: InsiderAppCard): string[] {
return appCard.categories.map((category: InsiderAppCardCategory) => category.name);
}categories is typed as a non-optional InsiderAppCardCategory[], reflecting the always-an-array guarantee. No null checks or optional chaining is required.
Behavior notes
Case | Behavior |
|---|---|
Card has no categories. | categories is [] |
Categories are missing from the response. | categories is [] |
A single category entry is invalid. | That entry is ignored; the remaining categories are kept, and the card is still returned |
categories is present but not an array. | The whole card is dropped by the native SDK and is not returned in the response |
An invalid category entry never fails the whole getCampaigns call; the entry is dropped and the card is still delivered. This is different from a card whose categories value is not an array at all: such a card is treated as malformed and dropped entirely by the native SDK on both iOS and Android.
Categories are delivered only in the getCampaigns response. markAsRead, markAsUnread, and delete operate on card identifiers and are unaffected.
Category support behaves identically on iOS and Android.
Available Methods
getCampaigns
Method signatures
window.Insider.appCards.getCampaigns(completion);
window.Insider.appCards.getCampaigns(); // returns a PromiseRetrieves the user's app card campaigns. Fetches all available app cards from the Insider platform for the current user. Pending campaign requests are canceled before a new one is initiated.
Name | Type | Required | Description |
|---|---|---|---|
completion | (error?: InsiderAppCardsError, response?: InsiderAppCardsCampaignResponse) => void | Yes | Called with the campaign response or an error. Omit to use the Promise form. |
The method supports both completion-callback and Promise forms. Pass a callback to receive (error, response), or omit it and await the returned Promise.
Method example
try {
const response = await window.Insider.appCards.getCampaigns();
response.appCards.forEach((appCard) => {
console.log('App Card Id:', appCard.id, 'Read:', appCard.isRead);
});
} catch (error) {
if (error instanceof Insider.AppCardsError) {
console.warn(error.code, error.message);
}
}markAsRead
Method signatures
window.Insider.appCards.markAsRead(appCardIds, completion);
window.Insider.appCards.markAsRead(appCardIds); // returns a PromiseMarks specified app cards as read. Updates the read status of one or more app cards to indicate they have been viewed by the user. The operation synchronizes with the Insider backend to persist state across devices.
Name | Type | Required | Description |
|---|---|---|---|
appCardIds | string[] | Yes | A non-empty array of app card identifiers to mark as read |
completion | (error?: InsiderAppCardsError) => void | No | Called with an error if the request fails, otherwise called with no arguments on success. Omit for the Promise form. |
App card IDs that don't exist on the backend are silently ignored. You can also call appCard.markAsRead(completion) directly on an InsiderAppCard instance to mark a single card.
Method example
try {
await window.Insider.appCards.markAsRead(['card_123', 'card_456']);
console.log('App cards marked as read successfully');
} catch (error) {
if (error instanceof Insider.AppCardsError) {
console.warn(error.code, error.message);
}
}markAsUnread
Method signatures
window.Insider.appCards.markAsUnread(appCardIds, completion);
window.Insider.appCards.markAsUnread(appCardIds); // returns a PromiseMarks specified app cards as unread. Updates the read status of one or more app cards to unread. The operation synchronizes with the Insider backend to persist state across devices.
Name | Type | Required | Description |
|---|---|---|---|
appCardIds | string[] | Yes | A non-empty array of app card identifiers to mark as unread |
completion | (error?: InsiderAppCardsError) => void | No | Called with an error if the request fails, otherwise called with no arguments on success. Omit for the Promise form. |
You can also call appCard.markAsUnread(completion) directly on an InsiderAppCard instance to unmark a single card.
Method example
try {
await window.Insider.appCards.markAsUnread(['card_123', 'card_456']);
console.log('App cards marked as unread successfully');
} catch (error) {
if (error instanceof Insider.AppCardsError) {
console.warn(error.code, error.message);
}
}delete
Method signatures
window.Insider.appCards.delete(appCardIds, completion);
window.Insider.appCards.delete(appCardIds); // returns a PromisePermanently removes one or more app cards from the user's campaigns. The operation synchronizes with the Insider backend.
Name | Type | Required | Description |
|---|---|---|---|
appCardIds | string[] | Yes | A non-empty array of app card identifiers to delete |
completion | (error?: InsiderAppCardsError) => void | No | Called with an error if the request fails; otherwise called with no arguments on success. Omit for the Promise form. |
You can also call appCard.delete(completion) directly on an InsiderAppCard instance to delete a single card.
Method example
try {
await window.Insider.appCards.delete(['card_123', 'card_456']);
console.log('App cards deleted successfully');
} catch (error) {
if (error instanceof Insider.AppCardsError) {
console.warn(error.code, error.message);
}
}click
Method signature
window.Insider.appCards.click(appCard)Records a click event for an app card. Call this method when a user clicks or taps on an app card. This executes the app card's deeplink action (if present) and notifies observers.
Name | Type | Required | Description |
|---|---|---|---|
appCard | InsiderAppCard | Yes | The app card that was clicked. Must be an instance returned from getCampaigns. |
You can also call appCard.click() directly on the card instance.
Example
window.Insider.appCards.click(appCard);view
Method signature
window.Insider.appCards.view(appCard)Records a view event for an app card. Call this method when an app card becomes visible to the user. This notifies observers and can be used for analytics tracking.
Name | Type | Required | Description |
|---|---|---|---|
appCard | InsiderAppCard | Yes | The app card that was viewed. Must be an instance returned from getCampaigns |
You can also call appCard.view() directly on the card instance.
Example
window.Insider.appCards.view(appCard);clickButton
Method signature
window.Insider.appCards.clickButton(button)Records a click event for a button within an app card. Call this method when a user clicks or taps on a button in an app card. This executes the button's action (if present) and notifies observers.
Name | Type | Required | Description |
|---|---|---|---|
button | InsiderAppCardButton | Yes | The button that was clicked. Must be an instance obtained from appCard.buttons. |
You can also call button.click() directly on the button instance.
Example
window.Insider.appCards.clickButton(button);Full Integration Example
End-to-end flow: wait for deviceready, initialize the SDK, fetch campaigns, view a card, click a button, branch on action type, and mark unread cards as read — with proper error handling.
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
window.Insider.init('your_partner_name', 'group.com.example.app', (event) => {
// handle Insider notification callbacks here
});
loadAppCards();
}
async function loadAppCards() {
try {
const response = await window.Insider.appCards.getCampaigns();
const cards = response.appCards ?? [];
if (cards.length === 0) return;
const firstCard = cards[0];
window.Insider.appCards.view(firstCard);
const firstButton = firstCard.buttons && firstCard.buttons[0];
if (firstButton) {
window.Insider.appCards.clickButton(firstButton);
handleAction(firstButton.action);
}
const unreadIds = cards
.filter((card) => !card.isRead)
.map((card) => card.id);
if (unreadIds.length > 0) {
await window.Insider.appCards.markAsRead(unreadIds);
}
} catch (error) {
if (error instanceof Insider.AppCardsError) {
switch (error.code) {
case Insider.AppCardsErrorCode.NETWORK_ERROR:
console.warn('Network issue, please try again');
break;
case Insider.AppCardsErrorCode.SDK_NOT_INITIALIZED:
console.warn('SDK not ready');
break;
default:
console.warn('App Cards error:', error.code, error.message);
}
}
}
}
function handleAction(action) {
if (!action) return;
switch (action.type) {
case 'deep_link':
if (action.url) {
// Open the deeplink — use cordova-plugin-inappbrowser for internal URLs,
// window.open for external ones, or a custom URL-scheme handler.
window.open(action.url, '_system');
}
break;
case 'feedback':
// present your feedback UI
break;
case 'open_settings':
// navigate to system settings via your preferred Cordova plugin
break;
}
}