Skip to main content

Documentation Index

Fetch the complete documentation index at: https://cometchat-22654f5b-eng-35741-widget-builder.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

CometChat Campaigns lets you deliver targeted, rich notifications to users via an in-app notification feed. Each notification is a Card Schema JSON — a structured layout rendered natively by the CometChat Cards library. The SDK provides APIs to fetch feed items, listen for real-time delivery, mark items as read/delivered, report engagement, and retrieve unread counts.
Before using the SDK, set up your channels, categories, templates, and campaigns in the CometChat Dashboard. See the Dashboard Setup Guide for step-by-step instructions.

CometChatCardsSwift

CometChatCardsSwift is the rendering library for Campaigns. The NotificationFeedItem.content field contains a Card Schema JSON — a structured layout definition. CometChatCardsSwift takes this JSON and produces a native UIKit view. Without it, content is just a raw dictionary. The library:
  • Parses the JSON schema into typed Swift models.
  • Renders native UIKit views (no web views) for each element (text, images, buttons, rows, etc.).
  • Handles light/dark mode color resolution from themed color pairs.
  • Manages interactive actions — button taps emit structured CometChatCardActionEvent objects with the action type and element ID.
  • Supports dynamic content — accordions expand/collapse, tabs switch panels, all with proper auto-layout height changes.
If you use CometChatNotificationFeed (UI Kit), the Cards library is used internally and you don’t interact with it directly. If you’re building a custom feed UI, you import CometChatCardsSwift and use CometChatCardView to render each item’s content.

Setting Up CometChatCardsSwift

Installation

Swift Package Manager In Xcode: File → Add Package Dependencies → enter:
https://github.com/cometchat/cometchat-cards-sdk-ios
Add CometChatCardsSwift to your target. CocoaPods
pod 'CometChatCardsSwift'
pod install
No initialization is required. The library is stateless — import it and start rendering.

Rendering Feed Items as Cards

import CometChatSDK
import CometChatCardsSwift

// After fetching items via NotificationFeedRequest
request.fetchNext(onSuccess: { items in
    for item in items {
        guard let jsonData = try? JSONSerialization.data(withJSONObject: item.content),
              let jsonString = String(data: jsonData, encoding: .utf8) else { continue }

        let cardView = CometChatCardView(frame: .zero)
        cardView.translatesAutoresizingMaskIntoConstraints = false
        cardView.themeMode = .auto
        cardView.cardJson = jsonString

        cardView.actionCallback = { actionEvent in
            // Report engagement on every action
            CometChat.reportFeedEngagement(item, interactionString: actionEvent.elementId, onSuccess: {}, onError: { _ in })

            switch actionEvent.action {
            case .openUrl(let url, _):
                if let link = URL(string: url) {
                    UIApplication.shared.open(link)
                }
            case .chatWithUser(let uid):
                // Navigate to 1-on-1 chat
                break
            case .chatWithGroup(let guid):
                // Navigate to group chat
                break
            default:
                break
            }
        }

        container.addSubview(cardView)
    }
}, onError: { error in
    print("Error: \(error?.errorDescription ?? "")")
})

CometChatCardView Properties

PropertyTypeDescription
cardJsonString?Set this to render a card. Triggers a full re-render.
themeModeCometChatCardThemeMode.auto (follows system), .light, or .dark.
actionCallback((CometChatCardActionEvent) -> Void)?Called when user taps a button, link, or icon button inside the card.
themeOverrideCometChatCardThemeOverride?Override default theme colors without modifying card JSON.

Theme Override

Override default card theme colors to match your app’s brand:
var override = CometChatCardThemeOverride()
override.textColor = CometChatCardColorValue(light: "#1A1A1A", dark: "#F0F0F0")
override.buttonFilledBg = CometChatCardColorValue(light: "#6852D6", dark: "#8B7AE8")
override.buttonFilledText = CometChatCardColorValue(light: "#FFFFFF", dark: "#FFFFFF")
override.fontFamily = "Avenir"

cardView.themeOverride = override

Content Size Changes

Cards with expandable content (accordions, tabs) change height dynamically. Observe size changes to update your layout:
NotificationCenter.default.addObserver(
    forName: CometChatCardView.contentSizeDidChangeNotification,
    object: cardView,
    queue: .main
) { _ in
    tableView.beginUpdates()
    tableView.endUpdates()
}

Key Concepts

ConceptDescription
NotificationFeedItemA single notification in the feed. Contains Card Schema JSON in its content field, a category for filtering, timestamps, and metadata.
NotificationCategoryA category label used for filter chips (e.g., “Promotions”, “Updates”).
Card Schema JSONThe fully rendered card layout (images, text, buttons) inside NotificationFeedItem.content. Passed directly to the CometChat Cards renderer.
PushNotificationRepresents a campaign push notification payload received via APNs.

How Cards Render in the Notification Feed

