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.
Coming Soon — Native ads are not yet available for general use. This section is published for early integration partners only. The native ads API is subject to change before public release.
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).