Native Ads - Custom Rendering

See the code lab for an end-to-end walkthrough of implementing native custom rendering.

This guide shows you how to use the Google Mobile Ads SDK to implement DFP native ads in an Android application, as well as some important things to consider along the way.

Prerequisites

This guide assumes some working knowledge of the Google Mobile Ads SDK. If you haven't already done so, consider running through Get Started.

What's a native ad?

Native ads are advertisements presented to users via UI components that are native to the platform. They're shown using the same types of views with which you're already building your layouts, and can be formatted to match the visual design of the user experience in which they live. In coding terms, this means that when a native ad loads, your app receives a NativeAd object that contains its assets, and the app (rather than the SDK) is then responsible for displaying them.

System-defined native ad formats

There are two system-defined formats for native ads: app install and content. App install ads are represented by NativeAppInstallAd, and content ads are represented by NativeContentAd. These objects contain the assets for the native ad.

Custom native ad formats

In addition to the system-defined native formats, DFP publishers have the option of creating their own native ad formats by defining custom lists of assets. These are called custom native ad formats, and can be used with reserved ads. This enables publishers to pass arbitrary structured data to their apps. These ads are represented by the NativeCustomTemplateAd object.

Load system-defined ad formats

Native ads are loaded via the AdLoader class, which has its own Builder class to customize it during creation. By adding listeners to the AdLoader while building it, an app specifies which types of native ads it is ready to receive. The AdLoader then requests just those types.

Build an AdLoader

The following code demonstrates how to build an AdLoader that can load either an app install ad or a content ad in a single request:

AdLoader adLoader = new AdLoader.Builder(context, "/6499/example/native")
    .forAppInstallAd(new OnAppInstallAdLoadedListener() {
        @Override
        public void onAppInstallAdLoaded(NativeAppInstallAd appInstallAd) {
            // Show the app install ad.
        }
    })
    .forContentAd(new OnContentAdLoadedListener() {
        @Override
        public void onContentAdLoaded(NativeContentAd contentAd) {
            // Show the content ad.
        }
    })
    .withAdListener(new AdListener() {
        @Override
        public void onAdFailedToLoad(int errorCode) {
            // Handle the failure by logging, altering the UI, etc.
        }
    })
    .withNativeAdOptions(new NativeAdOptions.Builder()
            // Methods in the NativeAdOptions.Builder class can be
            // used here to specify individual options settings.
            .build())
    .build();

Prepare for the individual formats

The first methods above are responsible for preparing the AdLoader for a particular type of native ad:

forAppInstallAd - Calling this method configures the AdLoader to request app install ads. When one has loaded successfully, the listener object's onAppInstallAdLoaded method is called.

forContentAd - This method works the same as forAppInstallAd, but with content ads. When one has loaded successfully, the onContentAdLoaded method is invoked on the listener object.

Even when the ad loader has handlers for multiple native ad formats, the SDK only makes a single ad request. Google selects and returns the ad that maximizes publisher yield.

Use AdListener with an AdLoader

Also included during the creation of the AdLoader above is a function to set an AdListener: withAdListener. This is an optional step. The method takes an AdListener, which receives callbacks from the AdLoader when ad lifecycle events take place, as its lone parameter:

.withAdListener(new AdListener() {
  // AdListener callbacks like OnAdFailedToLoad, OnAdOpened, and so on,
  // can be overridden here.
})

There is one important difference between the way AdListeners work with native ads and the way they work with banners and interstitials. Because the AdLoader has its own, format-specific listeners (OnAppInstallAdLoadedListener and so on), to use when an ad has loaded, the onAdLoaded method from AdListener is not called when a native ad loads successfully.

NativeAdOptions

The last function included in the creation of the AdLoader above is another optional method, withNativeAdOptions:

.withNativeAdOptions(new NativeAdOptions.Builder()
        // Methods in the NativeAdOptions.Builder class can be
        // used here to specify individual options settings.
        .build()
)

The NativeAdOptions object allows apps to set specific options used in making the request. Its Builder class offers these methods to use when creating an instance:

setReturnUrlsForImageAssets - Image assets for native ads are returned via instances of NativeAd.Image, which holds a Drawable and a Uri. If this option is set to false (which is the default), the SDK fetches image assets automatically and populates both the Drawable and the Uri for you. If it's set to true, however, the SDK instead populates just the Uri field, allowing you to download the actual images at your discretion.