Each NotificationFeedItem has a content field containing a [String: Any] dictionary — this is the Card Schema JSON. This JSON is passed directly to the CometChat Cards renderer library. The rendering flow:
  1. Fetch feed items via NotificationFeedRequest
  2. For each item, extract item.content — this is the Card Schema JSON
  3. Pass to the Cards renderer (CometChatCardView)
  4. The renderer produces a native UIKit view from the JSON

Card Schema JSON Structure

{
  "version": "1.0",
  "body": [
    { "type": "image", "id": "img_1", "url": "https://...", "height": 200 },
    { "type": "text", "id": "txt_1", "content": "Flash Sale!", "variant": "heading2" },
    { "type": "button", "id": "btn_1", "label": "Shop Now", "action": { "type": "openUrl", "url": "https://..." } }
  ],
  "style": { "background": {"light": "#FFFFFF", "dark": "#1E1E1E"}, "borderRadius": 12, "padding": 16 },
  "fallbackText": "Flash Sale! Shop Now: https://..."
}
The body array contains elements (text, image, button, row, column, etc.) rendered top-to-bottom. Interactive elements like buttons emit actions via a callback — the consumer handles navigation, deep links, or API calls.

Retrieve Notification Feed Items

Use NotificationFeedRequest to fetch a paginated list of feed items. Uses cursor-based pagination internally.

Build the Request

let request = NotificationFeedRequest.NotificationFeedRequestBuilder()
    .set(limit: 20)
    .set(readState: .unread)
    .set(category: "Updates")
    .build()

Builder Parameters

MethodTypeDefaultDescription
set(limit:)Int20Items per page.
set(readState:)FeedReadStateAllFilter by .read or .unread. Omit for all.
set(category:)StringnilFilter by category name. Sent as templateCategory query param. If categoryId is also set, categoryId takes priority.
set(categoryId:)StringnilFilter by category ID. Sent as templateCategory query param. Takes priority over category if both are set.
set(channelId:)StringnilFilter by channel.
set(tags:)[String]nilFilter by tags (comma-joined).
set(dateFrom:)StringnilISO 8601 date — items sent on or after.
set(dateTo:)StringnilISO 8601 date — items sent on or before.
set(category:) and set(categoryId:) both map to the same server-side filter (templateCategory). Use one or the other — not both. If both are provided, categoryId silently overwrites category.

Fetch Items

request.fetchNext(onSuccess: { items in
    for item in items {
        let cardJson = item.content
        // Pass cardJson to CometChatCardView
    }
}, onError: { error in
    print("Error: \(error?.errorDescription ?? "")")
})
Call fetchNext() repeatedly for pagination. When the server has no more items, subsequent calls return an empty array.

NotificationFeedItem Fields

FieldTypeDescription
idStringUnique item identifier.
categoryStringNotification category (e.g., “promotions”).
categoryIdStringCategory ID.
content[String: Any]Card Schema JSON — pass to CometChat Cards renderer.
readAtDoubleUnix timestamp when read, or 0 if unread.
deliveredAtDoubleUnix timestamp when delivered, or 0.
sentAtDoubleUnix timestamp when sent.
metadata[String: Any]Custom key-value metadata.
tags[String]Tags for filtering.
senderStringSender identifier.
receiverStringReceiver identifier.
receiverTypeStringReceiver type.
isReadBoolComputed — true if readAt != 0.

Retrieve Notification Categories

Use NotificationCategoriesRequest to fetch available categories for filter chips.
let categoriesRequest = NotificationCategoriesRequest.NotificationCategoriesRequestBuilder()
    .set(limit: 50)
    .build()

categoriesRequest.fetchNext(onSuccess: { categories in
    for category in categories {
        print("Category: \(category.label)")
    }
}, onError: { error in
    print("Error: \(error?.errorDescription ?? "")")
})

NotificationCategory Fields

FieldTypeDescription
idStringCategory identifier.
labelStringDisplay label for filter UI.

Real-Time Notification Feed Listener

Listen for new feed items arriving via WebSocket. This listener is independent from CometChatMessageDelegate, CometChatGroupDelegate, and CometChatCallDelegate.
CometChat.addNotificationFeedListener("feedListener", self)

// Implement CometChatNotificationFeedDelegate
extension MyViewController: CometChatNotificationFeedDelegate {
    func onFeedItemReceived(feedItem: NotificationFeedItem) {
        print("New item: \(feedItem.id)")
        let cardJson = feedItem.content
        // Insert at top of feed and render
    }
}
Remove the listener when no longer needed:
CometChat.removeNotificationFeedListener("feedListener")

Mark Feed Item as Read

Mark a single item as read. Idempotent — safe to call multiple times.
CometChat.markFeedItemAsRead(feedItem, onSuccess: {
    print("Marked as read")
}, onError: { error in
    print("Error: \(error?.errorDescription ?? "")")
})

