diff --git a/CampaignAssets/BubbleBuilder.png b/CampaignAssets/BubbleBuilder.png
new file mode 100644
index 000000000..422e6dcd7
Binary files /dev/null and b/CampaignAssets/BubbleBuilder.png differ
diff --git a/CampaignAssets/Create-Chan.png b/CampaignAssets/Create-Chan.png
new file mode 100644
index 000000000..2b1a7799f
Binary files /dev/null and b/CampaignAssets/Create-Chan.png differ
diff --git a/CampaignAssets/Create-Temp.png b/CampaignAssets/Create-Temp.png
new file mode 100644
index 000000000..409206bb5
Binary files /dev/null and b/CampaignAssets/Create-Temp.png differ
diff --git a/CampaignAssets/CreateCategory.png b/CampaignAssets/CreateCategory.png
new file mode 100644
index 000000000..11bca26f7
Binary files /dev/null and b/CampaignAssets/CreateCategory.png differ
diff --git a/CampaignAssets/create-Camp.png b/CampaignAssets/create-Camp.png
new file mode 100644
index 000000000..a42dd807c
Binary files /dev/null and b/CampaignAssets/create-Camp.png differ
diff --git a/docs.json b/docs.json
index 172825868..ee570524d 100644
--- a/docs.json
+++ b/docs.json
@@ -1268,7 +1268,8 @@
"ui-kit/ios/ai-features"
]
},
- "ui-kit/ios/call-features"
+ "ui-kit/ios/call-features",
+ "ui-kit/ios/campaigns"
]
},
{
@@ -1301,7 +1302,8 @@
"ui-kit/ios/call-buttons",
"ui-kit/ios/call-logs",
"ui-kit/ios/ai-assistant-chat-history",
- "ui-kit/ios/search"
+ "ui-kit/ios/search",
+ "ui-kit/ios/notification-feed"
]
},
{
@@ -3680,6 +3682,7 @@
},
"sdk/ios/ai-moderation",
"sdk/ios/ai-agents",
+ "sdk/ios/campaigns",
{
"group": "Resources",
"pages": [
diff --git a/sdk/ios/campaigns.mdx b/sdk/ios/campaigns.mdx
new file mode 100644
index 000000000..d1d08743a
--- /dev/null
+++ b/sdk/ios/campaigns.mdx
@@ -0,0 +1,499 @@
+---
+title: "Campaigns"
+description: "CometChat Campaigns SDK APIs — fetching feed items, managing engagement state, reporting interactions, and receiving real-time notifications."
+---
+
+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.
+
+---
+
+## 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**
+
+```ruby
+pod 'CometChatCardsSwift'
+```
+
+```bash
+pod install
+```
+
+No initialization is required. The library is stateless — import it and start rendering.
+
+### Rendering Feed Items as Cards
+
+```swift
+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
+
+| Property | Type | Description |
+| -------- | ---- | ----------- |
+| `cardJson` | `String?` | Set this to render a card. Triggers a full re-render. |
+| `themeMode` | `CometChatCardThemeMode` | `.auto` (follows system), `.light`, or `.dark`. |
+| `actionCallback` | `((CometChatCardActionEvent) -> Void)?` | Called when user taps a button, link, or icon button inside the card. |
+| `themeOverride` | `CometChatCardThemeOverride?` | Override default theme colors without modifying card JSON. |
+
+### Theme Override
+
+Override default card theme colors to match your app's brand:
+
+```swift
+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:
+
+```swift
+NotificationCenter.default.addObserver(
+ forName: CometChatCardView.contentSizeDidChangeNotification,
+ object: cardView,
+ queue: .main
+) { _ in
+ tableView.beginUpdates()
+ tableView.endUpdates()
+}
+```
+
+---
+
+## Key Concepts
+
+| Concept | Description |
+| ------- | ----------- |
+| NotificationFeedItem | A single notification in the feed. Contains Card Schema JSON in its `content` field, a category for filtering, timestamps, and metadata. |
+| NotificationCategory | A category label used for filter chips (e.g., "Promotions", "Updates"). |
+| Card Schema JSON | The fully rendered card layout (images, text, buttons) inside `NotificationFeedItem.content`. Passed directly to the CometChat Cards renderer. |
+| PushNotification | Represents 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
+
+```json
+{
+ "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
+
+```swift
+let request = NotificationFeedRequest.NotificationFeedRequestBuilder()
+ .set(limit: 20)
+ .set(readState: .unread)
+ .set(category: "Updates")
+ .build()
+```
+
+### Builder Parameters
+
+| Method | Type | Default | Description |
+| ------ | ---- | ------- | ----------- |
+| `set(limit:)` | `Int` | 20 | Items per page. |
+| `set(readState:)` | `FeedReadState` | All | Filter by `.read` or `.unread`. Omit for all. |
+| `set(category:)` | `String` | nil | Filter by category name. Sent as `templateCategory` query param. If `categoryId` is also set, `categoryId` takes priority. |
+| `set(categoryId:)` | `String` | nil | Filter by category ID. Sent as `templateCategory` query param. Takes priority over `category` if both are set. |
+| `set(channelId:)` | `String` | nil | Filter by channel. |
+| `set(tags:)` | `[String]` | nil | Filter by tags (comma-joined). |
+| `set(dateFrom:)` | `String` | nil | ISO 8601 date — items sent on or after. |
+| `set(dateTo:)` | `String` | nil | ISO 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
+
+```swift
+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
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `id` | `String` | Unique item identifier. |
+| `category` | `String` | Notification category (e.g., "promotions"). |
+| `categoryId` | `String` | Category ID. |
+| `content` | `[String: Any]` | Card Schema JSON — pass to CometChat Cards renderer. |
+| `readAt` | `Double` | Unix timestamp when read, or 0 if unread. |
+| `deliveredAt` | `Double` | Unix timestamp when delivered, or 0. |
+| `sentAt` | `Double` | Unix timestamp when sent. |
+| `metadata` | `[String: Any]` | Custom key-value metadata. |
+| `tags` | `[String]` | Tags for filtering. |
+| `sender` | `String` | Sender identifier. |
+| `receiver` | `String` | Receiver identifier. |
+| `receiverType` | `String` | Receiver type. |
+| `isRead` | `Bool` | Computed — `true` if `readAt != 0`. |
+
+---
+
+## Retrieve Notification Categories
+
+Use `NotificationCategoriesRequest` to fetch available categories for filter chips.
+
+```swift
+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
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `id` | `String` | Category identifier. |
+| `label` | `String` | Display 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`.
+
+```swift
+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:
+
+```swift
+CometChat.removeNotificationFeedListener("feedListener")
+```
+
+---
+
+## Mark Feed Item as Read
+
+Mark a single item as read. Idempotent — safe to call multiple times.
+
+```swift
+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.
+
+```swift
+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.
+
+```swift
+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.
+
+```swift
+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.
+
+```swift
+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"`:
+
+```swift
+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
+
+```json
+{
+ "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:
+
+```swift
+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:
+
+```swift
+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
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `id` | `String` | Push notification ID from the push payload. |
+| `announcementId` | `String` | Notification/announcement ID. |
+| `campaignId` | `String?` | Campaign ID if from a campaign. |
+| `source` | `String` | Always "campaign" for notification feed pushes. |
+
+---
+
+## FeedReadState Enum
+
+| Case | Value | Description |
+| ---- | ----- | ----------- |
+| `.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 Type | Parameters | Description |
+| ----------- | ---------- | ----------- |
+| `openUrl` | url, openIn | Open a URL in browser or webview. |
+| `chatWithUser` | uid | Navigate to 1:1 chat. |
+| `chatWithGroup` | guid | Navigate to group chat. |
+| `sendMessage` | text, receiverUid, receiverGuid | Send a text message. |
+| `copyToClipboard` | value | Copy text to clipboard. |
+| `downloadFile` | url, filename | Download a file. |
+| `initiateCall` | callType (audio/video), uid, guid | Start a call. |
+| `apiCall` | url, method, headers, body | Make an HTTP request. |
+| `customCallback` | callbackId, payload | App-specific logic. |
diff --git a/ui-kit/ios/campaigns.mdx b/ui-kit/ios/campaigns.mdx
new file mode 100644
index 000000000..e3ddfe8c8
--- /dev/null
+++ b/ui-kit/ios/campaigns.mdx
@@ -0,0 +1,203 @@
+---
+title: "Campaigns"
+description: "Deliver targeted, rich notifications to users via an in-app notification feed powered by the CometChat Cards renderer."
+---
+
+CometChat Campaigns enables you to send rich, interactive notifications to users through an in-app notification feed. Each notification is rendered as a native card using the CometChat Cards library — supporting images, text, buttons, layouts, and interactive actions.
+
+---
+
+## Overview
+
+Campaigns delivers notifications as Card Schema JSON — a structured format that defines the visual layout of each notification card. The system consists of three layers:
+
+- **CometChat Chat SDK** — Fetches feed items, manages read/delivered state, provides real-time listeners, handles push notification tracking
+- **CometChat Cards Library** — Renders Card Schema JSON into native UIKit views
+- **CometChat UI Kit** — Provides the ready-to-use `CometChatNotificationFeed` component that wires everything together
+
+---
+
+## Sending Campaigns
+
+### 1. Create Channel
+
+Set up the delivery channel for your campaign (e.g., in-app feed, push notification).
+
+
+
+### 2. Create Category
+
+Define a category to organize and filter your campaign notifications (e.g., Promotions, Updates).
+
+
+
+### 3. Create Template
+
+Name your template, assign it a category, and set a unique template ID.
+
+
+
+### 4. Bubble Builder
+
+Use the Bubble Builder to visually design how your template will look when rendered as a notification card.
+
+
+
+### 5. Send Campaign
+
+Configure your audience, schedule, and delivery settings — then send the campaign.
+
+
+
+---
+
+## How Cards Work
+
+Each `NotificationFeedItem` from the SDK contains a `content` field — a `[String: Any]` dictionary holding the Card Schema JSON. This JSON is passed directly to the CometChat Cards renderer which produces a native UIKit view.
+
+The Cards library is a pure renderer:
+
+- **Input:** Card Schema JSON string + theme mode + optional action callback
+- **Output:** Native UIKit view hierarchy
+
+It does not execute actions, manage message state, or call any SDK methods. When users tap interactive elements (buttons, links), the library emits the action to your callback. You decide what happens — open a URL, navigate to a chat, make an API call, etc.
+
+---
+
+## Card Schema JSON Example
+
+```json
+{
+ "version": "1.0",
+ "body": [
+ { "type": "image", "id": "img_1", "url": "https://cdn.example.com/sale.jpg", "height": 180, "fit": "cover", "borderRadius": 8 },
+ { "type": "text", "id": "txt_1", "content": "🎉 Flash Sale — 40% Off!", "variant": "heading2" },
+ { "type": "text", "id": "txt_2", "content": "Limited time offer on all premium plans.", "variant": "body" },
+ { "type": "button", "id": "btn_1", "label": "Claim Offer", "action": { "type": "openUrl", "url": "https://example.com/offer" }, "fullWidth": true }
+ ],
+ "style": { "background": {"light": "#FFFFFF", "dark": "#1E1E1E"}, "borderRadius": 12, "padding": 16 },
+ "fallbackText": "Flash Sale — 40% Off! Claim your offer: https://example.com/offer"
+}
+```
+
+The schema supports 20 element types (text, image, icon, avatar, badge, divider, spacer, chip, progressBar, codeBlock, markdown, row, column, grid, accordion, tabs, button, iconButton, link, table) and 9 action types (openUrl, chatWithUser, chatWithGroup, sendMessage, copyToClipboard, downloadFile, initiateCall, apiCall, customCallback).
+
+---
+
+## Notification Feed Component
+
+The `CometChatNotificationFeed` component renders campaign notifications as a full-screen scrollable feed. It handles fetching, card rendering, pagination, filtering, real-time updates, and engagement reporting automatically.
+
+
+
+```swift
+let notificationFeed = CometChatNotificationFeed()
+let navController = UINavigationController(rootViewController: notificationFeed)
+self.present(navController, animated: true)
+```
+
+
+
+See the full [CometChatNotificationFeed](/ui-kit/ios/notification-feed) documentation for all configuration options, actions, filtering, and customization.
+
+---
+
+## Setting Up Notification Service Extension
+
+To track push notification delivery for campaigns, you need a Notification Service Extension. This runs when a push arrives on the device (even if the app is in the background).
+
+### Step 1: Create the Extension
+
+1. In Xcode, go to **File → New → Target**.
+2. Select **Notification Service Extension**.
+3. Name it (e.g., `NotificationService`).
+4. Click **Finish**.
+
+### Step 2: Configure App Groups
+
+Both your main app and the extension need to share data via an App Group:
+
+1. Select your **main app target** → Signing & Capabilities → **+ Capability** → **App Groups**.
+2. Add a group (e.g., `group.com.yourapp.cometchat`).
+3. Select your **extension target** → repeat the same steps with the same group ID.
+
+### Step 3: Add CometChatSDK to the Extension
+
+Add `CometChatSDK` as a dependency to the extension target (via SPM or CocoaPods).
+
+### Step 4: Implement the Extension
+
+
+
+```swift
+import UserNotifications
+import CometChatSDK
+
+class NotificationService: UNNotificationServiceExtension {
+ override func didReceive(_ request: UNNotificationRequest,
+ withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
+ let bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)!
+
+ // Share auth state via App Group
+ CometChat.setExtensionGroupID(id: "group.com.yourapp.cometchat")
+
+ 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)
+ }
+}
+```
+
+
+
+---
+
+## Handling Push Notification Clicks
+
+When the user taps a campaign push notification, report the click and navigate to the feed:
+
+
+
+```swift
+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 })
+
+ // Navigate to notification feed
+ let notificationFeed = CometChatNotificationFeed()
+ let navController = UINavigationController(rootViewController: notificationFeed)
+ window?.rootViewController?.present(navController, animated: true)
+
+ completionHandler()
+ return
+ }
+
+ completionHandler()
+}
+```
+
+
+
+See the [SDK Campaigns documentation](/sdk/ios/campaigns) for the complete push notification tracking API.
+
+---
+
+## Managing Campaigns
+
+Campaigns are created and managed from the CometChat Dashboard or via the REST API. The SDK and UI Kit are consumer-side — they display and interact with campaigns, not create them.
+
+- **Dashboard:** Navigate to Campaigns → follow the flow above (Channel → Category → Template → Bubble Builder → Send).
+- **REST API:** Use the Campaigns API to programmatically create and schedule campaigns.
diff --git a/ui-kit/ios/notification-feed.mdx b/ui-kit/ios/notification-feed.mdx
new file mode 100644
index 000000000..923461846
--- /dev/null
+++ b/ui-kit/ios/notification-feed.mdx
@@ -0,0 +1,288 @@
+---
+title: "Notification Feed"
+description: "Full-screen notification feed component with category filtering, card rendering, real-time updates, and engagement reporting."
+---
+
+`CometChatNotificationFeed` displays a scrollable notification feed where each item is rendered as a native card using the CometChat Cards library. It handles fetching, pagination, category filtering, real-time updates, and read/delivered/engagement reporting automatically. Present it in a `UINavigationController`, push it onto an existing navigation stack, or embed it in a tab bar.
+
+Each notification gets its own section header with the category label on the left and a relative timestamp on the right:
+
+| Condition | Display |
+| --------- | ------- |
+| Today (< 24 hours ago) | Time only — 2:35 PM |
+| Yesterday (24–48 hours ago) | Yesterday |
+| This week (2–7 days ago) | Day name — Monday, Tuesday, etc. |
+| Older (> 7 days) | Full date — 25/05/2026 |
+
+
+
+```swift
+let notificationFeed = CometChatNotificationFeed()
+notificationFeed.set(onItemClick: { feedItem in
+ // Handle item tap (e.g., open detail or deep link)
+})
+
+let navController = UINavigationController(rootViewController: notificationFeed)
+self.present(navController, animated: true)
+```
+
+
+
+---
+
+## Quick Start
+
+
+
+```swift
+let notificationFeed = CometChatNotificationFeed()
+let navController = UINavigationController(rootViewController: notificationFeed)
+self.present(navController, animated: true)
+```
+
+
+
+Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()` and a user logged in.
+
+---
+
+## Filtering Feed Items
+
+Control what loads using custom request builders:
+
+
+
+```swift
+let notificationFeed = CometChatNotificationFeed()
+notificationFeed.set(notificationFeedRequestBuilder:
+ NotificationFeedRequest.NotificationFeedRequestBuilder()
+ .set(limit: 30)
+ .set(readState: .unread)
+ .set(category: "promotions")
+)
+```
+
+
+
+### Filter Options
+
+| Builder Method | Description |
+| -------------- | ----------- |
+| `.set(limit: Int)` | Items per page (default 20). |
+| `.set(readState: FeedReadState)` | `.read`, `.unread`, or omit for all. |
+| `.set(category: String)` | Filter by category name. |
+| `.set(categoryId: String)` | Filter by category ID. |
+| `.set(channelId: String)` | Filter by channel. |
+| `.set(tags: [String])` | Filter by tags. |
+| `.set(dateFrom: String)` | ISO 8601 date lower bound. |
+| `.set(dateTo: String)` | ISO 8601 date upper bound. |
+
+Pass the builder object, not the result of `.build()`. The component calls `.build()` internally.
+
+---
+
+## Actions and Events
+
+### onItemClick
+
+Fires when a feed item card is tapped.
+
+
+
+```swift
+notificationFeed.set(onItemClick: { feedItem in
+ // feedItem.id, feedItem.content (Card JSON), feedItem.category
+ print("Item tapped: \(feedItem.id)")
+})
+```
+
+
+
+---
+
+### onActionClick
+
+Fires when an interactive element (button, link) inside a card is tapped.
+
+
+
+```swift
+notificationFeed.set(onActionClick: { feedItem, actionEvent in
+ // Report engagement on every action
+ CometChat.reportFeedEngagement(feedItem, interactionString: "button_clicked", onSuccess: {}, onError: { _ in })
+
+ // Handle the action
+ 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
+ case .customCallback(let callbackId, let payload):
+ // Custom app logic
+ break
+ default:
+ break
+ }
+})
+```
+
+
+
+---
+
+### onError
+
+Fires when an internal error occurs (network failure, SDK exception).
+
+
+
+```swift
+notificationFeed.set(onError: { error in
+ print("Feed error: \(error.errorDescription)")
+})
+```
+
+
+
+---
+
+## Automatic Behaviors
+
+The component handles these automatically — no manual setup needed:
+
+| Behavior | Description |
+| -------- | ----------- |
+| Real-time updates | New items appear at the top via WebSocket listener. |
+| Delivery reporting | Items are reported as delivered when fetched. |
+| Read reporting | Items are reported as read after 1 second of visibility. |
+| Unread count polling | Polls unread count every 30 seconds to update badges. |
+| Infinite scroll | Fetches next page when scrolling near the bottom. |
+| Pull-to-refresh | Resets and fetches fresh data on pull. |
+| Timestamp grouping | Groups items as "Today", "Yesterday", day name, or date. |
+| Category filtering | Filter chips row for category-based filtering. |
+| Connection recovery | Automatically refreshes when the app returns from background. |
+
+---
+
+## Functionality
+
+| Method | Description |
+| ------ | ----------- |
+| `set(title: String)` | Header title text. Default "Notifications". |
+| `set(showBackButton: Bool)` | Toggle back button visibility. Default `true`. |
+| `set(showFilterChips: Bool)` | Toggle category filter chips. Default `true`. |
+| `set(cardThemeMode: String)` | Card rendering theme: "auto", "light", or "dark". |
+| `set(notificationFeedRequestBuilder:)` | Custom feed request builder. |
+| `set(notificationCategoriesRequestBuilder:)` | Custom categories request builder. |
+
+
+
+```swift
+let notificationFeed = CometChatNotificationFeed()
+notificationFeed.set(title: "Activity")
+notificationFeed.set(showBackButton: false)
+notificationFeed.set(showFilterChips: true)
+notificationFeed.set(cardThemeMode: "dark")
+```
+
+
+
+---
+
+## Common Patterns
+
+### Show only unread items
+
+
+
+```swift
+notificationFeed.set(notificationFeedRequestBuilder:
+ NotificationFeedRequest.NotificationFeedRequestBuilder()
+ .set(readState: .unread)
+)
+```
+
+
+
+### Hide filter chips
+
+
+
+```swift
+notificationFeed.set(showFilterChips: false)
+```
+
+
+
+### Custom categories request
+
+
+
+```swift
+notificationFeed.set(notificationCategoriesRequestBuilder:
+ NotificationCategoriesRequest.NotificationCategoriesRequestBuilder()
+ .set(limit: 10)
+)
+```
+
+
+
+### Embed in a Tab Bar
+
+
+
+```swift
+let notificationFeed = CometChatNotificationFeed()
+notificationFeed.set(showBackButton: false)
+notificationFeed.tabBarItem = UITabBarItem(
+ title: "Notifications",
+ image: UIImage(systemName: "bell"),
+ selectedImage: UIImage(systemName: "bell.fill")
+)
+
+// Add to tab bar controller
+let navController = UINavigationController(rootViewController: notificationFeed)
+tabBarController.viewControllers?.append(navController)
+```
+
+
+
+### Handle action + report engagement
+
+
+
+```swift
+notificationFeed.set(onActionClick: { feedItem, actionEvent in
+ // Always report engagement
+ CometChat.reportFeedEngagement(feedItem, 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):
+ // Open CometChat messages with user
+ break
+ default:
+ break
+ }
+})
+```
+
+
+
+---
+
+## Next Steps
+
+| Topic | Description |
+| ----- | ----------- |
+| [Campaigns Feature](/ui-kit/ios/campaigns) | Overview of how campaigns work end-to-end. |
+| [SDK Campaigns API](/sdk/ios/campaigns) | Low-level SDK APIs for feed items, categories, and engagement. |