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

# Native Ads

> Integrate CloudX native ads and Reels-style native video experiences in Android apps

Native ads let you render ad creatives using your own UI components — title, body, icon, media, call-to-action — in your own layout. With video creatives and the right playback settings, native ads become full-screen vertical "Reels" (the same UX as Instagram Reels or TikTok).

A Reel is built from three things:

1. **A native ad with video content.** The ad's `mediaView` contains the video player. Other assets (title, body, icon, CTA) are overlaid on top.
2. **Video playback settings.** Three properties on the loader disable fullscreen, start the video with sound, and hide media controls.
3. **A full-screen paging container.** A `ViewPager2` with `android:orientation="vertical"`. Each page is one Reel.

#### Reels API Surface

| Capability            | CloudX API                                 | Description                                               |
| --------------------- | ------------------------------------------ | --------------------------------------------------------- |
| Detect video creative | `ad.nativeAd?.isVideoContent`              | Returns `true` when the loaded creative is a video        |
| Get video duration    | `ad.nativeAd?.videoDuration`               | Duration of the video in seconds (0.0 if unknown)         |
| Ad dismissed by user  | `onNativeAdClosed(ad)` listener callback   | Fires when the user reports or hides the ad via AdChoices |
| Disable fullscreen    | `loader.isVideoFullScreenDisabled = true`  | Prevents the video from entering fullscreen on tap        |
| Start unmuted         | `loader.isStartVideoUnmuted = true`        | Starts playback with sound on                             |
| Hide media controls   | `loader.isVideoMediaControlsHidden = true` | Hides play/pause and progress bar controls                |

<Note>
  Native-ad adapter support and dependencies are documented on the adapter overview pages. See the [Meta Audience Network adapter](/en/android/adapters/meta/overview) for current native-ad support.
</Note>

#### Create a Layout and View Binder

```xml res/layout/native_ad_layout.xml theme={null}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">

        <FrameLayout
            android:id="@+id/native_ad_options"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_vertical">

            <ImageView
                android:id="@+id/native_ad_icon"
                android:layout_width="48dp"
                android:layout_height="48dp" />

            <TextView
                android:id="@+id/native_ad_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_marginStart="8dp"
                android:textSize="16sp"
                android:textStyle="bold" />
        </LinearLayout>

        <TextView
            android:id="@+id/native_ad_body"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <FrameLayout
            android:id="@+id/native_ad_media_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:gravity="center_vertical">

            <TextView
                android:id="@+id/native_ad_advertiser"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:textColor="#888" />

            <Button
                android:id="@+id/native_ad_cta"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>

    </LinearLayout>
</FrameLayout>
```

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val binder = CloudXNativeAdViewBinder.Builder(R.layout.native_ad_layout)
      .setTitleTextViewId(R.id.native_ad_title)
      .setBodyTextViewId(R.id.native_ad_body)
      .setIconImageViewId(R.id.native_ad_icon)
      .setMediaContentViewGroupId(R.id.native_ad_media_container)
      .setCallToActionButtonId(R.id.native_ad_cta)
      .setOptionsContentViewGroupId(R.id.native_ad_options)
      .setAdvertiserTextViewId(R.id.native_ad_advertiser)
      .build()
  ```

  ```java Java theme={null}
  CloudXNativeAdViewBinder binder = new CloudXNativeAdViewBinder.Builder(R.layout.native_ad_layout)
      .setTitleTextViewId(R.id.native_ad_title)
      .setBodyTextViewId(R.id.native_ad_body)
      .setIconImageViewId(R.id.native_ad_icon)
      .setMediaContentViewGroupId(R.id.native_ad_media_container)
      .setCallToActionButtonId(R.id.native_ad_cta)
      .setOptionsContentViewGroupId(R.id.native_ad_options)
      .setAdvertiserTextViewId(R.id.native_ad_advertiser)
      .build();
  ```
</CodeGroup>

#### Create a Loader and Configure Video

<CodeGroup>
  ```kotlin Kotlin theme={null}
  class YourActivity : AppCompatActivity(), CloudXNativeAdListener, CloudXAdRevenueListener {
      private lateinit var nativeAdLoader: CloudXNativeAdLoader

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)

          nativeAdLoader = CloudX.createNativeAdLoader(this, "your-native-ad-unit-id")
          nativeAdLoader.nativeAdListener = this
          nativeAdLoader.revenueListener = this

          nativeAdLoader.isVideoFullScreenDisabled = true
          nativeAdLoader.isStartVideoUnmuted = true
          nativeAdLoader.isVideoMediaControlsHidden = true
      }

      override fun onDestroy() {
          super.onDestroy()
          nativeAdLoader.destroy()
      }
  }
  ```

  ```java Java theme={null}
  public class YourActivity extends AppCompatActivity implements CloudXNativeAdListener, CloudXAdRevenueListener {
      private CloudXNativeAdLoader nativeAdLoader;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);

          nativeAdLoader = CloudX.createNativeAdLoader(this, "your-native-ad-unit-id");
          nativeAdLoader.setNativeAdListener(this);
          nativeAdLoader.setRevenueListener(this);

          nativeAdLoader.setVideoFullScreenDisabled(true);
          nativeAdLoader.setStartVideoUnmuted(true);
          nativeAdLoader.setVideoMediaControlsHidden(true);
      }

      @Override
      protected void onDestroy() {
          super.onDestroy();
          if (nativeAdLoader != null) {
              nativeAdLoader.destroy();
          }
      }
  }
  ```
</CodeGroup>

| Property                     | Default | Reels Value | Description                                             |
| ---------------------------- | ------- | ----------- | ------------------------------------------------------- |
| `isVideoFullScreenDisabled`  | `false` | `true`      | Prevents the video from entering fullscreen when tapped |
| `isStartVideoUnmuted`        | `false` | `true`      | Starts video playback with sound on                     |
| `isVideoMediaControlsHidden` | `false` | `true`      | Hides play/pause and progress bar controls              |

Set these properties **before** calling `loadAd()`. They are ignored for static image creatives. For a Reels-style feed, set all three to `true`.

#### Load the Ad

**Flow A — Load into a pre-built view:**

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val adView = CloudXNativeAdView(this, binder)
  nativeAdLoader.loadAd(adView)
  ```

  ```java Java theme={null}
  CloudXNativeAdView adView = new CloudXNativeAdView(this, binder);
  nativeAdLoader.loadAd(adView);
  ```