Mark Feed Item as Delivered

Mark a single item as delivered. Idempotent.
CometChat.markFeedItemAsDelivered(feedItem, onSuccess: {
    // Success
}, onError: { error in
    print("Error: \(error?.errorDescription ?? "")")
})

Report Engagement

Report that a user engaged with a feed item (e.g., viewed, clicked, interacted). Idempotent per topic.
CometChat.reportFeedEngagement(feedItem, interactionString: "clicked", onSuccess: {
    // Success
}, onError: { error in
    print("Error: \(error?.errorDescription ?? "")")
})
The interactionString parameter is a free-form string describing the engagement (e.g., “viewed”, “clicked”, “interacted”).

Get Unread Count

Fetch the total number of unread notification feed items. Optionally filter by category.
CometChat.getNotificationFeedUnreadCount(category: nil, onSuccess: { count in
    print("Unread: \(count)")
}, onError: { error in
    print("Error: \(error?.errorDescription ?? "")")
})

Fetch Single Feed Item

Fetch a specific item by ID — useful for deep linking from push notifications.
CometChat.getNotificationFeedItem(id: "item-id-123", onSuccess: { item in
    let cardJson = item.content
    // Render the card
}, onError: { error in
    print("Error: \(error?.errorDescription ?? "")")
})

Push Notification Tracking

When a campaign push notification arrives via APNs, use these methods to report delivery and click engagement.

Setting Up Notification Service Extension

  1. In Xcode: File → New → Target → select Notification Service Extension.
  2. Enable App Groups on both your main app target and the extension target with the same group ID (e.g., group.com.yourapp.cometchat).
  3. Add CometChatSDK as a dependency to the extension target.

Identifying Campaign Push Notifications

Campaign pushes contain a cometchat dictionary with "type": "business_messaging":
func isCampaignNotification(userInfo: [AnyHashable: Any]) -> Bool {
    if let cometchat = userInfo["cometchat"] as? [String: Any],
       let type = cometchat["type"] as? String,
       type == "business_messaging" {
        return true
    }
    return false
}

Push Payload Structure

{
  "aps": { "alert": { "title": "...", "body": "..." }, "badge": 1, "mutable-content": 1 },
  "cometchat": {
    "type": "business_messaging",
    "appId": "your-app-id",
    "campaignId": "campaign-cuid",
    "notificationId": "notification-cuid",
    "pushNotificationId": "uuid-for-push-tracking",
    "uid": "target-user-id",
    "sentAt": "2026-05-21T12:43:55.206Z"
  }
}

Mark Push Notification as Delivered

Call this in your Notification Service Extension:
import UserNotifications
import CometChatSDK

class NotificationService: UNNotificationServiceExtension {
    override func didReceive(_ request: UNNotificationRequest,
                             withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        let bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)!

        // Required for extensions to share auth state via App Group container
        CometChat.setExtensionGroupID(id: "group.your.app.group")

        let userInfo = bestAttemptContent.userInfo
        if let cometchat = userInfo["cometchat"] as? [String: Any],
           let type = cometchat["type"] as? String,
           type == "business_messaging" {
            let push = PushNotification.fromPayload(cometchat)
            CometChat.markPushNotificationDelivered(push, onSuccess: {}, onError: { _ in })
        }

        contentHandler(bestAttemptContent)
    }
}

Mark Push Notification as Clicked

Call this when the user taps the push notification:
func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive response: UNNotificationResponse,
                            withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo

    if let cometchat = userInfo["cometchat"] as? [String: Any],
       let type = cometchat["type"] as? String,
       type == "business_messaging" {
        let push = PushNotification.fromPayload(cometchat)
        CometChat.markPushNotificationClicked(push, onSuccess: {}, onError: { _ in })
        navigateToNotificationsTab()
        completionHandler()
        return
    }

    completionHandler()
}

PushNotification Fields

FieldTypeDescription
idStringPush notification ID from the push payload.
announcementIdStringNotification/announcement ID.
campaignIdString?Campaign ID if from a campaign.
sourceStringAlways “campaign” for notification feed pushes.

FeedReadState Enum

CaseValueDescription
.read"read"Only read items.
.unread"unread"Only unread items.
If not set, returns all items (default).

Supported Card Actions

When a user taps a button or link inside a card, the action callback receives one of these action types:
Action TypeParametersDescription
openUrlurl, openInOpen a URL in browser or webview.
chatWithUseruidNavigate to 1:1 chat.
chatWithGroupguidNavigate to group chat.
sendMessagetext, receiverUid, receiverGuidSend a text message.
copyToClipboardvalueCopy text to clipboard.
downloadFileurl, filenameDownload a file.
initiateCallcallType (audio/video), uid, guidStart a call.
apiCallurl, method, headers, bodyMake an HTTP request.
customCallbackcallbackId, payloadApp-specific logic.