setImageOrientation - Some creatives have multiple available images to match different device orientations. Calling this method with one of the NativeAdOptions orientation constants (ORIENTATION_PORTRAIT, ORIENTATION_LANDSCAPE, or ORIENTATION_ANY) requests images for a particular orientation. If this method is not called, the default value of ORIENTATION_ANY is used.

If you use setImageOrientation to specify a preference for landscape or portrait image orientation, the SDK places images matching that orientation first in image asset arrays and place non-matching images after them. Since some ads only have one orientation available, make sure that your apps can handle both landscape and portrait images.

setRequestMultipleImages - Some image assets contain a series of images rather than just one. By setting this value to true, your app indicates that it's prepared to display all the images for any assets that have more than one. By setting it to false (default) your app instructs the SDK to provide just the first image for any assets that contain a series.

If withNativeAdOptions is not called at all when creating an AdLoader, the default value for each option is used.

setAdChoicesPlacement()

The AdChoices overlay is set to the top right corner by default. Apps can change which corner this overlay is rendered in by setting this property to one of the following:

  • ADCHOICES_TOP_LEFT
  • ADCHOICES_TOP_RIGHT
  • ADCHOICES_BOTTOM_RIGHT
  • ADCHOICES_BOTTOM_LEFT

Load the native ad

Once you've finished building an AdLoader, call its loadAd method to request an ad:

adLoader.loadAd(new PublisherAdRequest.Builder().build());

Note that AdLoaders use the same PublisherAdRequest class as banners and interstitials. You can use that class's methods to add targeting information just as you would with other ad types.

A single AdLoader can make multiple requests, but only if they're done one at a time. When reusing an AdLoader, make sure you wait for each request to finish before calling loadAd again to begin the next. If you need to request multiple ads in parallel, you can always use multiple AdLoader objects.

When to request ads

Applications displaying native ads are free to request them in advance of when they'll actually be displayed. In many cases, this is the recommended practice. An app displaying a list of items with native ads mixed in, for example, can load native ads for the whole list, knowing that some will be shown only after the user scrolls the view and some may not be displayed at all.

While prefetching ads is a great technique, it's important that publishers not keep old ads around forever without displaying them. Any native ad objects that have been held without display for longer than an hour should be discarded and replaced with new ads from a new request.

Display system-defined ad formats

When a native ad loads, the SDK invokes the listener for the corresponding ad format. Your app is then responsible for displaying the ad, though it doesn't necessarily have to do so immediately. To make displaying system-defined ad formats easier, the SDK offers some useful resources.

The ad view classes

For each of the system-defined formats, there is a corresponding ad view class: NativeAppInstallAdView for app install ads, and NativeContentAdView for content ads. These ad view classes are ViewGroups that publishers should use as the roots for native ads of the corresponding format. A single NativeContentAdView, for example, corresponds to a single content ad. Each of the views used to display that ad's assets (the ImageView that displays the screenshot asset, for instance) should be children of the NativeContentAdView object.

The view hierarchy for a content ad that used a RelativeLayout to display its asset views might look like this:

The ad view classes also provide methods used to register the view used for each individual asset, and one to register the NativeAd object itself. Registering the views in this way allows the SDK to automatically handle tasks such as:

  • recording clicks
  • recording impressions (when the first pixel is visible on the screen)
  • displaying the AdChoices overlay for native backfill creatives (currently in beta release to a limited group of publishers)

AdChoices overlay

An AdChoices overlay is added an ad view by the SDK when a backfill ad is returned. If your app uses native ads backfill, please leave space in your preferred corner of your native ad view for the automatically inserted AdChoices logo. Also, it's important that the AdChoices overlay be easily seen, so choose background colors and images appropriately. For more information on the overlay's appearance and function, see the native backfill implementation guidelines.

Code Example

These are the steps for displaying a system-defined native ad format:

  1. Create an instance of the correct ad view class.
  2. For each ad asset to be displayed:
    1. Populate the asset view with the asset in the native ad object.
    2. Register the asset view with the ViewGroup class.
  3. Register the native ad object with the ViewGroup class.

Here is an example function that displays a NativeContentAd:

