Native ads let you monetize your app in a way that’s consistent with its existing design. The AppLovin MAX SDK gives you access to an ad’s individual assets. This way, you can design the ad layout to be consistent with the look and feel of your app. The SDK automatically handles image caching and metrics tracking. You can focus on how, when, and where to display ads.
AppLovin deprecated templates integration. If you integrate native ads into your app via templates, those ads will start no-filling at . AppLovin will remove support for templates integration in an upcoming SDK release.
Use this API if you have custom views and you want to manually load native ad assets into those views. This integration method involves three high-level steps:
To use the manual API, select Manual in the Create New Ad Unit screen:

You can bind custom UI components to the MAX SDK and render native ad assets into those components. This example demonstrates this with custom views created using xibs and unique tag IDs. You can also use this method if you create your views programmatically or with the Storyboard.
Per AppLovin’s policy, your ad must contain the Privacy Information icon.
This icon links to an important privacy notice.
You can bind to it via -[MANativeAdViewBinderBuilder setOptionsContentViewTag:].
Your custom view containing the UI components to bind must subclass from MANativeAdView.

Assign unique tag IDs to the subviews of your custom views.
You use these IDs in the next integration step.
The example image below sets the ID to 1234 for the title label.

Next, bind the subviews using unique tag IDs with an instance of MANativeAdViewBinder.
AppLovin does not guarantee a network will return certain assets.
#import "ExampleViewController.h"
#import <AppLovinSDK/AppLovinSDK.h>
⋮
@implementation ExampleViewController
⋮
- (MANativeAdView *)createNativeAdView
{
UINib *nativeAdViewNib = [UINib nibWithNibName: @"NativeCustomAdView" bundle: NSBundle.mainBundle];
MANativeAdView *nativeAdView = [nativeAdViewNib instantiateWithOwner: nil options: nil].firstObject;
MANativeAdViewBinder *binder = [[MANativeAdViewBinder alloc] initWithBuilderBlock:^(MANativeAdViewBinderBuilder *builder) {
builder.titleLabelTag = «title-label-tag»;
builder.bodyLabelTag = «body-lable-tag»;
builder.callToActionButtonTag = «call-to-action-label-tag»;
builder.iconImageViewTag = «icon-image-view-taG»;
builder.mediaContentViewTag = «media-view-content-view-tag»;
builder.starRatingContentViewTag = «star-rating-content-view-tag»;
builder.advertiserLabelTag = «advertiser-label-tag»;
builder.optionsContentViewTag = «options-content-view-tag»;
}];
[nativeAdView bindViewsWithAdViewBinder: binder];
return nativeAdView;
}
⋮
@end
class ExampleViewController : UIViewController
{
func createNativeAdView() -> MANativeAdView
{
let nativeAdViewNib = UINib(nibName: "NativeCustomAdView", bundle: Bundle.main)
let nativeAdView = nativeAdViewNib.instantiate(withOwner: nil, options: nil).first! as! MANativeAdView?
let adViewBinder = MANativeAdViewBinder.init(builderBlock: { (builder) in
builder.titleLabelTag = «title-label-tag»;
builder.bodyLabelTag = «body-lable-tag»;
builder.callToActionButtonTag = «call-to-action-label-tag»;
builder.iconImageViewTag = «icon-image-view-tag»;
builder.mediaContentViewTag = «media-view-content-view-tag»;
builder.starRatingContentViewTag = «star-rating-content-view-tag»;
builder.advertiserLabelTag = «advertiser-label-tag»;
builder.optionsContentViewTag = «options-content-view-tag»;
})
nativeAdView?.bindViews(with: adViewBinder)
}
}Follow each network’s guidance and bind their required ad assets. Otherwise, they may invalidate your impressions.
As of Google bidding and Google AdMob adapter version 9.11.0.6 and Google Ad Manager adapter version 9.11.0.5, take these steps to bind UI components. This ensures that any unassociated views in your custom native ad view are still clickable for those networks:
Add a wrapper view inside of MANativeAdView that contains all the ad assets.
Set its Custom Class to GADNativeAdView.

