> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-audit-mechanical-fixes.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Campaigns

> Deliver targeted, rich in-app notification campaigns to users in your Android app using CometChat Campaigns and the Card Schema JSON format.

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.

<Note>
  Before using the SDK, set up your channels, categories, templates, and campaigns in the CometChat Dashboard. See the [Dashboard Setup Guide](/campaigns#setup-flow) for step-by-step instructions.
</Note>

***

## 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.getContent()`. Passed directly to the CometChat Cards renderer. |
| **PushNotification**     | Represents a campaign push notification payload received via FCM.                                                                                   |

***

## Rendering Cards

The `content` field of each `NotificationFeedItem` is a Card Schema JSON object. To render it natively, use the CometChat Cards library.

### Add the Cards Dependency

Add the Cloudsmith repository and the cards library to your project:

```groovy theme={null}
// settings.gradle or project-level build.gradle
repositories {
    maven { url "https://dl.cloudsmith.io/public/cometchat/cometchat/maven/" }
}
```

```groovy theme={null}
// app/build.gradle
dependencies {
    implementation "com.cometchat:cards-android:1.0.0"
}
```

<Note>
  Requires `minSdk 24`, Kotlin, and internet permission in your AndroidManifest.xml.
</Note>

### Render a Card from a Feed Item

<Tabs>
  <Tab title="Jetpack Compose">
    ```kotlin theme={null}
    import com.cometchat.cards.CometChatCardComposable
    import com.cometchat.cards.core.CometChatCardThemeMode

    @Composable
    fun NotificationCard(item: NotificationFeedItem) {
        CometChatCardComposable(
            cardJson = item.content.toString(),
            themeMode = CometChatCardThemeMode.AUTO,
            onAction = { event ->
                when (event.action) {
                    is CometChatCardOpenUrlAction -> {
                        // Open URL in browser
                    }
                    is CometChatCardChatWithUserAction -> {
                        // Navigate to chat
                    }
                }
            }
        )
    }
    ```
  </Tab>

  <Tab title="Traditional View">
    ```kotlin theme={null}
    import com.cometchat.cards.CometChatCardView
    import com.cometchat.cards.core.CometChatCardThemeMode

    val cardView = CometChatCardView(context)
    cardView.setCardSchema(item.content.toString())
    cardView.setThemeMode(CometChatCardThemeMode.AUTO)
    cardView.setActionCallback { event ->
        // Handle action: event.action, event.elementId
    }
    parentLayout.addView(cardView)
    ```
  </Tab>
</Tabs>

<Note>
  The Cards library is a pure renderer — it does not execute actions. Your code must handle action callbacks (opening URLs, navigating to chats, making API calls, etc.).
</Note>

***

## How Cards Render in the Notification Feed

Each `NotificationFeedItem` has a `content` field containing a `JSONObject` — this is the **Card Schema JSON**. This JSON is passed directly to the **CometChat Cards** renderer library (`com.cometchat:cards-android`).

The rendering flow:

1. Fetch feed items via `NotificationFeedRequest`
2. For each item, extract `item.getContent()` — this is the Card Schema JSON
3. Convert to string: `item.getContent().toString()`
4. Pass to the Cards renderer (`CometChatCardView` or `CometChatCardComposable`)
5. The renderer produces a native Android view from the JSON

### Card Schema JSON Structure

```json theme={null}
{
  "version": "1.0",
  "body": [
    {
      "type": "column",
      "backgroundColor": {
        "light": "transparent",
        "dark": "transparent"
      },
      "gap": 5,
      "items": [
        {
          "type": "text",
          "content": "📢 Announcement",
          "variant": "heading2",
          "id": "txt_99323141-2459-4e33-88d3-ca39c5fd2f50"
        },
        {
          "type": "text",
          "content": "Your announcement message here.",
          "variant": "body",
          "id": "txt_61a417bc-5e4a-4ba2-bfe7-b7bc64dbaf35"
        },
        {
          "type": "divider",
          "id": "div_80f5c7fb-fd10-41d1-8c2f-51498f0f62d0"
        },
        {
          "type": "button",
          "label": "Learn More",
          "backgroundColor": {
            "light": "transparent",
            "dark": "transparent"
          },
          "textColor": {
            "light": "#6C5CE7",
            "dark": "#6C5CE7"
          },
          "size": 40,
          "fontSize": 13,
          "borderRadius": 6,
          "padding": {
            "top": 0,
            "right": 16,
            "bottom": 0,
            "left": 16
          },
          "action": {
            "type": "openUrl",
            "url": ""
          },
          "id": "btn_9b87a3f1-b0c6-45b9-a4c2-e22ea590f17f"
        }
      ],
      "id": "col_98fed9bd-1a95-4cee-aa81-84a9016e41f2"
    }
  ],
  "fallbackText": "",
  "style": {
    "background": {
      "light": "#E8E8E8",
      "dark": "#E8E8E8"
    },
    "borderRadius": 16,
    "borderColor": {
      "light": "#DFE6E9",
      "dark": "#DFE6E9"
    },
    "padding": 12
  }
}
```

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

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    NotificationFeedRequest request = new NotificationFeedRequest.NotificationFeedRequestBuilder()
        .setLimit(20)
        .build();
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val request = NotificationFeedRequest.NotificationFeedRequestBuilder()
        .setLimit(20)
        .build()
    ```
  </Tab>
</Tabs>

### Builder Parameters

| Method                        | Type   | Default | Description                             |
| ----------------------------- | ------ | ------- | --------------------------------------- |
| `setLimit(int)`               | int    | 20      | Items per page (max 100)                |
| `setReadState(FeedReadState)` | enum   | `ALL`   | Filter by `READ`, `UNREAD`, or `ALL`    |
| `setCategory(String)`         | String | null    | Filter by category ID                   |
| `setChannelId(String)`        | String | null    | Filter by channel                       |
| `setTags(List<String>)`       | List   | null    | Filter by tags                          |
| `setDateFrom(String)`         | String | null    | ISO 8601 date — items sent on or after  |
| `setDateTo(String)`           | String | null    | ISO 8601 date — items sent on or before |

### Fetch Items

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    request.fetchNext(new CometChat.CallbackListener<List<NotificationFeedItem>>() {
        @Override
        public void onSuccess(List<NotificationFeedItem> items) {
            for (NotificationFeedItem item : items) {
                String cardJson = item.getContent().toString();
                // Pass cardJson to CometChatCardView or CometChatCardComposable
            }
        }

        @Override
        public void onError(CometChatException e) {
            Log.e("Feed", "Error: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    request.fetchNext(object : CometChat.CallbackListener<List<NotificationFeedItem>>() {
        override fun onSuccess(items: List<NotificationFeedItem>) {
            items.forEach { item ->
                val cardJson = item.content.toString()
                // Pass cardJson to CometChatCardView or CometChatCardComposable
            }
        }

        override fun onError(e: CometChatException) {
            Log.e("Feed", "Error: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

Call `fetchNext()` repeatedly for pagination. When the server has no more items, subsequent calls return an empty list.

### NotificationFeedItem Fields

| Field         | Type          | Description                                         |
| ------------- | ------------- | --------------------------------------------------- |
| `id`          | String        | Unique item identifier                              |
| `category`    | String        | Notification category (e.g., "promotions")          |
| `content`     | JSONObject    | Card Schema JSON — pass to CometChat Cards renderer |
| `readAt`      | Long?         | Unix timestamp when read, or null if unread         |
| `deliveredAt` | Long?         | Unix timestamp when delivered, or null              |
| `sentAt`      | long          | Unix timestamp when sent                            |
| `metadata`    | HashMap       | Custom key-value metadata                           |
| `tags`        | List\<String> | Tags for filtering                                  |
| `receiver`    | String        | Receiver identifier                                 |

***

## Retrieve Notification Categories

Use `NotificationCategoriesRequest` to fetch available categories for filter chips.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    NotificationCategoriesRequest categoriesRequest = new NotificationCategoriesRequest
        .NotificationCategoriesRequestBuilder()
        .setLimit(50)
        .build();

    categoriesRequest.fetchNext(new CometChat.CallbackListener<List<NotificationCategory>>() {
        @Override
        public void onSuccess(List<NotificationCategory> categories) {
            for (NotificationCategory category : categories) {
                Log.d("Feed", "Category: " + category.getName());
            }
        }

        @Override
        public void onError(CometChatException e) {
            Log.e("Feed", "Error: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val categoriesRequest = NotificationCategoriesRequest.NotificationCategoriesRequestBuilder()
        .setLimit(50)
        .build()

    categoriesRequest.fetchNext(object : CometChat.CallbackListener<List<NotificationCategory>>() {
        override fun onSuccess(categories: List<NotificationCategory>) {
            categories.forEach { category ->
                Log.d("Feed", "Category: ${category.name}")
            }
        }

        override fun onError(e: CometChatException) {
            Log.e("Feed", "Error: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

### NotificationCategory Fields

| Field         | Type   | Description                |
| ------------- | ------ | -------------------------- |
| `id`          | String | Category identifier        |
| `name`        | String | Display name for filter UI |
| `description` | String | Category description       |
| `appId`       | String | Associated app ID          |

***

## Real-Time Notification Feed Listener

Listen for new feed items arriving via WebSocket. This listener is independent from `MessageListener`, `GroupListener`, and `CallListener`.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CometChat.addNotificationFeedListener("feedListener", new NotificationFeedListener() {
        @Override
        public void onFeedItemReceived(NotificationFeedItem feedItem) {
            Log.d("Feed", "New item: " + feedItem.getId());
            String cardJson = feedItem.getContent().toString();
            // Insert at top of feed and render
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.addNotificationFeedListener("feedListener", object : NotificationFeedListener() {
        override fun onFeedItemReceived(feedItem: NotificationFeedItem) {
            Log.d("Feed", "New item: ${feedItem.id}")
            val cardJson = feedItem.content.toString()
            // Insert at top of feed and render
        }
    })
    ```
  </Tab>
</Tabs>

Remove the listener when no longer needed:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CometChat.removeNotificationFeedListener("feedListener");
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.removeNotificationFeedListener("feedListener")
    ```
  </Tab>
</Tabs>

***

## Mark Feed Item as Read

Mark a single item as read. Idempotent — safe to call multiple times.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CometChat.markFeedItemAsRead(feedItem, new CometChat.CallbackListener<Void>() {
        @Override
        public void onSuccess(Void unused) {
            Log.d("Feed", "Marked as read");
        }

        @Override
        public void onError(CometChatException e) {
            Log.e("Feed", "Error: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.markFeedItemAsRead(feedItem, object : CometChat.CallbackListener<Void?>() {
        override fun onSuccess(result: Void?) {
            Log.d("Feed", "Marked as read")
        }

        override fun onError(e: CometChatException) {
            Log.e("Feed", "Error: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

***

## Mark Feed Item as Delivered

Mark a single item as delivered. Idempotent.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CometChat.markFeedItemAsDelivered(feedItem, new CometChat.CallbackListener<Void>() {
        @Override
        public void onSuccess(Void unused) {
            // Success
        }

        @Override
        public void onError(CometChatException e) {
            Log.e("Feed", "Error: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.markFeedItemAsDelivered(feedItem, object : CometChat.CallbackListener<Void?>() {
        override fun onSuccess(result: Void?) { /* Success */ }
        override fun onError(e: CometChatException) {
            Log.e("Feed", "Error: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

***

## Report Engagement

Report that a user engaged with a feed item (e.g., viewed, clicked, interacted). Idempotent.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CometChat.reportFeedEngagement(feedItem, "clicked", new CometChat.CallbackListener<Void>() {
        @Override
        public void onSuccess(Void unused) { }

        @Override
        public void onError(CometChatException e) { }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.reportFeedEngagement(feedItem, "clicked", object : CometChat.CallbackListener<Void?>() {
        override fun onSuccess(result: Void?) { }
        override fun onError(e: CometChatException) { }
    })
    ```
  </Tab>
</Tabs>

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.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CometChat.getNotificationFeedUnreadCount(new CometChat.CallbackListener<Integer>() {
        @Override
        public void onSuccess(Integer count) {
            Log.d("Feed", "Unread: " + count);
        }

        @Override
        public void onError(CometChatException e) {
            Log.e("Feed", "Error: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.getNotificationFeedUnreadCount(object : CometChat.CallbackListener<Int>() {
        override fun onSuccess(count: Int) {
            Log.d("Feed", "Unread: $count")
        }

        override fun onError(e: CometChatException) {
            Log.e("Feed", "Error: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

***

## Fetch Single Feed Item

Fetch a specific item by ID — useful for deep linking from push notifications.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CometChat.getNotificationFeedItem("item-id-123", new CometChat.CallbackListener<NotificationFeedItem>() {
        @Override
        public void onSuccess(NotificationFeedItem item) {
            String cardJson = item.getContent().toString();
            // Render the card
        }

        @Override
        public void onError(CometChatException e) {
            Log.e("Feed", "Error: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.getNotificationFeedItem("item-id-123", object : CometChat.CallbackListener<NotificationFeedItem>() {
        override fun onSuccess(item: NotificationFeedItem) {
            val cardJson = item.content.toString()
            // Render the card
        }

        override fun onError(e: CometChatException) {
            Log.e("Feed", "Error: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

***

## Push Notification Tracking

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

### Mark Push Notification as Delivered

Call this in your `FirebaseMessagingService.onMessageReceived()`:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    PushNotification pushNotification = PushNotification.fromJson(pushPayloadJson);

    CometChat.markPushNotificationDelivered(pushNotification, new CometChat.CallbackListener<Void>() {
        @Override
        public void onSuccess(Void unused) { }

        @Override
        public void onError(CometChatException e) { }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val pushNotification = PushNotification.fromJson(pushPayloadJson)

    CometChat.markPushNotificationDelivered(pushNotification, object : CometChat.CallbackListener<Void?>() {
        override fun onSuccess(result: Void?) { }
        override fun onError(e: CometChatException) { }
    })
    ```
  </Tab>
</Tabs>

### Mark Push Notification as Clicked

Call this when the user taps the push notification:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CometChat.markPushNotificationClicked(pushNotification, new CometChat.CallbackListener<Void>() {
        @Override
        public void onSuccess(Void unused) { }

        @Override
        public void onError(CometChatException e) { }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.markPushNotificationClicked(pushNotification, object : CometChat.CallbackListener<Void?>() {
        override fun onSuccess(result: Void?) { }
        override fun onError(e: CometChatException) { }
    })
    ```
  </Tab>
</Tabs>

### PushNotification Fields

| Field            | Type    | Description                                      |
| ---------------- | ------- | ------------------------------------------------ |
| `id`             | String  | Announcement ID from the push payload            |
| `announcementId` | String  | Same as id (for clarity)                         |
| `campaignId`     | String? | Campaign ID if from a campaign                   |
| `source`         | String  | Always `"campaign"` for notification feed pushes |

***

## FeedReadState Enum

| Value    | Description         |
| -------- | ------------------- |
| `READ`   | Only read items     |
| `UNREAD` | Only unread items   |
| `ALL`    | 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               |
