Native Ads

Load and render CloudX native ads in custom iOS layouts

Native ads expose individual creative assets—such as the title, body, icon, media, and call to action—so you can render them in a layout that matches your app. CloudX populates the bound views and delegates impression and click tracking to the winning network adapter.

The integration has three steps:

  1. Bind your layout’s UI components.
  2. Create a loader and load or render the native ad.
  3. Destroy the ad and loader when they are no longer needed.

Supported networks

Per-network Native support — including the Native Banner and Native MREC variants — is maintained in the Native ad format matrix. Adapter-specific dependencies and setup notes are documented on each adapter’s overview page.

1. Bind UI components

Create a CLXNativeAdView using a view binder that maps your custom subviews to asset roles. A network may omit optional assets, so make sure your layout can collapse or hide empty views.

The options container is required: CloudX uses it to display the network-provided AdChoices or privacy control.

- (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;
        builder.starRatingContentViewTag = CLXNativeAdViewTagStarRatingContentView;
    }];

    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;

Star rating

CloudX fills the star rating container only when the network provides a rating of 3.0 or higher; otherwise the container is left empty. Design your layout so an empty star rating container collapses or is hidden.

2. Create a loader

@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;
}

- (void)dealloc {
    [self.nativeAdLoader destroy];
}

@end

Load the ad

Choose one loading flow.

Load into a pre-built view

Use this flow when the destination view is already available. CloudX populates and registers the view before returning it through didLoadNativeAd.

CLXNativeAdView *adView = [self createNativeAdView];
[self.nativeAdLoader loadAdIntoAdView:adView];

Load and render separately

Use deferred rendering when you want to load the ad before its destination view exists. Call renderNativeAdView(...) before adding the view to your hierarchy.

[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

Loaded native ads expire one hour after load; didExpireNativeAd fires so you can destroy the expired ad and load a fresh one. In didFailToLoadNativeAd, avoid immediately retrying in a tight loop — retry after a delay or at the next natural display opportunity.

#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);
}

3. Destroy native ads

Destroy an individual ad when it is replaced or expires. Destroy the loader when its owning screen or component is finished. This releases network media views and prevents resources from accumulating over time.

// Destroy a specific loaded ad
[self.nativeAdLoader destroyAd:ad];

// Destroy the loader and all associated resources
[self.nativeAdLoader destroy];

Native ad assets

The CLXNativeAd object is available via ad.nativeAd in delegate callbacks:

PropertyTypeDescription
titleNSString?Headline text
bodyNSString?Body / description text
callToActionNSString?CTA button text (e.g., “Install Now”)
advertiserNSString?Advertiser name
iconCLXNativeAdImage?App icon image
mainImageCLXNativeAdImage?Main image (static creatives)
mediaViewUIView?Video/media player view (adapter-provided)
optionsViewUIView?AdChoices or options view (adapter-provided)
mediaContentAspectRatioCGFloatAspect ratio of the media content
starRatingNSNumber?App store rating (0–5)
isVideoContentBOOLWhether the creative is a video
videoDurationNSTimeIntervalVideo length in seconds (0 if unknown)
expiredBOOLWhether the ad has expired

Assets vary by network and creative. Treat nullable values as optional and hide the corresponding UI when an asset is unavailable. A mediaContentAspectRatio or videoDuration value of 0 means the network did not provide a usable value yet.

Native video metadata

Use isVideoContent to distinguish video from static native creatives. When it is true, videoDuration contains the duration in seconds if the network has made it available. Query duration after rendering for the most accurate value.