</CodeGroup>

**Flow B — Load first, render later (deferred rendering):**

<CodeGroup>
  ```kotlin Kotlin theme={null}
  nativeAdLoader.loadAd()

  override fun onNativeAdLoaded(adView: CloudXNativeAdView?, ad: CloudXAd) {
      val newAdView = CloudXNativeAdView(this@YourActivity, binder)
      nativeAdLoader.render(newAdView, ad)
      container.addView(newAdView)
  }
  ```

  ```java Java theme={null}
  nativeAdLoader.loadAd();

  @Override
  public void onNativeAdLoaded(CloudXNativeAdView adView, CloudXAd ad) {
      CloudXNativeAdView newAdView = new CloudXNativeAdView(YourActivity.this, binder);
      nativeAdLoader.render(newAdView, ad);
      container.addView(newAdView);
  }
  ```
</CodeGroup>

#### Handle Callbacks

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // Required callbacks

  override fun onNativeAdLoaded(adView: CloudXNativeAdView?, ad: CloudXAd) {
      Log.d("CloudX", "Native ad loaded from ${ad.networkName}")

      ad.nativeAd?.let { nativeAd ->
          if (nativeAd.isVideoContent) {
              Log.d("CloudX", "Video duration: ${nativeAd.videoDuration}s")
          }
      }

      adView?.let { container.addView(it) }
  }

  override fun onNativeAdLoadFailed(adUnitId: String, error: CloudXError) {
      Log.e("CloudX", "Native ad failed to load: ${error.message}")
  }

  override fun onNativeAdClicked(ad: CloudXAd) {
      Log.d("CloudX", "Native ad clicked")
  }

  // Optional callbacks (default no-op)

  override fun onNativeAdExpired(ad: CloudXAd) {
      Log.d("CloudX", "Native ad expired — destroy and reload")
      nativeAdLoader.destroy(ad)
      nativeAdLoader.loadAd()
  }

  override fun onNativeAdClosed(ad: CloudXAd) {
      Log.d("CloudX", "User dismissed the ad via AdChoices")
      nativeAdLoader.destroy(ad)
  }

  // Revenue callback

  override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
      Log.d("CloudX", "Native ad revenue: ${cloudXAd.revenue} from ${cloudXAd.networkName}")
  }
  ```

  ```java Java theme={null}
  // Required callbacks

  @Override
  public void onNativeAdLoaded(CloudXNativeAdView adView, CloudXAd ad) {
      Log.d("CloudX", "Native ad loaded from " + ad.getNetworkName());

      CloudXNativeAd nativeAd = ad.getNativeAd();
      if (nativeAd != null && nativeAd.isVideoContent()) {
          Log.d("CloudX", "Video duration: " + nativeAd.getVideoDuration() + "s");
      }

      if (adView != null) {
          container.addView(adView);
      }
  }

  @Override
  public void onNativeAdLoadFailed(@NonNull String adUnitId, @NonNull CloudXError error) {
      Log.e("CloudX", "Native ad failed to load: " + error.getMessage());
  }

  @Override
  public void onNativeAdClicked(@NonNull CloudXAd ad) {
      Log.d("CloudX", "Native ad clicked");
  }

  // Optional callbacks (default no-op)

  @Override
  public void onNativeAdExpired(@NonNull CloudXAd ad) {
      Log.d("CloudX", "Native ad expired — destroy and reload");
      nativeAdLoader.destroy(ad);
      nativeAdLoader.loadAd();
  }

  @Override
  public void onNativeAdClosed(@NonNull CloudXAd ad) {
      Log.d("CloudX", "User dismissed the ad via AdChoices");
      nativeAdLoader.destroy(ad);
  }

  // Revenue callback

  @Override
  public void onAdRevenuePaid(@NonNull CloudXAd cloudXAd) {
      Log.d("CloudX", "Native ad revenue: " + cloudXAd.getRevenue() + " from " + cloudXAd.getNetworkName());
  }
  ```
</CodeGroup>

#### Clean Up

Always destroy ads when you're done with them:

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // Destroy a specific loaded ad
  nativeAdLoader.destroy(ad)

  // Destroy the loader and all associated resources
  nativeAdLoader.destroy()
  ```

  ```java Java theme={null}
  // Destroy a specific loaded ad
  nativeAdLoader.destroy(ad);

  // Destroy the loader and all associated resources
  nativeAdLoader.destroy();
  ```
