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 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:
- A native ad with video content. The ad’s
mediaView contains the video player. Other assets (title, body, icon, CTA) are overlaid on top.
- Video playback settings. Three properties on the loader disable fullscreen, start the video with sound, and hide media controls.
- 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 |
Native-ad adapter support and dependencies are documented on the adapter overview pages. See the Meta Audience Network adapter for current native-ad support.
Create a Layout and View Binder
res/layout/native_ad_layout.xml
<?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>
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()
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()
}
}
| 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:
val adView = CloudXNativeAdView(this, binder)
nativeAdLoader.loadAd(adView)
Flow B — Load first, render later (deferred rendering):
nativeAdLoader.loadAd()
override fun onNativeAdLoaded(adView: CloudXNativeAdView?, ad: CloudXAd) {
val newAdView = CloudXNativeAdView(this@YourActivity, binder)
nativeAdLoader.render(newAdView, ad)
container.addView(newAdView)
}
Handle Callbacks
// 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}")
}
Clean Up
Always destroy ads when you’re done with them:
// Destroy a specific loaded ad
nativeAdLoader.destroy(ad)
// Destroy the loader and all associated resources
nativeAdLoader.destroy()
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).