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 caches images and tracks metrics. 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. Then you can render native ad assets into those components. The example below demonstrates this with custom views that you create with the Layout Editor and unique view IDs. You can also use this method if you create your views programmatically.
To accord with 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 MaxNativeAdViewBinder.Builder#setOptionsContentViewGroupId(…).
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/icon_image_view"
… />
<LinearLayout
android:id="@+id/ad_options_view"
… />
<TextView
android:id="@+id/title_text_view"
… />
<FrameLayout
android:id="@+id/star_rating_view"
… />
<TextView
android:id="@+id/advertiser_textView"
… />
<TextView
android:id="@+id/body_text_view"
… />
<FrameLayout
android:id="@+id/media_view_container"
… />
<Button
android:id="@+id/cta_button"
… />
</androidx.constraintlayout.widget.ConstraintLayout>
Next, bind the subviews using unique view IDs with an instance of MaxNativeAdViewBinder.
AppLovin does not guarantee a network will return certain assets.
public class ExampleActivity
extends Activity
implements MaxAdRevenueListener
{
⋮
private MaxNativeAdView createNativeAdView()
{
MaxNativeAdViewBinder binder = new MaxNativeAdViewBinder.Builder( R.layout.native_custom_ad_view )
.setTitleTextViewId( R.id.title_text_view )
.setBodyTextViewId( R.id.body_text_view )
.setStarRatingContentViewGroupId( R.id.star_rating_view )
.setAdvertiserTextViewId( R.id.advertiser_textView )
.setIconImageViewId( R.id.icon_image_view )
.setMediaContentViewGroupId( R.id.media_view_container )
.setOptionsContentViewGroupId( R.id.options_view )
.setCallToActionButtonId( R.id.cta_button )
.build();
return new MaxNativeAdView( binder, this );
}
⋮
}class ExampleActivity : Activity(), MaxAdRevenueListener
{
⋮
private fun createNativeAdView(): MaxNativeAdView
{
val binder: MaxNativeAdViewBinder =
MaxNativeAdViewBinder.Builder(R.layout.native_custom_ad_view)
.setTitleTextViewId(R.id.title_text_view)
.setBodyTextViewId(R.id.body_text_view)
.setStarRatingContentViewGroupId(R.id.star_rating_view )
.setAdvertiserTextViewId(R.id.advertiser_textView)
.setIconImageViewId(R.id.icon_image_view)
.setMediaContentViewGroupId(R.id.media_view_container)
.setOptionsContentViewGroupId(R.id.options_view)
.setCallToActionButtonId(R.id.cta_button)
.build()
return MaxNativeAdView(binder, this)
}
⋮
}Follow each network’s guidance and bind their required ad assets. Otherwise, they may invalidate your impressions.
To load a pre-rendered native ad, first instantiate a MaxNativeAdLoader corresponding to your Ad Unit ID.
Then call its loadAd(MaxNativeAdView) method.
Implement and set the MaxNativeAdLoadListener so that you are notified when your native ad’s load state changes.
To load a native ad, first instantiate a MaxNativeAdLoader corresponding to your Ad Unit ID.
Then call its loadAd() method.
Implement and set the MaxNativeAdLoadListener so that you are notified when your native ad’s load state changes.
Then use the MaxAd returned in onNativeAdLoaded to render the ad view.
You can do this by calling MaxNativeAdLoader.render(MaxNativeAdView, MaxAd).
Native ads are expected to be shown in the ad expiration window of four hours. Impressions associated with ads that show outside of this window are invalidated.
If you stop using a native ad, destroy its resources by calling the destroy() method.
If you do not, the performance of your app degrades over time.
Below is an example of how you load and destroy a native ad.
This takes place after you have bound the UI components from the previous step.
public class ExampleActivity
extends Activity
implements MaxAdRevenueListener
{
private ViewGroup nativeAdContainerView;
private MaxNativeAdLoader nativeAdLoader;
private MaxAd loadedNativeAd;
⋮
private void createNativeAdLoader()
{
nativeAdLoader = new MaxNativeAdLoader( "«ad-unit-ID»", this );
nativeAdLoader.setRevenueListener( this );
nativeAdLoader.setNativeAdListener( new NativeAdListener() );
}
private void loadNativeAd()
{
nativeAdLoader.loadAd( createNativeAdView() );
}
@Override
public void onAdRevenuePaid(final MaxAd ad) { }
private class NativeAdListener
extends MaxNativeAdListener
{
@Override
public void onNativeAdLoaded(final MaxNativeAdView nativeAdView, final MaxAd nativeAd)
{
// Destroy any pre-existing native ad to prevent memory leaks.
if ( loadedNativeAd != null )
{
nativeAdLoader.destroy( loadedNativeAd );
}
// Save ad for cleanup.
loadedNativeAd = nativeAd;
nativeAdContainerView.removeAllViews();
nativeAdContainerView.addView( nativeAdView );
}
@Override
public void onNativeAdLoadFailed(final String adUnitId, final MaxError error)
{
// Native ad load failed.
// AppLovin recommends retrying with exponentially higher delays up to a maximum delay.
}
@Override
public void onNativeAdClicked(final MaxAd nativeAd) { }
@Override
public void onNativeAdExpired(final MaxAd nativeAd)
{
// Native ad has expired, which can occur after four hours.
// Load the next ad.
nativeAdLoader.loadAd( createNativeAdView() );
}
}
@Override
protected void onDestroy()
{
// Destroy the native ad and native ad loader to prevent memory leaks.
if ( loadedNativeAd != null )
{
nativeAdLoader.destroy( loadedNativeAd );
}
nativeAdLoader.destroy();
super.onDestroy();
}
}class ExampleActivity : Activity(), MaxAdRevenueListener
{
private val nativeAdContainerView: ViewGroup? = null
private var nativeAdLoader: MaxNativeAdLoader? = null
private var loadedNativeAd: MaxAd? = null
⋮
private fun createNativeAdLoader()
{
nativeAdLoader = MaxNativeAdLoader("«ad-unit-ID»", this)
nativeAdLoader?.setRevenueListener(this)
nativeAdLoader?.setNativeAdListener(NativeAdListener())
}
private fun loadNativeAd()
{
nativeAdLoader?.loadAd(createNativeAdView())
}
override fun onAdRevenuePaid(ad: MaxAd) {}
private inner class NativeAdListener : MaxNativeAdListener()
{
override fun onNativeAdLoaded(nativeAdView: MaxNativeAdView?, nativeAd: MaxAd)
{
// Destroy any pre-existing native ad to prevent memory leaks.
if (loadedNativeAd != null)
{
nativeAdLoader?.destroy(loadedNativeAd)
}
// Save ad for cleanup.
loadedNativeAd = nativeAd
nativeAdContainerView?.removeAllViews()
nativeAdContainerView?.addView(nativeAdView)
}
override fun onNativeAdLoadFailed(adUnitId: String, error: MaxError)
{
// Native ad load failed.
// AppLovin recommends retrying with exponentially higher delays up to a maximum delay.
}
override fun onNativeAdClicked(nativeAd: MaxAd) {}
override fun onNativeAdExpired(nativeAd: MaxAd)
{
// Native ad has expired, which can occur after four hours.
// Load the next ad.
nativeAdLoader?.loadAd(createNativeAdView())
}
}
override fun onDestroy()
{
// Destroy the native ad and native ad loader to prevent memory leaks.
if (loadedNativeAd != null)
{
nativeAdLoader?.destroy(loadedNativeAd)
}
nativeAdLoader?.destroy()
super.onDestroy()
}
}AppLovin recommends that you incorporate as many of the native elements as are appropriate in the context of what the rest of your app looks like. These may include the Title and Media View or Icon. If you give the user more information, this helps them decide whether they want to click the ad.
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 demonstrates how to get the media content aspect ratio of your native ad:
@Override
public void onNativeAdLoaded(final MaxNativeAdView adView, final MaxAd ad)
{
MaxNativeAd nativeAd = ad.getNativeAd();
if ( nativeAd != null )
{
float aspectRatio = nativeAd.getMediaContentAspectRatio();
}
}override fun onNativeAdLoaded(nativeAdView: MaxNativeAdView?, ad: MaxAd) {
val nativeAd = ad.nativeAd
if (nativeAd != null) {
val aspectRatio = nativeAd.mediaContentAspectRatio
}
}Some networks do not provide media content aspect ratios. For those networks, the value is zero.
You can access and render the star rating for the advertised app. This value, when 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 if 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:
@Override
public void onNativeAdLoaded(final MaxNativeAdView adView, final MaxAd ad)
{
MaxNativeAd nativeAd = ad.getNativeAd();
if ( nativeAd != null )
{
Double starRating = nativeAd.getStarRating();
if ( starRating == null || starRating < 3 )
{
// Star rating not available, or < 3 - hide star rating container view
return;
}
// Star rating available and >= 3 - show star rating container view
}
}override fun onNativeAdLoaded(nativeAdView: MaxNativeAdView?, ad: MaxAd) {
val nativeAd = ad.nativeAd
if (nativeAd != null) {
val starRating = nativeAd.starRating
if (starRating == null || starRating < 3) {
// 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 RecyclerView.
To integrate this API, take the following high-level steps:
This page explains these steps in greater detail below.
To accord with 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 MaxNativeAdViewBinder.Builder#setOptionsContentViewGroupId(…).
Ad placer supports manual native ad layouts. See the “Manual” section of this page to learn how to configure such ad layouts. 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 MaxAdPlacerSettings object with your ad unit identifier.
This object configures your ad placer and provides positioning information for ads in your feed.
MaxAdPlacerSettings settings = new MaxAdPlacerSettings( "«ad-unit-ID»" );val settings = MaxAdPlacerSettings("«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 MaxAdPlacerSettings:
settings.addFixedPosition( 3 );
settings.addFixedPosition( 3 )
settings.resetFixedPositions();
settings.resetFixedPositions()
settings.setRepeatingInterval( 5 );
settings.repeatingInterval = 5
You can further configure your ad placer by adjusting these settings in MaxAdPlacerSettings:
maxAdCountmaxPreloadedAdCountChoose one of these two options when you configure your ad placer:
RecyclerView, use MaxRecyclerAdapter.
The helper class wraps the original adapter.
It automatically renders and inserts ads into the feed.
You can access the underlying ad placer by calling getAdPlacer().MaxAdPlacer.
You may want to do this, for example, if your feed uses some other custom UI componentTo configure your ad placer with MaxRecyclerAdapter follow these instructions:
MaxRecyclerAdapter with your settings, original adapter, and activity:adAdapter = new MaxRecyclerAdapter( settings, adapter, this );
adAdapter = MaxRecyclerAdapter(settings, adapter, this)
MaxRecyclerAdapter:recyclerView.setAdapter( adAdapter );
recyclerView.adapter = adAdapter
notifyItemInserted()notifyItemRemoved()notifyItemsInserted()notifyItemsRemoved()MaxRecyclerAdapter instead.
This way, they receive the adjusted position of content items after ad insertion.adAdapter.getOriginalPosition().loadAds() to start loading ads:adAdapter.loadAds();
adAdapter.loadAds()
The following code shows how you load ads into a recycler view by using MaxRecyclerAdapter:
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate( savedInstanceState );
// Create your own recycler view and original adapter
⋮
// Configure ad adapter
MaxAdPlacerSettings settings = new MaxAdPlacerSettings( "«ad-unit-ID»" );
settings.setRepeatingInterval( 5 );
adAdapter = new MaxRecyclerAdapter( settings, originalAdapter, this );
// Optionally, register listener
adAdapter.setListener( this );
// Configure recycler view and load ads
recyclerView.setAdapter( adAdapter );
adAdapter.loadAds();
}
@Override
public void onDestroy()
{
adAdapter.destroy();
super.onDestroy();
}override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
// Create your own recycler view and original adapter
⋮
// Configure ad adapter
val settings = MaxAdPlacerSettings("«ad-unit-ID»")
settings.repeatingInterval = 5
adAdapter = MaxRecyclerAdapter(settings, originalAdapter, this)
// Optionally, register listener
adAdapter.listener = this
// Configure recycler view and load ads
recycler.adapter = adAdapter
adAdapter.loadAds()
}
override fun onDestroy()
{
adAdapter.destroy()
super.onDestroy()
}Call setNativeAdViewBinder on the ad placer before you load ads.
Always set the ad size.
This optimizes rendering.
The ad placer supports an optional listener that notifies you of events:
onAdLoaded()onAdRemoved()onAdClicked()onAdRevenuePaid()