</CodeGroup>

#### Native Ad Assets (CloudXNativeAd)

The `CloudXNativeAd` interface is available via `ad.nativeAd` in listener callbacks:

| Property                  | Type                   | Description                                  |
| ------------------------- | ---------------------- | -------------------------------------------- |
| `title`                   | `String?`              | Headline text                                |
| `body`                    | `String?`              | Body / description text                      |
| `callToAction`            | `String?`              | CTA button text (e.g., "Install Now")        |
| `advertiser`              | `String?`              | Advertiser name                              |
| `icon`                    | `CloudXNativeAdImage?` | App icon (as `Drawable` or `Uri`)            |
| `mainImage`               | `CloudXNativeAdImage?` | Main image (static creatives)                |
| `mediaView`               | `View?`                | Video/media player view (adapter-provided)   |
| `optionsView`             | `View?`                | AdChoices or options view (adapter-provided) |
| `mediaContentAspectRatio` | `Float`                | Aspect ratio of the media content            |
| `starRating`              | `Double?`              | App store rating (0–5)                       |
| `isVideoContent`          | `Boolean`              | Whether the creative is a video              |
| `videoDuration`           | `Double`               | Video length in seconds (0.0 if unknown)     |
| `isExpired`               | `Boolean`              | Whether the ad has expired                   |

#### Reels Feed Tips

* Use a `ViewPager2` with `android:orientation="vertical"`. Each item should be `MATCH_PARENT` in both dimensions.
* Call `prepareForReuse()` on the `CloudXNativeAdView` when recycling items.
* Create one `CloudXNativeAdLoader` per slot. Load ads sequentially.
* Destroy ads when no longer needed via `destroy(ad)`.