private void displayContentAd(ViewGroup parent, NativeContentAd contentAd) {
    // Inflate a layout and add it to the parent ViewGroup.
    LayoutInflater inflater = (LayoutInflater) parent.getContext()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    NativeContentAdView adView = (NativeContentAdView) inflater
            .inflate(R.layout.my_content_ad, parent);

    // Locate the view that will hold the headline, set its text, and call the
    // NativeContentAdView's setHeadlineView method to register it.
    TextView headlineView = (TextView) adView.findViewById(R.id.contentad_headline);
    headlineView.setText(contentAd.getHeadline());
    adView.setHeadlineView(headlineView);

    ...
    // Repeat the above process for the other assets in the NativeContentAd
    // using additional view objects (Buttons, ImageViews, etc).
    ...

    // Call the NativeContentAdView's setNativeAd method to register the
    // NativeAdObject.
    adView.setNativeAd(contentAd);

    // Place the AdView into the parent.
    parent.addView(adView);
}

Let's take a look at the individual tasks:

Inflate the layout

LayoutInflater inflater = (LayoutInflater) parent.getContext()
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
NativeContentAdView adView = (NativeContentAdView) inflater
        .inflate(R.layout.my_content_ad, parent);

In this example, we're inflating an XML layout that contains views for displaying a content ad, and then locating a reference to the NativeContentAdView that is its root element. This is a great way to get started, but note that you could also reuse an existing NativeContentAdView if there's one in your fragment or activity, or even create an instance dynamically without using a layout file.

Populate and register the asset views

TextView headlineView = (TextView) adView.findViewById(R.id.contentad_headline);
headlineView.setText(contentAd.getHeadline());
adView.setHeadlineView(headlineView);

Here we're locating the view that is used to display the headline, setting its text using the string asset provided by contentAd, and then registering it with the NativeContentAdView object. This process of locating the view, setting its value, and registering it with the ad view class should be repeated for each of the assets provided by the native ad object.

Register the native ad object

adView.setNativeAd(contentAd);

This final step registers the native ad object with the view that's responsible for displaying it.

Native video

In addition to images, text, and numbers, some native ads contain video assets. Not every ad includes a video asset, and apps are not required to display them.

To simplify the configuration and display of video, the Mobile Ads SDK provides the following video-related classes:

VideoOptions

The VideoOptions class allows apps to configure how native video assets should behave. VideoOptions objects should be assigned to a NativeAdOptions object that's used when constructing the AdLoader:

VideoOptions videoOptions = new VideoOptions.Builder()
        .setStartMuted(false)
        .build();

NativeAdOptions adOptions = new NativeAdOptions.Builder()
        .setVideoOptions(videoOptions)
        .build();

AdLoader adLoader = new AdLoader.Builder(this, "/6499/example/native")
        .forAppInstallAd( ... )
        .forContentAd( ... )
        .withNativeAdOptions(adOptions)
        .build();

The VideoOptions.Builder class currently offers one method, setStartMuted(), which tells the SDK whether video assets should start in a muted state. The default value is true.

MediaView

Video assets are displayed to users via MediaView. This is a View that can be defined in an XML layout or constructed dynamically, and should be placed within the view hierarchy of a NativeAdView, just like any other asset view.

Unlike other asset views, however, apps do not need to manually populate a MediaView with its asset. The SDK handles this automatically:

  • If a video asset is available, it is buffered and starts playing inside the MediaView.
  • If the ad does not contain a video asset, the first image asset is downloaded and placed inside the MediaView instead.

While apps that don't intend to display video assets aren't required to include a MediaView in their layouts, it's recommended that they do.

VideoController

The VideoController class is used to retrieve information about video assets. Apps can get a reference to the controller from a NativeAppInstallAd by calling the getVideoController() method:

VideoController vc = myAppInstallAd.getVideoController();

This method always returns a VideoController object, even when no video asset is present in the ad.

VideoController offers these methods for querying video state:

  • hasVideoContent() - Returns true if the ad has a video asset, and false if it doesn't.
  • getAspectRatio() - Returns the aspect ratio of the video (width/height), or zero if no video asset is present.

Apps can also use the VideoController.VideoLifecycleCallbacks class to get notifications when events occur in the lifecycle of a video asset:

VideoController vc = nativeAppInstallAd.getVideoController();

vc.setVideoLifecycleCallbacks(new VideoController.VideoLifecycleCallbacks() {
    public void onVideoEnd() {
        // Here apps can take action knowing video playback is finished.
        // It's always a good idea to wait for playback to complete before
        // replacing or refreshing a native ad, for example.
        super.onVideoEnd();
    }
});

Load custom native ad formats

Build an AdLoader

Like their system-defined counterparts, custom native ad formats are loaded using the AdLoader class:

AdLoader adLoader = new AdLoader.Builder(context, "/6499/example/native")
    .forCustomTemplateAd("10063170",
      new NativeCustomTemplateAd.OnCustomTemplateAdLoadedListener() {
          @Override
          public void onCustomTemplateAdLoaded(NativeCustomTemplateAd ad) {
              // Show the custom template and record an impression.
          }
      },
      new NativeCustomTemplateAd.OnCustomClickListener() {
          @Override
          public void onCustomClick(NativeCustomTemplateAd ad, String s) {
              // Handle the click action
          }
      })
    .withAdListener( ... )
    .withNativeAdOptions( ... )
    .build();

Much like the forAppInstallAd method configures the AdLoader to request an app install ad, the forCustomTemplateAd method sets it to handle custom template ads. There are three parameters passed into the method:

  • The template ID of the custom template the AdLoader should request. Each custom native ad format has a template ID value associated with it. This parameter indicates which template your app wants the AdLoader to request.
  • An OnCustomTemplateAdLoadedListener to be invoked when an ad has loaded successfully.
  • An optional OnCustomClickListener to be invoked when the user taps or clicks on the ad. For more on this listener, see the "Handling clicks and impressions" section below.

Because a single ad unit can be set up to serve more than one creative template, forCustomTemplateAd can be called multiple times with unique template IDs in order to prepare the ad loader for more than one possible custom native ad format.

Template IDs

The template IDs used to uniquely refer to native custom ad formats can be found in the DFP UI under the Creatives > Native Ad Formats section of the Delivery tab:

Each custom native ad format's template ID appears beneath its name. Clicking on one of the names brings you to a details screen showing information about the template's fields:

From here, individual fields can be added, edited, and removed. Note the Variable ID column to the right. These IDs are used to access the individual assets, and are discussed more in the next section.

Display custom native ad formats

Custom native ad formats differ from system-defined ones in that publishers have the power to define their own "templates," or lists of assets, that make up an ad. Therefore, the process for displaying one differs from system-defined formats in a few ways:

  1. Because the NativeCustomTemplateAd class is meant to handle any of the custom native ad formats you define in DFP, it doesn't have named "getters" for assets. Instead, it offers methods like getText and getImage that take the Variable ID of a template field as a parameter.
  2. There is no dedicated ad view class like NativeContentAdView to use with NativeCustomTemplateAd. You are free to use a FrameLayout, RelativeLayout, or whatever makes sense for your user experience.
  3. Because there is no dedicated ViewGroup class, you do not need to register any of the views you use to display the ad's assets. This saves a few lines of code when displaying the ad, but also means you'll need to do a little extra work to handle clicks later on.

Here's an example function that displays a NativeCustomTemplateAd:

public void displayCustomTemplateAd (ViewGroup parent,
                                     NativeCustomTemplateAd customTemplateAd) {
    // Inflate a layout and add it to the parent ViewGroup.
    LayoutInflater inflater = (LayoutInflater) parent.getContext()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View adView = inflater.inflate(R.layout.custom_template_ad, parent);

    // Locate the TextView that will hold the value for "Headline" and
    // set its text.
    TextView myHeadlineView = (TextView) adView.findViewById(R.id.headline);
    myHeadlineView.setText(customTemplateAd.getText("Headline"));

    // Locate the ImageView that will hold the value for "MainImage" and
    // set its drawable.
    Button myMainImageView = (ImageView) adView.findViewById(R.id.main_image);
    myMainImageView.setImageDrawable(
            nativeCustomTemplateAd.getImage("MainImage").getDrawable());

    ...
    // Continue locating views and displaying assets until finished.
    ...
}

Native video for custom native ad formats

When creating a new native ad format, you have the option to make the format eligible for video.

Simply check the box to make your format video eligible, and when you make a new creative for this format, you'll have an option to provide a video asset.

In your app implementation, you can use NativeCustomTemplateAd.getVideoMediaView() to get the video's view. Then add this view to your view hierarchy. If the ad doesn't have video content, make alternate plans to show the ad without a video.

The example below checks if the ad has video content, and displays an image in its place if a video is not available:

// Called when a custom native ad loads.
@Override
public void onCustomTemplateAdLoaded(NativeCustomTemplateAd ad) {
    VideoController vc = ad.getVideoController();
    // Assumes you have a FrameLayout in your view hierarchy with the id media_placeholder.
    FrameLayout mediaPlaceholder = (FrameLayout) findViewById(R.id.media_placeholder);
    if (vc.hasVideoContent()) {
        mediaPlaceholder.addView(ad.getVideoMediaView());
    } else {
        ImageView mainImage = new ImageView(this);
        mainImage.setAdjustViewBounds(true);
        // Assumes your native format has an image asset with the name MainImage.
        mainImage.setImageDrawable(ad.getImage("MainImage").getDrawable());
        mediaPlaceholder.addView(mainImage);
    }
}

See VideoController for more information on how you can customize a custom native ad's video experience.

Download the DFP Custom Rendering example for a working example of native video in action.

Custom native ad format clicks and impressions

With custom native ad formats, your app is responsible for recording impressions and reporting click events to the SDK.

Record impressions

To record an impression for a custom template ad, call the recordImpression method on the corresponding NativeCustomTemplateAd:

myCustomTemplateAd.recordImpression();

If your app accidentally calls the method twice for the same ad, the SDK automatically prevents a duplicate impression from being recorded for a single request.

Report clicks

To report to the SDK that a click has occurred on an asset view, call the performClick method on the corresponding NativeCustomTemplateAd and pass in the name of the asset that was clicked. For example, if you had an asset in your custom template called "MainImage" and wanted to report a click on the ImageView that corresponded to that asset, your code would look like this:

myCustomTemplateAd.performClick("MainImage");

Note that you don't need to call this method for every view associated with your ad. If you had another field called "Caption" that was meant to be displayed but not clicked or tapped on by the user, your app would not need to call performClick for that asset's view.

Respond to custom click actions

When a click is performed on a custom template ad, there are three possible responses from the SDK, attempted in this order:

  1. Invoke the OnCustomClickListener from AdLoader, if one was provided.
  2. For each of the ad's deep link URLs, attempt to locate a content resolver and start the first one that resolves.
  3. Open a browser and navigate to the ad's traditional Destination URL.

The forCustomTemplateAd method accepts an OnCustomClickListener. If you pass a listener object in, the SDK instead invokes its onCustomClick method and takes no further action. If you pass a null value as the listener, however, the SDK falls back to the deeplink and/or destination URLs registered with the ad.

Custom Click listeners allow your app to decide the best action to take in response to a click, whether it's updating the UI, launching a new activity, or merely logging the click. Here's an example that simply logs that a click took place:

AdLoader adLoader = new AdLoader.Builder(context, "/6499/example/native")
    .forCustomTemplateAd("10063170",
      new NativeCustomTemplateAd.OnCustomTemplateAdLoadedListener() {
        // Display the ad.
      },
      new NativeCustomTemplateAd.OnCustomClickListener() {
          @Override
          public void onCustomClick(NativeCustomTemplateAd ad, String assetName) {
            Log.i("MyApp", "A custom click just happened for " + assetName + "!");
          }
      }).build();

At first, it might seem strange that custom click listeners exist. After all, your app just told the SDK that a click happened, so why should the SDK turn around and report that to the app?

This flow of information is useful for a few reasons, but most importantly it allows the SDK to remain in control of the response to the click. It can automatically ping third-party tracking URLs that have been set for the creative, for example, and handle other tasks behind the scenes, without any additional code.

Destroy an ad

When you are done showing your native ad, you should destroy it so that the ad is properly garbage collected. This is especially important if you're using Native Video. Use the following code to destroy an ad:

if (nativeAd.getVideoController().hasVideoContent()) {
    adView.setMediaView(null);
    // Warning: If you are reusing this native ad view for another ad,
    // make sure to destroy the ad before configuring your new ad with the
    // view. Otherwise, this call to setNativeAd() will override the
    // setNativeAd() call you made with your new ad.
    adView.setNativeAd(nativeAd);
}
nativeAd.destroy();

Test native ad code

Direct-sold ads

If you'd like to test out what direct-sold native ads are like, you can make use of this DFP ad unit ID:

/6499/example/native

It's configured to serve sample app install and content ads, as well as a custom native ad format with the following assets:

  • Headline (text)
  • MainImage (image)
  • Caption (text)

The template ID for the custom native ad format is 10063170.

Native backfill ads

Ad Exchange backfill is currently in beta release to a limited group of publishers.

To test the behavior of native backfill ads, use this DFP ad unit:

/6499/example/native-backfill

It serves sample app install and content ads that include the AdChoices overlay.

Remember to update your code to refer to your actual ad unit and template IDs before going live!

Send feedback about...

SDK for DFP Users on Android
Need help? Visit our support page.