> ## 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 iOS app using the MoEngage self-handled cards SDK and APIs.

Self-handled cards give you the flexibility to create card campaigns on the MoEngage Platform and display the cards anywhere within the application. The SDK provides APIs to fetch the campaign's data, which allows you to create your own custom view for the cards.

# SDK Installation

## Install using Swift Package Manager

MoEngageCards is supported through SPM from SDK version 3.2.0. To integrate use the following git hub url link and set the branch as master or version as 4.0.0 and above [https://github.com/moengage/MoEngage-iOS-Cards.git](https://github.com/moengage/MoEngage-iOS-Cards.git)

## Install using CocoaPod

<Info>
  **Information**

  CocoaPods is being deprecated. MoEngage recommends using Swift Package Manager for all new integrations. For detailed info on cocoapods, refer to [CocoaPods Integration Guide](/developer-guide/ios-sdk/sdk-integration/basic/integration-through-cocoa-pods).
</Info>

Integrate the MoEngageCards framework by adding the dependency in the podfile as shown below.

<CodeGroup>
  ```ruby Ruby theme={"theme":{"light":"github-light","dark":"github-dark"}}
  pod 'MoEngage-iOS-SDK/Cards',
  ```
</CodeGroup>

Now run `pod install` to install the framework.

## Manual Integration

<Info>
  **Manual Integration**

  To integrate the `MoEngageCards` SDK manually to your project follow this [doc](/developer-guide/ios-sdk/manual-integration/manual-integration).
</Info>

## Notify on Section Load

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/ios-api-reference/Classes/MoEngageSDKCards.html#/c:@M@MoEngageCards@objc\(cs\)MoEngageSDKCards\(im\)onCardSectionLoadedForAppID:withCompletion)

<Info>
  **If you are using a** `UIViewController `**as the cards page, call** `onCardSectionLoaded() `**inside** `viewWillAppear(_:) `**to ensure cards are synced each time the screen becomes visible.**
</Info>

<CodeGroup>
  ```swift Swift wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoEngageSDKCards.sharedInstance.onCardSectionLoaded(forAppID: "Your Workspace Id") { data in
     print("Card section loaded, hasUpdates: \(data?.hasUpdates ?? false)")
  }
  ```

  ```objective-c Objective C wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  [[MoEngageSDKCards sharedInstance] onCardSectionLoadedForAppID:@"Your Workspace Id"
                                                 withCompletion:^(MoEngageCardSyncCompleteData * _Nullable data) {
     NSLog(@"Card section loaded, hasUpdates: %d", data.hasUpdates);
  }];
  ```
</CodeGroup>

Use the below APIs to fetch the card's data and build your own UI.

## Fetch Categories

To fetch all the categories for which cards are configured use the API [*getCardsCategories(forAppID:withCompletionBlock:)*](https://moengage.github.io/ios-api-reference/Classes/MoEngageSDKCards.html#/c:@M@MoEngageCards@objc\(cs\)MoEngageSDKCards\(im\)getCardsCategoriesForAppID:withCompletionBlock:)

<CodeGroup>
  ```swift Swift wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoEngageSDKCards.sharedInstance.getCardsCategories { categories, accountMeta in
     print("Fetched Cards Categories \(categories)")
  }
  ```

  ```objective-c Objective C wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  [[MoEngageSDKCards sharedInstance] getCardsCategoriesForAppID:@"Your Workspace Id" withCompletionBlock:^(NSArray * _Nonnull, MoEngageAccountMeta * _Nullable) {
     NSLog(@"Fetched Cards Categories");
  }];
  ```
</CodeGroup>

## Fetch Cards for Categories

To fetch cards eligible for display for a specific category use the API [*getCards(forCategory:forAppID:withCompletionBlock:)*](https://moengage.github.io/ios-api-reference/Classes/MoEngageSDKCards.html#/c:@M@MoEngageCards@objc\(cs\)MoEngageSDKCards\(im\)getCardsForCategory:forAppID:withCompletionBlock:)

<CodeGroup>
  ```swift Swift wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoEngageSDKCards.sharedInstance.getCards(forCategory: "CATEGORY") { cards, accountMeta in
     print("Fetched cards for given category")
  }
  ```

  ```objective-c Objective C wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  [[MoEngageSDKCards sharedInstance] getCardsForCategory:@"CATEGORY" forAppID:@"YOUR Workspace ID" withCompletionBlock:^(NSArray * _Nonnull, MoEngageAccountMeta * _Nullable) {
     NSLog(@"Fetched cards for given category");
  }];
  ```
</CodeGroup>

Instead of using separate APIs to fetch the Cards and categories you can use the method [*getCardsData(forAppID:withCompletionBlock:)*](https://moengage.github.io/ios-api-reference/Classes/MoEngageSDKCards.html#/c:@M@MoEngageCards@objc\(cs\)MoEngageSDKCards\(im\)getCardsDataForAppID:withCompletionBlock:) to fetch all the information in one go.

<CodeGroup>
  ```swift Swift wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoEngageSDKCards.sharedInstance.getCardsData { cardsData, accountMeta in
     print("Cards category \(cardsData?.cardCategories)")
     print("Cards Data \(cardsData?.cards)")
  }
  ```

  ```objective-c Objective C wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  [[MoEngageSDKCards sharedInstance] getCardsDataForAppID:@"YOUR Workspace ID" withCompletionBlock:^(MoEngageCardsData * _Nullable, MoEngageAccountMeta * _Nullable) {
     NSLog(@"Cards category %@", cardsData.cardCategories);
     NSLog(@"Cards Data %@", cardsData.cards);
  }];
  ```
</CodeGroup>

## Track Statistics for Cards

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

### Delivered

To track delivery to the card section of the application use the API [*cardDelivered(\_:forAppID:)*](https://moengage.github.io/ios-api-reference/Classes/MoEngageSDKCards.html#/c:@M@MoEngageCards@objc\(cs\)MoEngageSDKCards\(im\)cardDelivered:forAppID:) when the cards section of the application is loaded by passing the instance of [*MoEngageCardCampaign*](https://moengage.github.io/ios-api-reference/Classes/MoEngageCardCampaign.html).

<CodeGroup>
  ```swift Swift wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoEngageSDKCards.sharedInstance.cardDelivered(cardCampaign, forAppID: "YOUR Workspace ID")   
  ```

  ```objective-c Objective C wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  [[MoEngageSDKCards sharedInstance] cardDelivered:cardCamapigns forAppID:@"YOUR Workspace ID"];   
  ```
</CodeGroup>

### Impression

Call the method [*cardShown(\_:forAppID:)*](https://moengage.github.io/ios-api-reference/Classes/MoEngageSDKCards.html#/c:@M@MoEngageCards@objc\(cs\)MoEngageSDKCards\(im\)cardShown:forAppID:) when a specific card is visible on the screen.

<CodeGroup>
  ```swift Swift wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoEngageSDKCards.sharedInstance.cardShown(cardCampaign, forAppID: "YOUR Workspace ID")
  ```

  ```objective-c Objective C wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  [[MoEngageSDKCards sharedInstance] cardShown:cardCamapign forAppID:@"YOUR Workspace ID"];   
  ```
</CodeGroup>

### Click

Call the method [*cardClicked(\_:withWidgetID:forAppID:)*](https://moengage.github.io/ios-api-reference/Classes/MoEngageSDKCards.html#/c:@M@MoEngageCards@objc\(cs\)MoEngageSDKCards\(im\)cardClicked:withWidgetID:forAppID:) whenever a user clicks on a card, along with the card object widget identifier for the UI element clicked should also be passed.

<CodeGroup>
  ```swift Swift wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoEngageSDKCards.sharedInstance.cardClicked(cardCampaign, withWidgetID: widgetID);
  ```

  ```objective-c Objective C wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  [[MoEngageSDKCards sharedInstance] cardClicked:cardCamapigns withWidgetID:widgetID forAppID:@"YOUR Workspace ID"];   
  ```
</CodeGroup>

## Delete Card

Call the method [deleteCards(\_:forAppID:andCompletionBlock:)](https://moengage.github.io/ios-api-reference/Classes/MoEngageSDKCards.html#/c:@M@MoEngageCards@objc\(cs\)MoEngageSDKCards\(im\)deleteCards:forAppID:andCompletionBlock:) to delete a card by passing an array of [MoEngageCardCampaign](https://moengage.github.io/ios-api-reference/Classes/MoEngageCardCampaign.html) as parameter.

<CodeGroup>
  ```swift Swift wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoEngageSDKCards.sharedInstance.deleteCards([cards]) { isDeleted, accountMeta in
     print("Card deletion was \(isDeleted)")
  }
  ```

  ```objective-c Objective C wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  [[MoEngageSDKCards sharedInstance] deleteCards:[cardCamapigns] forAppID:nil andCompletionBlock:^(BOOL isDeleted, MoEngageAccountMeta * _Nullable accountMeta) {
     NSLog(@"Card deletion was %d", isDeleted);
  }];
  ```
</CodeGroup>

The above API has an overloaded method that accepts a list of cards to be deleted.

## Fetch Cards from the Server

Use the [*fetchCards(forAppID:withCompletion:)*](https://moengage.github.io/ios-api-reference/Classes/MoEngageSDKCards.html#/c:@M@MoEngageCards@objc\(cs\)MoEngageSDKCards\(im\)fetchCardsForAppID:withCompletion:) API to refresh cards from the MoEngage server if required, [*MoEngageCardData*](https://moengage.github.io/ios-api-reference/Classes/MoEngageCardData.html) is provided in callback with refreshed [*MoEngageCardCampaign*](https://moengage.github.io/ios-api-reference/Classes/MoEngageCardCampaign.html) in *cards* property and account meta-data [*MoEngageAccountMeta*](https://moengage.github.io/ios-api-reference/Classes/MoEngageAccountMeta.html) in *accountMeta*.

<CodeGroup>
  ```swift Swift wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  MoEngageSDKCards.sharedInstance.fetchCards { data in
     print("Refreshed cards: \(data?.cards) for account \(data?.accountMeta)")
  }
  ```

  ```objective-c Objective C wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
  [[MoEngageSDKCards sharedInstance] fetchCardsForAppID:nil withCompletion:^(MoEngageCardData * _Nullable data) {
     NSLog(@"Refreshed cards: %@ for account %@", data.cards, data.accountMeta);
  }];
  ```
</CodeGroup>

<Info>
  **Note**

  **The SDK caches cards and rate-limits server calls.** `fetchCards()  `**hit the server at most once every 5 minutes. If called more frequently, the existing cached cards are returned via the callback.**
</Info>

# FAQs

<AccordionGroup>
  <Accordion title="How do I handle near-real-time card updates (e.g., replacing a survey card after submission)?">
    For use cases requiring immediate UI updates based on user actions, we recommend the following execution pattern:

    1. **Initial Load**: On screen load, call `fetchCards()` to pull the latest cards from the server.
    2. **Trigger Update**: After the user action (like a survey submission), call `onCardSectionLoaded()`. This method returns a `hasUpdates` flag in its completion handler.
    3. **Refresh UI**: If `hasUpdates` is **true**, call `getCards(forCategory:)` or `getCardsData()` to retrieve the refreshed cards from local storage and update your view.
  </Accordion>

  <Accordion title="What is the difference between onCardSectionLoaded() and fetchCards()?">
    While both APIs involve fetching card data, they serve different purposes within the card lifecycle:

    | Feature      | `onCardSectionLoaded()`                                 | `fetchCards()`                                       |
    | :----------- | :------------------------------------------------------ | :--------------------------------------------------- |
    | **Use Case** | **Recommended** for standard card inbox screens.        | One-time force refresh outside the normal lifecycle. |
    | **Sync**     | Tracks impressions automatically.                       | Does not handle impression tracking.                 |
    | **Callback** | Provides a `hasUpdates` flag in the completion handler. | Standard success/error completion.                   |
  </Accordion>
</AccordionGroup>
