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
UICollectionView with pagingEnabled = YES and a vertical flow layout. Each cell is one Reel.
Reels API Surface
| Capability | CloudX API | Description |
|---|
| Detect video creative | ad.nativeAd.isVideoContent | Returns YES when the loaded creative is a video |
| Get video duration | ad.nativeAd.videoDuration | Duration of the video in seconds (0 if unknown) |
| Ad dismissed by user | didCloseNativeAd: delegate callback | Fires when the user reports or hides the ad via AdChoices |
| Disable fullscreen | loader.disableVideoFullScreen = YES | Prevents the video from entering fullscreen on tap |
| Start unmuted | loader.startVideoUnmuted = YES | Starts playback with sound on |
| Hide media controls | loader.hideVideoMediaControls = YES | Hides play/pause and mute/unmute controls |
The Reels video playback settings are adapter-dependent. In CloudX iOS SDK 3.4.0, they are honored by Meta native video creatives.
Native-ad adapter support and dependencies are documented on the adapter pages.
@interface YourViewController () <CLXNativeAdDelegate, CLXAdRevenueDelegate>
@property (nonatomic, strong) CLXNativeAdLoader *nativeAdLoader;
@end
@implementation YourViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.nativeAdLoader = [[CloudXCore shared] createNativeAdLoaderWithAdUnitIdentifier:@"your-native-ad-unit-id"];
self.nativeAdLoader.nativeAdDelegate = self;
self.nativeAdLoader.revenueDelegate = self;
self.nativeAdLoader.disableVideoFullScreen = YES;
self.nativeAdLoader.startVideoUnmuted = YES;
self.nativeAdLoader.hideVideoMediaControls = YES;
}
- (void)dealloc {
[self.nativeAdLoader destroy];
}
@end
| Property | Default | Reels Value | Description |
|---|
disableVideoFullScreen | NO | YES | Prevents the video from entering fullscreen when tapped |
startVideoUnmuted | NO | YES | Starts video playback with sound on |
hideVideoMediaControls | NO | YES | Hides play/pause and mute/unmute controls |
Set these properties before calling loadAd. They are ignored for static image creatives. For a Reels-style feed, set all three to YES.
Build a Native Ad Layout
Create a CLXNativeAdView using a view binder that maps your custom subviews to asset roles:
- (CLXNativeAdView *)createNativeAdView {
CLXNativeAdViewBinder *binder = [[CLXNativeAdViewBinder alloc] initWithBuilderBlock:^(CLXNativeAdViewBinderBuilder *builder) {
builder.titleLabelTag = CLXNativeAdViewTagTitleLabel;
builder.bodyLabelTag = CLXNativeAdViewTagBodyLabel;
builder.iconImageViewTag = CLXNativeAdViewTagIconImageView;
builder.callToActionButtonTag = CLXNativeAdViewTagCallToActionButton;
builder.mediaContentViewTag = CLXNativeAdViewTagMediaViewContainer;
builder.optionsContentViewTag = CLXNativeAdViewTagOptionsContentView;
builder.advertiserLabelTag = CLXNativeAdViewTagAdvertiserLabel;
}];
CLXNativeAdView *adView = [[CLXNativeAdView alloc] init];
[adView bindViewsWithViewBinder:binder];
return adView;
}
Alternatively, set outlets directly on the CLXNativeAdView:
CLXNativeAdView *adView = [[CLXNativeAdView alloc] init];
adView.titleLabel = myTitleLabel;
adView.bodyLabel = myBodyLabel;
adView.iconImageView = myIconImageView;
adView.callToActionButton = myCTAButton;
adView.mediaContentView = myMediaContainer;
adView.optionsContentView = myOptionsContainer;
adView.advertiserLabel = myAdvertiserLabel;
Load the Ad
Flow A — Load into a pre-built view:
CLXNativeAdView *adView = [self createNativeAdView];
[self.nativeAdLoader loadAdIntoAdView:adView];
Flow B — Load first, render later (deferred rendering):
[self.nativeAdLoader loadAd];
- (void)didLoadNativeAd:(nullable CLXNativeAdView *)nativeAdView forAd:(CLXAd *)ad {
CLXNativeAdView *adView = /* create your ad view */;
[self.nativeAdLoader renderNativeAdView:adView withAd:ad];
[self.view addSubview:adView];
}
Handle Callbacks
#pragma mark - CLXNativeAdDelegate (Required)
- (void)didLoadNativeAd:(nullable CLXNativeAdView *)nativeAdView forAd:(CLXAd *)ad {
NSLog(@"Native ad loaded from %@", ad.networkName);
if (ad.nativeAd.isVideoContent) {
NSLog(@"Video duration: %.1fs", ad.nativeAd.videoDuration);
}
if (nativeAdView) {
[self.view addSubview:nativeAdView];
}
}
- (void)didFailToLoadNativeAdForAdUnitIdentifier:(NSString *)adUnitId error:(CLXError *)error {
NSLog(@"Native ad failed to load: %@", error.localizedDescription);
}
- (void)didClickNativeAd:(CLXAd *)ad {
NSLog(@"Native ad clicked");
}
#pragma mark - CLXNativeAdDelegate (Optional)
- (void)didExpireNativeAd:(CLXAd *)ad {
NSLog(@"Native ad expired — destroy and reload");
[self.nativeAdLoader destroyAd:ad];
[self.nativeAdLoader loadAd];
}
- (void)didCloseNativeAd:(CLXAd *)ad {
NSLog(@"User dismissed the ad via AdChoices");
[self.nativeAdLoader destroyAd:ad];
}
#pragma mark - CLXAdRevenueDelegate
- (void)didPayRevenueForAd:(CLXAd *)ad {
NSLog(@"Native ad revenue: %@ from %@", ad.revenue, ad.networkName);
}
Clean Up
Always destroy ads when you’re done with them:
// Destroy a specific loaded ad
[self.nativeAdLoader destroyAd:ad];
// Destroy the loader and all associated resources
[self.nativeAdLoader destroy];
Native Ad Assets (CLXNativeAd)
The CLXNativeAd object is available via ad.nativeAd in delegate callbacks:
| Property | Type | Description |
|---|
title | NSString? | Headline text |
body | NSString? | Body / description text |
callToAction | NSString? | CTA button text (e.g., “Install Now”) |
advertiser | NSString? | Advertiser name |
icon | CLXNativeAdImage? | App icon image |
mainImage | CLXNativeAdImage? | Main image (static creatives) |
mediaView | UIView? | Video/media player view (adapter-provided) |
optionsView | UIView? | AdChoices or options view (adapter-provided) |
mediaContentAspectRatio | CGFloat | Aspect ratio of the media content |
starRating | NSNumber? | App store rating (0–5) |
isVideoContent | BOOL | Whether the creative is a video |
videoDuration | NSTimeInterval | Video length in seconds (0 if unknown) |
expired | BOOL | Whether the ad has expired |
Reels Feed Tips
- Use a
UICollectionView with pagingEnabled = YES and a vertical UICollectionViewFlowLayout with minimumLineSpacing = 0. Each cell should be full-screen.
- Call
prepareForReuse on the CLXNativeAdView when recycling cells.
- Create one
CLXNativeAdLoader per slot. Load ads sequentially.
- Destroy ads when no longer needed via
destroyAd:.