Native Ads
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. So you can focus on how, when, and where to display ads.
Templates
The easiest way to integrate native ads into your app is via the templates API.
The AppLovin MAX SDK allows you to load an android.view.View
with the assets of the native ads pre-populated for you.
To use the templates API, select either a “Small” (360×120 dp) or “Medium” (300×250 dp) size template in the Create New Ad Unit screen.
The media view for “Small” templates fills one third of the template’s width, and spans the template’s height.
The media view for “Medium” templates spans the media content’s width and height, and preserves the content’s aspect ratio.
Select the size that best suits your needs.
Set a height for the native ad’s container view so that the media content can render properly.
The SDK automatically handles the view layouts for you.
Loading a Native Ad
To load a native ad, instantiate a MaxNativeAdLoader
corresponding to your ad unit.
Then call its loadAd()
method.
Implement MaxNativeAdLoadListener
so that you are notified when your native ad is ready.
Implement MaxAdListener
to be notified of other ad-related events.
Clean up any unused instances of native ads by calling the destroy()
method.
public class ExampleActivity extends Activity{ private MaxNativeAdLoader nativeAdLoader; private MaxAd nativeAd;
void createNativeAd() { FrameLayout nativeAdContainer = findViewById( R.id.native_ad_layout );
nativeAdLoader = new MaxNativeAdLoader( "«ad-unit-ID»", this ); nativeAdLoader.setNativeAdListener( new MaxNativeAdListener() { @Override public void onNativeAdLoaded(final MaxNativeAdView nativeAdView, final MaxAd ad) { // Clean up any pre-existing native ad to prevent memory leaks. if ( nativeAd != null ) { nativeAdLoader.destroy( nativeAd ); }
// Save ad for cleanup. nativeAd = ad;
// Add ad view to view. nativeAdContainer.removeAllViews(); nativeAdContainer.addView( nativeAdView ); }
@Override public void onNativeAdLoadFailed(final String adUnitId, final MaxError error) { // AppLovin recommends that you retry with exponentially higher delays up to a maximum delay }
@Override public void onNativeAdClicked(final MaxAd ad) { // Optional click callback } } );
nativeAdLoader.loadAd(); }
@Override protected void onDestroy() { // Destroy the native ad and native ad loader to prevent memory leaks. if ( nativeAd != null ) { nativeAdLoader.destroy( nativeAd ); }
nativeAdLoader.destroy(); super.onDestroy(); }}
class ExampleActivity : Activity(){ private lateinit var nativeAdLoader: MaxNativeAdLoader private var nativeAd: MaxAd? = null
fun createNativeAd() { val nativeAdContainer = findViewById(R.id.native_ad_layout) nativeAdLoader = MaxNativeAdLoader("«ad-unit-ID»", this) nativeAdLoader.setNativeAdListener(object : MaxNativeAdListener() {
override fun onNativeAdLoaded(nativeAdView: MaxNativeAdView?, ad: MaxAd) { // Clean up any pre-existing native ad to prevent memory leaks. if (nativeAd != null) { nativeAdLoader.destroy(nativeAd) }
// Save ad for cleanup. nativeAd = ad
// Add ad view to view. nativeAdContainer.removeAllViews() nativeAdContainer.addView( nativeAdView ) }
override fun onNativeAdLoadFailed(adUnitId: String, error: MaxError) { // AppLovin recommends that you retry with exponentially higher delays up to a maximum delay }
override fun onNativeAdClicked(ad: MaxAd) { // Optional click callback } }) nativeAdLoader.loadAd() }
override fun onDestroy() { // Destroy the native ad and native ad loader to prevent memory leaks. if (nativeAd != null) { nativeAdLoader.destroy(nativeAd) }
nativeAdLoader.destroy() super.onDestroy() }}
Asset Sizes
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.
How to Get the Media Content Aspect Ratio
The following code snippet shows how you get the media content aspect ratio of your native ad:
@Overridepublic 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 }}
Supported Adapter Versions
Ad Network | Adapter Version |
---|---|
BidMachine | 1.9.4.1 |
Google Ad Manager | 20.5.0.2 |
Google Bidding and Google AdMob | 20.5.0.2 |
InMobi | 10.0.5.3 |
LINE | 2021.5.11.9 |
Meta Audience Network | 6.8.0.3 |
Mintegral | 15.8.1.1 |
Moloco | 3.5.0.0 |
Pangle | 4.1.1.5.2 |
Smaato | 21.6.7.1 |
VK Ad Network | 5.14.4.2 |
Yandex | 5.3.0.1 |
Manual
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:
- Bind UI Components.
- Load the Native Ad.
- Destroy the Native Ad.
To use the manual API, select the Manual template in the Create New Ad Unit screen:
Bind UI Components
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. However, you could also use this method if you create your views programmatically.
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 MaxNativeAdViewBinder.Builder#setOptionsContentViewGroupId(…)
.
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="https://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) } ⋮}
Load the Native Ad
Load a Pre-Rendered Ad
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.
Load and Render Ad Separately
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)
.
Destroy the Native Ad
If you stop using a native ad, clean up its resources by calling the destroy()
method.
If you do not, the performance of your app will degrade 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) { // Clean up 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 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) { // Clean up 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 onDestroy() { // Destroy the native ad and native ad loader to prevent memory leaks. if (loadedNativeAd != null) { nativeAdLoader.destroy(loadedNativeAd) }
nativeAdLoader.destroy() super.onDestroy() } }}
Asset Sizes
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 on 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.
How to Get the Media Content Aspect Ratio
The following code snippet demonstratyes how to get the media content aspect ratio of your native ad:
@Overridepublic 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 }}
Supported Adapter Versions
Ad Network | Adapter Version |
---|---|
BidMachine | 1.9.4.1 |
Google Ad Manager | 20.5.0.2 |
Google Bidding and Google AdMob | 20.5.0.2 |
InMobi | 10.0.5.3 |
LINE | 2021.5.11.9 |
Meta Audience Network | 6.8.0.3 |
Mintegral | 15.8.1.1 |
Moloco | 3.5.0.0 |
Pangle | 4.1.1.5.2 |
Smaato | 21.6.7.1 |
VK Ad Network | 5.14.4.2 |
Yandex | 5.3.0.1 |
Star Rating
Starting with AppLovin MAX SDK v11.7.0, 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:
@Overridepublic 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 }}
Supported Adapter Versions (Star Rating)
Ad Network | Adapter Version |
---|---|
Google Ad Manager | 20.5.0.2 |
Google Bidding and Google AdMob | 20.5.0.2 |
InMobi | 10.1.2.3 |
Mintegral | 16.3.41.1 |
Ad Placer
Ad Placer automatically inserts native ads into your existing content stream using RecyclerView
.
To integrate this API, take the following high-level steps:
- Set up native ad layout.
- Create ad placer settings.
- Set up ad placer.
- Configure ad rendering settings.
- Optionally, set listener.
These steps are explained in greater detail below.
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 MaxNativeAdViewBinder.Builder#setOptionsContentViewGroupId(…)
.
1. Set Up Native Ad Layout
Ad placer supports either template or manual native ad layouts. See the “Templates” and “Manual” sections of this page to learn how to configure such ad layouts. See Configure Ad Rendering Settings below to learn how to set up the ad placer to support your layout.
2. Create Ad Placer Settings
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»")
Configure Ad Positions
Ad placer positions ads in your feed. It does this based on at least one of the following:
- a list of fixed index paths that indicate where to place ads
- a repeating interval at which to regularly insert ads
- Your ad placer inserts repeating ads after the last fixed position. If you do not set any fixed positions, your ad placer adds repeating ads after the first position in the stream. This interval value must be greater than or equal to 2. An interval value less than 2 disables the ad placer.
Configure ad positions by modifying MaxAdPlacerSettings
:
- To add a new fixed ad position (for example, at row 1):
settings.addFixedPosition( 3 );
settings.addFixedPosition( 3 )
- To remove existing fixed positions:
settings.resetFixedPositions();
settings.resetFixedPositions()
- To change the repeating interval (for example, to insert ads at every fifth position in the feed):
settings.setRepeatingInterval( 5 );
settings.repeatingInterval = 5
Additional Settings
You can further configure your ad placer by adjusting these settings in MaxAdPlacerSettings
:
maxAdCount
- Set this to the maximum number of ads in a stream (default=256). If a stream contains multiple sections, this determines the maximum number of ads per ad section.
maxPreloadedAdCount
- Set this to the maximum number of ads to preload for placement in a stream (default=4).
3. Set Up Ad Placer
Choose one of these two options when you set up your ad placer:
- If your feed is based on a
RecyclerView
, useMaxRecyclerAdapter
. The helper class wraps the original adapter. It automatically renders and inserts ads into the feed. You can access the underlying ad placer by callinggetAdPlacer()
. - You may prefer either to subclass or to directly use
MaxAdPlacer
. You may want to do this, for example, if your feed uses some other custom UI component
Using MaxRecyclerAdapter
To set up your ad placer with MaxRecyclerAdapter
follow these instructions:
- Initialize
MaxRecyclerAdapter
with your settings, original adapter, and activity:adAdapter = new MaxRecyclerAdapter( settings, adapter, this );
adAdapter = MaxRecyclerAdapter(settings, adapter, this)
- Set your recycler view’s adapter to the instantiated
MaxRecyclerAdapter
:recyclerView.setAdapter( adAdapter );
recyclerView.adapter = adAdapter
- Update your code to implement the following:
- Whenever you add or delete items from your stream, call the appropriate methods from your adapter.
These methods notify the ad placer of updates to your stream:
notifyItemInserted()
notifyItemRemoved()
notifyItemsInserted()
notifyItemsRemoved()
- If you register any data observers on your original adapter, register them on the
MaxRecyclerAdapter
instead. This way, they receive the adjusted position of content items after ad insertion. - If any other parts of your code depend on a content item’s position before ad insertion, convert the position to its original position.
Do this by calling
adAdapter.getOriginalPosition()
.
- Whenever you add or delete items from your stream, call the appropriate methods from your adapter.
These methods notify the ad placer of updates to your stream:
- Call
loadAds()
to start loading ads:adAdapter.loadAds();
adAdapter.loadAds()
The following code shows how you load ads into a recycler view by using MaxRecyclerAdapter
:
@Overridepublic 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();}
@Overridepublic 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()}
4. Configure Ad Rendering Settings
Templates
If you use a default template, the ad view automatically sizes to 360×120 for “Small” and 360×300 for “Medium” templates.
You can customize the rendered ad size by calling setAdSize
on the ad placer before you load ads.
For example, to set the ad size with a width of 300 and height of 200, make this call:
adAdapter.getAdPlacer().setAdSize( 300, 200 );
adAdapter.adPlacer.setAdSize(300, 200)
You may also pass a value of −1 (MATCH_PARENT
) for the width or height.
When you do so, the ad view fills the corresponding dimension of its parent view.
Manual
If you use a manual layout, you must call setNativeAdViewBinder
on the ad placer before you load ads.
Always set the ad size when you use manual templates.
This optimizes rendering.
5. Optionally Set Listener
The ad placer supports an optional listener that notifies you of events:
onAdLoaded()
onAdRemoved()
onAdClicked()
onAdRevenuePaid()