Give this wrapper view a unique Tag that is not used by other views.

Set a local extra parameter for the native ad loader that contains this tag value, with the corresponding key google_native_ad_view_tag.
For example, if the view’s tag is 1008:
-[setLocalExtraParameterForKey: "google_native_ad_view_tag" value: 1008]
setLocalExtraParameterForKey("google_native_ad_view_tag", value: 1008)To load a pre-rendered native ad, instantiate a MANativeAdLoader corresponding to your Ad Unit ID and call its loadAdIntoAdView method.
Implement and set the MANativeAdDelegate so that you are notified when your native ad’s load state changes.
To load a native ad, instantiate a MANativeAdLoader corresponding to your Ad Unit ID and call its loadAd method.
Implement and set the MANativeAdDelegate so that you are notified when your native ad’s load state changes.
Then use the MAAd returned in didLoadNativeAd:forAd: to render the ad view.
You can do this by calling MANativeAdLoader’s renderNativeAdView:withAd: method.
Show native ads in the ad expiration window of four hours. Impressions associated with ads shown outside this window are invalidated.
If you are no longer using a native ad, destroy its resources.
Do so by calling the destroy() method.
If you do not do this, the performance of your app degrades.
Below is an example of how you load and destroy a native ad, after you have bound the UI components from the previous step:
#import "ExampleViewController.h"
#import <AppLovinSDK/AppLovinSDK.h>
@interface ExampleViewController()<MANativeAdDelegate, MAAdRevenueDelegate>
@property (nonatomic, strong) UIView *nativeAdContainerView;
@property (nonatomic, strong) MANativeAdLoader *nativeAdLoader;
@property (nonatomic, strong) MAAd *loadedNativeAd;
@end
@implementation ExampleViewController
⋮
- (void)createNativeAdLoader
{
self.nativeAdLoader = [[MANativeAdLoader alloc] initWithAdUnitIdentifier: @"«ad-unit-ID»"];
self.nativeAdLoader.nativeAdDelegate = self;
self.nativeAdLoader.revenueDelegate = self;
}
- (void)loadNativeAd
{
[self.nativeAdLoader loadAdIntoAdView: [self createNativeAdView]];
}
- (void)didLoadNativeAd:(MANativeAdView *)nativeAdView forAd:(MAAd *)ad
{
// Cleanup any pre-existing native ad to prevent memory leaks.
if ( self.loadedNativeAd )
{
[self.nativeAdLoader destroyAd: self.loadedNativeAd];
}
// Save ad for cleanup.
self.loadedNativeAd = ad;
// Set to false if modifying constraints after adding the ad view to your layout
self.nativeAdContainerView.translatesAutoresizingMaskIntoConstraints = NO;
// Add the native ad view to your layout
[self.nativeAdContainerView addSubview: nativeAdView];
// Set ad view to span width and height of container and center the ad
[self.nativeAdContainerView addConstraint: [NSLayoutConstraint constraintWithItem: nativeAdView attribute: NSLayoutAttributeWidth r elatedBy: NSLayoutRelationEqual toItem: self.nativeAdContainerView attribute: NSLayoutAttributeWidth multiplier: 1 constant: 0]];
[self.nativeAdContainerView addConstraint: [NSLayoutConstraint constraintWithItem: nativeAdView attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: self.nativeAdContainerView attribute: NSLayoutAttributeHeight multiplier: 1 constant: 0]];
[self.nativeAdContainerView addConstraint: [NSLayoutConstraint constraintWithItem: nativeAdView attribute: NSLayoutAttributeCenterX relatedBy: NSLayoutRelationEqual toItem: self.nativeAdContainerView attribute: NSLayoutAttributeCenterX multiplier: 1 constant: 0]];
[self.nativeAdContainerView addConstraint: [NSLayoutConstraint constraintWithItem: nativeAdView attribute: NSLayoutAttributeCenterY relatedBy: NSLayoutRelationEqual toItem: self.nativeAdContainerView attribute: NSLayoutAttributeCenterY multiplier: 1 constant: 0]];
}
- (void)didFailToLoadNativeAdForAdUnitIdentifier:(NSString *)adUnitIdentifier withError:(MAError *)error
{
// Native ad load failed
// AppLovin recommends that you retry with exponentially higher delays up to a maximum delay
}
- (void)didClickNativeAd:(MAAd *)ad { }
- (void)didPayRevenueForAd:(MAAd *)ad { }
@end
class ExampleViewController : UIViewController
{
private var nativeAdContainerView: UIView!
private var nativeAdLoader: MANativeAdLoader?
private var loadedNativeAd: MAAd?
⋮
func createNativeAdLoader()
{
nativeAdLoader = MANativeAdLoader(adUnitIdentifier: "«ad-unit-ID»")
nativeAdLoader?.nativeAdDelegate = self;
nativeAdLoader?.revenueDelegate = self;
}
func loadNativeAd()
{
nativeAdLoader?.loadAd(into: createNativeAdView());
}
}
extension ExampleViewController: MANativeAdDelegate
{
func didLoadNativeAdView(_ nativeAdView: MANativeAdView?, for ad: MAAd)
{
if let nativeAd = loadedNativeAd
{
nativeAdLoader?.destroy(nativeAd)
}
loadedNativeAd = ad;
// Set to false if modifying constraints after adding the ad view to your layout
nativeAdContainerView.translatesAutoresizingMaskIntoConstraints = false
// Add the native ad view to your layout
guard let nativeAdView = nativeAdView else { return }
nativeContainerView.addSubview(nativeAdView)
// Set ad view to span width and height of container and center the ad
nativeAdContainerView.addConstraint(NSLayoutConstraint(item: nativeAdView, attribute: .width, relatedBy: .equal, toItem: nativeAdContainerView, attribute: .width, multiplier: 1, constant: 0))
nativeAdContainerView.addConstraint(NSLayoutConstraint(item: nativeAdView, attribute: .height, relatedBy: .equal, toItem: nativeAdContainerView, attribute: .height, multiplier: 1, constant: 0))
nativeAdContainerView.addConstraint(NSLayoutConstraint(item: nativeAdView, attribute: .centerX, relatedBy: .equal, toItem: nativeAdContainerView, attribute: .centerX, multiplier: 1, constant: 0))
nativeAdContainerView.addConstraint(NSLayoutConstraint(item: nativeAdView, attribute: .centerY, relatedBy: .equal, toItem: nativeAdContainerView, attribute: .centerY, multiplier: 1, constant: 0))
}
func didFailToLoadNativeAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError)
{
// Native ad load failed
// AppLovin recommends that you retry with exponentially higher delays up to a maximum delay
}
func didClickNativeAd(_ ad: MAAd) { }
}
extension ExampleViewController: MAAdRevenueDelegate
{
func didPayRevenue(for ad: MAAd) { }
}For AppLovin Exchange demand, the maximum numbers of characters allowed for Title, Description, and CTA are as follows:
| Asset | Maximum character count |
|---|---|
| Title | 50 characters |
| Description | 150 characters. You can add an ellipsis (…) after 149 characters, as the 150th character. |
| CTA | 15 characters |
For SDK-mediated networks, the network sets the maximum character counts.
The following code snippet shows how you get the media content aspect ratio of your native ad:
- (void)didLoadNativeAd:(MANativeAdView *)nativeAdView forAd:(MAAd *)ad
{
CGFloat aspectRatio = ad.nativeAd.mediaContentAspectRatio;
}
func didLoadNativeAd(_ nativeAdView: MANativeAdView?, for ad: MAAd)
{
if let nativeAd = ad.nativeAd
{
var aspectRatio = nativeAd.mediaContentAspectRatio
}
}Some networks do not provide media content aspect ratios, in which case the value is zero.
With the AppLovin MAX SDK you can access and render the star rating for the advertised app. The value, if available, is a floating point number in the range of [0.0, 5.0].
The MAX SDK automatically renders the stars in the container view that you designate as the star rating container. If the network does not provide the star rating, or the star rating is < 3, the SDK does not fill the star rating container view. You are responsible for adjusting your layout accordingly.
To retrieve the star rating for the current ad:
- (void)didLoadNativeAd:(MANativeAdView *)nativeAdView forAd:(MAAd *)ad
{
if ( ad.nativeAd.starRating < 3 )
{
// Star rating not available, or < 3 - hide star rating container view
return;
}
// Star rating available and >= 3 - show star rating container view
}
func didLoadNativeAd(_ nativeAdView: MANativeAdView?, for ad: MAAd)
{
if let nativeAd = ad.nativeAd
{
guard let starRating = nativeAd.starRating, starRating >= 3 else {
// Star rating not available, or < 3 - hide star rating container view
return
}
// Star rating available and >= 3 - show star rating container view
}
}Ad Placer automatically inserts native ads into your existing content stream using UITableView or UICollectionView.
To integrate this API, take the following high-level steps:
Per AppLovin’s policy, your ad must contain the Privacy Information icon.
This icon links to an important privacy notice.
You can bind to it via -[MANativeAdViewBinderBuilder setOptionsContentViewTag:].
Your custom view containing the UI components to bind must subclass from MANativeAdView.
Ad placer supports manual native ad layouts. See the “Manual” section above to learn how to configure your ad units. See Configure ad rendering settings below to learn how to configure the ad placer to support your layout.
Follow each network’s guidance and bind their required ad assets. Otherwise they may invalidate your impressions.
Create a MAAdPlacerSettings object with your ad unit identifier.
This object configures your ad placer and provides positioning information for ads in your feed.
MAAdPlacerSettings *settings = [MAAdPlacerSettings settingsWithAdUnitIdentifier: @"«ad-unit-ID»"];
let settings = MAAdPlacerSettings(adUnitIdentifier: "«ad-unit-ID»")Ad placer positions ads in your feed. It does this based on at least one of the following:
Configure ad positions by modifying MAAdPlacerSettings:
[settings addFixedPositions: [NSIndexPath indexPathForRow: 1 inSection: 0]];
settings.addFixedPosition(IndexPath(row: 1, section: 0)) [settings resetFixedPositions];
settings.resetFixedPositions()
settings.repeatingInterval = 5;
settings.repeatingInterval = 5You can configure your ad placer by adjusting settings in MAAdPlacerSettings:
maximumAdCountmaximumPreloadedAdCountChoose one of these two options when you configure your ad placer:
UITableView, MATableViewAdPlacer.
If it is based on a UICollectionView, use MACollectionViewAdPlacer.
The helper class wraps the original adapter to automatically render and insert ads into the feed.You must replace uses of the UITableView/UICollectionView properties and methods in your code with AppLovin’s category equivalents.
These exist in UITableView+MATableViewAdPlacer.h or UICollectionView+MACollectionViewAdPlacer.h.
These methods adjust index paths to account for the inserted ads.
They also inform the ad placer of changes to the content.
MAAdPlacer in your implementation.To configure your ad placer with MATableViewAdPlacer follow these instructions:
MATableViewAdPlacer with your table view and settings: self.adPlacer = [MATableViewAdPlacer placerWithTableView: self.tableView settings: settings];
adPlacer = MATableViewAdPlacer(tableView: tableView, settings: settings)UITableView properties and methods with the AppLovin category equivalents (prefixed with al_):
dataSourcedelegatedeleteRowsAtIndexPaths:withRowAnimation:deleteSections:withRowAnimation:dequeueReusableCellWithIdentifier:forIndexPath:deselectRowAtIndexPath:animated:endUpdatesindexPathForCell:indexPathForRowAtPoint:indexPathForSelectedRowindexPathsForRowsInRect:indexPathsForSelectedRowsindexPathsForVisibleRowsinsertRowsAtIndexPaths:withRowAnimation:insertSections:withRowAnimation:moveRowsAtIndexPaths:withRowAnimation:moveSections:withRowAnimation:performBatchUpdates:completion:rectForRowAtIndexPath:reloadDatareloadRowsAtIndexPaths:withRowAnimation:reloadSections:withRowAnimation:scrollToRowAtIndexPath:atScrollPosition:animated:selectRowAtIndexPath:animated:scrollPosition:visibleCellsloadAds to start loading ads.The following code shows how you load ads into a table view by using MATableViewAdPlacer:
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure table view
self.tableView.al_delegate = self;
self.tableView.al_dataSource = self;
// Configure ad placer and load ads
MAAdPlacerSettings *settings = [MAAdPlacerSettings settingsWithAdUnitIdentifier: @"«ad-unit-ID»"];
self.adPlacer = [MATableViewAdPlacer placerWithTableView: self.tableView settings: settings];
self.adPlacer.delegate = self;
[self.adPlacer loadAds];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.data.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView al_dequeueReusableCellWithIdentifier: @"YourCell" forIndexPath: indexPath];
cell.textLabel.text = self.data[indexPath.row];
return cell;
}
override func viewDidLoad()
{
super.viewDidLoad()
// Configure table view
tableView.al_delegate = self
tableView.al_dataSource = self
// Configure ad placer and load ads
let settings = MAAdPlacerSettings(adUnitIdentifier: "«ad-unit-ID»")
adPlacer = MATableViewAdPlacer(tableView: tableView, settings: settings)
adPlacer.delegate = self
adPlacer.loadAds()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.al_dequeueReusableCell(withIdentifier: "YourCell", for: indexPath)
cell.textLabel!.text = data[indexPath.row]
return cell
}To configure your ad placer with MACollectionViewAdPlacer follow these instructions:
MACollectionViewAdPlacer with your table view and settings: self.adPlacer = [MACollectionViewAdPlacer placerWithCollectionView: self.collectionView settings: settings];
adPlacer = MACollectionViewAdPlacer(collectionView: collectionView, settings: settings)UITableView properties and methods with the AppLovin category equivalents (prefixed with al_):
cellForItemAtIndexPath:dataSourcedelegatedeleteItemsAtIndexPaths:deleteSections:dequeueReusableCellWithIdentifier:forIndexPath:deselectItemAtIndexPath:animated:indexPathForCell:indexPathForItemAtPoint:indexPathsForSelectedItemsindexPathsForVisibleItemsinsertItemsAtIndexPaths:insertSections:layoutAttributesForItemAtIndexPath:moveItemsAtIndexPaths:moveSections:performBatchUpdates:completion:reloadDatareloadItemsAtIndexPaths:reloadSections:scrollToItemAtIndexPath:atScrollPosition:animated:selectedItemAtIndexPath:animated:scrollPosition:visibleCellsloadAds to start loading ads.The following code shows how you load ads into a table view by using MACollectionViewAdPlacer:
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure collection view
self.collectionView.al_delegate = self;
self.collectionView.al_dataSource = self;
// Configure ad placer and load ads
MAAdPlacerSettings *settings = [MAAdPlacerSettings settingsWithAdUnitIdentifier: @"«ad-unit-ID»"];
self.adPlacer = [MACollectionViewAdPlacer placerWithCollectionView: self.collectionView settings: settings];
self.adPlacer.delegate = self;
[self.adPlacer loadAds];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.data.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *cell = (MyCollectionViewCell *)[collectionView al_dequeueReusableCellWithIdentifier: @"YourCell" forIndexPath: indexPath];
cell.textLabel.text = self.data[indexPath.row];
return cell;
}
override func viewDidLoad()
{
super.viewDidLoad()
// Configure collection view
collectionView.al_delegate = self
collectionView.al_dataSource = self
// Configure ad placer and load ads
let settings = MAAdPlacerSettings(adUnitIdentifier: "«ad-unit-ID»")
adPlacer = MACollectionViewAdPlacer(collectionView: collectionView, settings: settings)
adPlacer.delegate = self
adPlacer.loadAds()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return data.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.al_dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! MyCollectionViewCell
cell.textLabel.text = data[indexPath.row]
return cell
}Set the nativeAdViewNib and nativeAdViewBinder properties on the ad placer before you load ads.
AppLovin recommends that you also set the adSize property.
This optimizes rendering.
All ad placers include optional delegate callbacks that can notify you events:
didLoadAdAtIndexPath:didRemoveAdsAtIndexPaths:didClickAd:didPayRevenueForAd: