> ## Documentation Index
> Fetch the complete documentation index at: https://moengage-sdk-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Self Handled Cards

> Build custom card views in your Android app using the MoEngage self-handled Cards SDK.

Self-handled cards give you the flexibility of creating Card Campaigns on the MoEngage Platform and displaying the cards anywhere inside the application. SDK provides APIs to fetch the campaign's data using which you can create your own view for cards.

# SDK Installation

## Installing using BOM

Integration using BOM  is the recommended way of integration; refer to the [Install Using BOM](/developer-guide/android-sdk/sdk-integration/basic-integration/Install-Using-BOM) document. Once you have configured the BOM add the dependency in the *app/build.gradle* file as shown below

<CodeGroup>
  ```kotlin build.gradle.kts wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  dependencies {
     ...
     implementation("com.moengage:cards-core")
  }
  ```
</CodeGroup>

Once the BOM is configured, include the specific MoEngage modules required for the application. \
Note: Version numbers are not required for these dependencies; the BOM automatically manages them.

# Implementing Self Handled Cards

Use the below APIs to fetch the card's data and build your own UI. The SDK provides both blocking and async APIs for fetching the data. In this document, we have just added the blocking APIs, refer to the API reference for [*MoECardHelper*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/index.html) for the async APIs.

## Notify on Section Load/Unload

You can show the cards on a separate screen or a section of the screen. When the cards screen/section is loaded call [*onCardSectionLoaded()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/on-card-section-loaded.html) and call [*onCardSectionUnloaded()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/on-card-section-unloaded.html) when the screen/section is no longer visible or going to background.

<Info>
  * *When onCardSectionLoaded()* and *onCardSectionUnloaded()* are called together, the SDK automatically tracks the card impressions.
  * The *onCardSectionLoaded()* has an SLA of 5 minutes.
</Info>

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  // call on section or screen load
  MoECardHelper.onCardSectionLoaded(context,listener);
  // call when the section is no longer visible or going to background.
  MoECardHelper.onCardSectionUnloaded(context);
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  // call on section or screen load
  MoECardHelper.INSTANCE.onCardSectionLoaded(context,listener);
  // call when the section is no longer visible or going to background.
  MoECardHelper.INSTANCE.onCardSectionUnloaded(context);
  ```
</CodeGroup>

## Fetch Cards from the Server

Use the [*fetchCards()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/fetch-cards.html) API to refresh cards from the MoEngage server.

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.fetchCards(Context, CardAvailableListener)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.fetchCards(Context, CardAvailableListener);
  ```
</CodeGroup>

<Info>
  *fetchCards()* hits the server at most once every 5 minutes. If called more frequently, the existing cached cards are returned via the callback.
</Info>

## Refresh Cards

Checks the server for card updates. Returns a `hasUpdates` flag. If `hasUpdates` is true, the latest cards are stored in local storage. Call `getCards()` / `getCardsForCategory()` / `getCardsInfo()` to retrieve the updated cards from local storage.

**Method signature:** `MoECardHelper.refreshCards(context, listener)`

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.refreshCards(context, listener)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.refreshCards(context, listener);
  ```
</CodeGroup>

<Info>
  *refreshCards()* has a  shorter SLA (\~5 seconds) compared to fetchCards() (5 minutes), making it suitable for near-real-time card updates.
</Info>

## Fetch Categories

To fetch all the categories for which cards are configured, use the [*getCardCategories()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/get-card-categories.html) API.

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.getCardCategories(context)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.getCardCategories(context);
  ```
</CodeGroup>

Additionally, you can optionally have an **All** category which would be like a superset of other categories. Use the [*isAllCategoryEnabled()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/is-all-category-enabled.html) API.

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.isAllCategoryEnabled(context)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.isAllCategoryEnabled(context);
  ```
</CodeGroup>

## Fetch Cards for Categories

To fetch cards eligible for display for a specific category, use the [*getCardsForCategory()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/get-cards-for-category.html) API

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.getCardsForCategory(context, "[YOUR_CATEGORY]")
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.getCardsForCategory(context, "[YOUR_CATEGORY]");
  ```
</CodeGroup>

To fetch all the cards eligible for display irrespective of the category, pass the category **CARD\_CATEGORY\_ALL** as shown below

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.getCardsForCategory(context, CARDS_CATEGORY_ALL)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.getCardsForCategory(context, MoECardsCoreConstants.CARDS_CATEGORY_ALL);
  ```
</CodeGroup>

Refer to the documentation of the [*Card*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core.model/-card/index.html) model to know more about the fields and data present.

Instead of using separate APIs to fetch the Cards and categories, you can use the [*getCardsInfo()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/get-cards-info.html) API to fetch all the information in one go

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.getCardsInfo(context)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.getCardsInfo(context);
  ```
</CodeGroup>

## Widget and Widget Id Mapping

### Basic Card/Illustration Card

| Widget Id | Widget Type                | Widget Information                |
| --------- | -------------------------- | --------------------------------- |
| 0         | Image (WidgetType.IMAGE)   | Image widget in the card.         |
| 1         | Text (WidgetType.TEXT)     | Header text for the card.         |
| 2         | Text (WidgetType.TEXT)     | Message text for the card.        |
| 3         | Button (WidgetType.Button) | Call to action(CTA) for the card. |

## Track Statistics for Cards

Since the UI/display of the cards is controlled by the application to track statistics on delivery, display, and click, we need the application to notify the SDK.

### Delivered

To track delivery to the card section of the application, call the [*cardDelivered()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/card-delivered.html) API when the cards section of the application is loaded.

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.cardDelivered(context)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.cardDelivered(context);
  ```
</CodeGroup>

### Impression

Call the [*cardShown()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/card-shown.html) API when a specific card is visible on the screen.

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.cardShown(context, card)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.cardShown(context, card);
  ```
</CodeGroup>

### Click

Call the [*cardClicked()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/card-clicked.html) API whenever a user clicks on a card, along with the card object widget identifier for the UI element clicked should also be passed.

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.cardClicked(context, card, widgetId)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.cardClicked(context, card, widgetId);
  ```
</CodeGroup>

## Delete Card

Call the [*deleteCard()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/delete-card.html) API to delete a card

<CodeGroup>
  ```Kotlin Kotlin wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.deleteCard(context, card)
  ```

  ```Java Java theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoECardHelper.INSTANCE.deleteCard(context, card);
  ```
</CodeGroup>

To delete a list of cards, use [*deleteCards()*](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/delete-cards.html) API.

Please take a look at the [documentation](https://moengage.github.io/android-api-reference/cards-core/com.moengage.cards.core/-mo-e-card-helper/index.html) for a complete guide on available helper APIs.

# FAQs

<Accordion title="What is the recommended implementation for a standard Cards Inbox?">
  MoEngage recommends calling onCardSectionLoaded() when the user enters the Cards section and onCardSectionUnloaded() when they leave. Doing so allows the SDK to automatically handle server synchronization, event deduplication, and impression tracking.
</Accordion>

<Accordion title="How do I handle near-real-time card updates (e.g., replacing a card after a user action)">
  Follow this 3-step pattern to ensure cards are always fresh without hitting rate limits:

  1. **Initial Load**: On page load, call `fetchCards()` to get the latest cards from the server.
  2. **Trigger Update**: When you need to check for updates (e.g., after a survey submission), call `refreshCards()`.
  3. **Retrieve Data**: If `refreshCards()` returns `hasUpdates = true`, call `getCardsForCategory()` or `getCardsInfo()` to pull the updated cards from local storage.
</Accordion>

<Accordion title="What is the difference between onCardSectionLoaded() and fetchCards()?">
  | Feature                 | `onCardSectionLoaded() + onCardSectionUnLoaded()` | `fetchCards()`                                  |
  | :---------------------- | :------------------------------------------------ | :---------------------------------------------- |
  | **Use Case**            | **Recommended** for card inbox screens.           | One-time refresh outside the section lifecycle. |
  | **Impression Tracking** | The SDK tracks card impressions automatically.    | User have to track impressions Manually         |
</Accordion>
