Native Ads - Custom Rendering

This guide will show you how to use the Google Mobile Ads SDK to implement DFP native ads in an iOS 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 our Get Started guide.

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 classes you already use in your storyboards, and can be formatted to match your app's visual design. When a native ad loads, your app will receive a native ad 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 GADNativeAppInstallAd, and content ads are represented by GADNativeContentAd. Instances of the classes 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 for direct-sold native ads. Custom native ad formats enable publishers to pass arbitrary structured data to their apps. These ads are represented by the GADNativeCustomTemplateAd class.

Custom native ad formats are also referred to as custom template ads. This is because publishers define their own "templates" (lists of asset names and types) for their custom native ad formats. This will become clearer as you progress through the guide, but for right now just remember that "custom template ads" and "custom native ad formats" both refer to the same kind of ad.

Load system-defined native ad formats

Native ads are loaded via GADAdLoader objects, which send messages to their delegates according to the GADAdLoaderDelegate protocol.

Initialize a GADAdLoader

The following code demonstrates how to initialize a GADAdLoader for an app install ad:

Swift

adLoader = GADAdLoader(adUnitID: "/6499/example/native",
    rootViewController: self,
    adTypes: [ ... ad type constants ... ],
    options: [ ... ad loader options objects ... ])
adLoader.delegate = self

Objective-C

self.adLoader = [[GADAdLoader alloc]
      initWithAdUnitID:@"/6499/example/native"
    rootViewController:rootViewController
               adTypes:@[ ... ad type constants ... ]
               options:@[ ... ad loader options objects ... ]];
self.adLoader.delegate = self;

The adTypes array parameter allows your app to pass in constants that specify which native formats it wants to request. The array should contain one or more of the following constants:

  • kGADAdLoaderAdTypeNativeAppInstall
  • kGADAdLoaderAdTypeNativeContent
  • kGADAdLoaderAdTypeNativeCustomTemplate

Request the native ad

Once your GADAdLoader is initialized, call its loadRequest method to request an ad:

Swift

adLoader.load(DFPRequest())

Objective-C

[self.adLoader loadRequest:[DFPRequest request]];

The loadRequest method in GADAdLoader accepts the same DFPRequest objects as banners and interstitials. You can use request objects to add targeting information, just as you would with other ad types.

When reusing a GADAdLoader, make sure you wait for each request to finish before calling loadRequest again to begin the next.

Knowing when loading has finished

When an app calls loadRequest, it can expect to receive the results of the request via calls to any of these delegate methods:

  • adLoader:didReceiveNativeAppInstallAd: in GADNativeAppInstallAdLoaderDelegate
  • adLoader:didReceiveNativeContentAd: in GADNativeContentAdLoaderDelegate
  • adLoader:didReceiveNativeCustomTemplateAd: in GADNativeCustomTemplateAdLoaderDelegate
  • adLoader:didFailToReceiveAdWithError: in GADAdLoaderDelegate

A request for a single ad will result in one call to one of those methods. A request for multiple ads will result in at least one callback to the above methods, but no more than the maximum number of ads requested.

In addition, GADAdLoaderDelegate offers the adLoaderDidFinishLoading callback. This delegate method indicates an ad loader has finished loading ads and no other ads or errors will be reported for the request. Here's an example of how to use it when loading multiple native ads at one time:

Swift

class ViewController: UIViewController, GADNativeAppInstallAdLoaderDelegate,
    GADNativeContentAdLoaderDelegate {

  var adLoader: GADAdLoader!

  override func viewDidLoad() {
    super.viewDidLoad()

    let multipleAdsOptions = GADMultipleAdsAdLoaderOptions()
    multipleAdsOptions.numberOfAds = 5

    adLoader = GADAdLoader(adUnitID: YOUR_AD_UNIT_ID, rootViewController: self,
        adTypes: [kGADAdLoaderAdTypeNativeContent,
                  kGADAdLoaderAdTypeNativeAppInstall,
                  kGADAdLoaderAdTypeNativeCustomTemplate],
        options: [multipleAdsOptions])
    adLoader.delegate = self
    adLoader.load(DFPRequest())
  }

  func adLoader(_ adLoader: GADAdLoader,
                didReceive nativeCustomTemplateAd: GADNativeCustomTemplateAd) {
    // A custom template ad has loaded and can be displayed.
  }

  func adLoader(_ adLoader: GADAdLoader,
                didReceive nativeAppInstallAd: GADNativeAppInstallAd) {
    // An app install ad has loaded and can be displayed.
  }

  func adLoader(_ adLoader: GADAdLoader,
                didReceive nativeContentAd: GADNativeContentAd) {
      // A content ad has loaded and can be displayed.
  }

  func adLoaderDidFinishLoading(_ adLoader: GADAdLoader) {
      // The adLoader has finished loading ads, and a new request can be sent.
  }
}

Objective-C

@interface ViewController () 

@property(nonatomic, strong) GADAdLoader *adLoader;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  GADMultipleAdsAdLoaderOptions *multipleAdsOptions =
      [[GADMultipleAdsAdLoaderOptions alloc] init];
  multipleAdsOptions.numberOfAds = 5;

  self.adLoader = [[GADAdLoader alloc] initWithAdUnitID:YOUR_AD_UNIT_ID
          rootViewController:self
                     adTypes:@[kGADAdLoaderAdTypeNativeContent,
                               kGADAdLoaderAdTypeNativeAppInstall,
                               kGADAdLoaderAdTypeNativeCustomTemplate]
                     options:@[multipleAdsOptions]];
  self.adLoader.delegate = self;
  [self.adLoader loadRequest:[DFPRequest request]];
  }
}

- (void)adLoader:(GADAdLoader *)adLoader
    didReceiveNativeCustomTemplateAd:(GADNativeCustomTemplateAd *) nativeCustomTemplateAd {
   // A custom template ad has loaded and can be displayed.
}

- (void)adLoader:(GADAdLoader *)adLoader
    didReceiveNativeAppInstallAd:(GADNativeAppInstallAd *) nativeAppInstallAd {
   // An app install ad has loaded and can be displayed.
}

- (void)adLoader:(GADAdLoader *)adLoader
    didReceiveNativeContentAd:(GADNativeContentAd *) nativeContentAd {
   // A content ad has loaded and can be displayed.
}

- (void)adLoaderDidFinishLoading:(GADAdLoader *) adLoader {
  // The adLoader has finished loading ads, and a new request can be sent.
}

@end

GADAdLoaderDelegate protocols

For each native ad format you request, the ad loader delegate needs to implement a corresponding protocol:

GADNativeAppInstallAdLoaderDelegate

This protocol includes a message that's sent to the delegate when an app install ad has loaded:

Swift

public func adLoader(_ adLoader: GADAdLoader,
    didReceive nativeAppInstallAd: GADNativeAppInstallAd)

Objective-C

- (void)adLoader:(GADAdLoader *)adLoader
    didReceiveNativeAppInstallAd:(GADNativeAppInstallAd *)nativeAppInstallAd;

GADNativeContentAdLoaderDelegate

This one defines a message sent when a content ad has loaded:

Swift

public func adLoader(_ adLoader: GADAdLoader,
    didReceive nativeContentAd: GADNativeContentAd)

Objective-C

- (void)adLoader:(GADAdLoader *)adLoader
    didReceiveNativeContentAd:(GADNativeContentAd *)nativeContentAd;

Handle a failed request

The above protocols extend the GADAdLoaderDelegate protocol, which defines a message sent when ads fail to load:

Swift

public func adLoader(_ adLoader: GADAdLoader,
    didFailToReceiveAdWithError error: GADRequestError)

Objective-C

- (void)adLoader:(GADAdLoader *)adLoader
    didFailToReceiveAdWithError:(GADRequestError *)error;

You can use the GADRequestError object to determine the cause of the error.

Native ad options

The last parameter included in the creation of the GADAdLoader above is an optional array of objects:

Swift

adLoader = GADAdLoader(adUnitID: "/6499/example/native",
    rootViewController: self,
    adTypes: [ ... ad type constants ... ],
    options: [ ... ad loader options objects ... ])

Objective-C

self.adLoader = [[GADAdLoader alloc]
      initWithAdUnitID:@"/6499/example/native"
    rootViewController:rootViewController
               adTypes:@[ ... ad type constants ... ]
               options:@[ ... ad loader options objects ... ]];

GADNativeAdImageAdLoaderOptions contains properties relating to images in native ads. Apps can control how a GADAdLoader handles native ad image assets by creating a GADNativeAdImageAdLoaderOptions object, setting its properties, and passing it in during initialization.

GADNativeAdImageAdLoaderOptions has the following properties:

disableImageLoading - Image assets for native ads are returned via instances of GADNativeAdImage, which contains image and imageURL properties. If disableImageLoading is set to false (default), the SDK will fetch image assets automatically and populate both the image and the imageURL properties for you. If it's set to true, however, the SDK will only populate imageURL, allowing you to download the actual images at your discretion.

preferredImageOrientation - Some creatives have multiple available images to match different device orientations. Apps can request images for a particular orientation by setting this property to one of the orientation constants:

  • GADNativeAdImageAdLoaderOptionsOrientationAny
  • GADNativeAdImageAdLoaderOptionsOrientationLandscape
  • GADNativeAdImageAdLoaderOptionsOrientationPortrait

If this method is not called, the default value of GADNativeAdImageAdLoaderOptionsOrientationAny will be used.

shouldRequestMultipleImages - Some image assets will 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 no GADAdLoaderOptions objects are passed in when initializing a GADAdLoader, the default value for each option will be used.

GADNativeAdViewOptions

GADNativeAdViewAdOptions contains the preferredAdChoicesPosition property, which publishers can use to specify the location where the AdChoices icon should be placed. The icon can appear at any corner of the ad, and defaults to GADAdChoicesPositionTopRightCorner.

Here's an example showing how to place the AdChoices icon in the top left corner of an ad:

Swift

let adViewOptions = GADNativeAdViewAdOptions()
adViewOptions.preferredAdChoicesPosition = .topLeftCorner
adLoader = GADAdLoader(adUnitID: "/6499/example/native",
    rootViewController: self,
    adTypes: [ kGADAdLoaderAdTypeNativeAppInstall, kGADAdLoaderAdTypeNativeContent],
    options: [ adViewOptions ])

Objective-C

GADNativeAdViewAdOptions *adViewOptions = [[GADNativeAdViewAdOptions alloc] init];
adViewOptions.preferredAdChoicesPosition = GADAdChoicesPositionTopLeftCorner;
self.adLoader = [[GADAdLoader alloc]
      initWithAdUnitID:@"/6499/example/native"
    rootViewController:self
               adTypes:@[ kGADAdLoaderAdTypeNativeAppInstall, kGADAdLoaderAdTypeNativeContent ]
               options:@[ adViewOptions ]];

GADMultipleAdsAdLoaderOptions

GADMultipleAdsAdLoaderOptions objects allow publishers to instruct an ad loader to load multiple ads in a single request. Ads loaded in this way are guaranteed to be unique.

GADMultipleAdsAdLoaderOptions has a single property:

numberOfAds - The number of ads the ad loader should attempt to return for the request. By default this value is 1, and it's capped at a maximum of 5 (even if an app requests more ads, at most 5 will be returned). The actual number of ads returned is not guaranteed, but will be between zero and numberOfAds.

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 a system-defined native ad format

When a native ad loads, your app will receive a native ad object via one of the GADAdLoaderDelegate protocol messages. 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: GADNativeAppInstallAdView for app install ads, and GADNativeContentAdView for content ads. These ad view classes are UIViews that publishers should use to display native ads of the corresponding format. A single GADNativeAppInstallAdView, for example, can display a single instance of a GADNativeAppInstallAd. Each UIView used to display that ad's assets should be children of that GADNativeAppInstallAdView object.

If you were displaying an app install ad in a UITableView, for example, the view hierarchy for one of the cells might look like this:

The ad view classes also provide IBOutlets used to register the view used for each individual asset, and a method to register the GADNativeAd object itself. Registering the views and native ad object 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

The AdChoices overlay

For indirect native ads (delivered via DFP backfill or through Ad Exchange or AdSense), an AdChoices overlay is added by the SDK. Please leave space in your preferred corner of your native ad view for the automatically inserted AdChoices logo. Also, make sure the AdChoices overlay is placed on content that allows the icon to be easily seen. For more information on the overlay's appearance and function, see the native backfill implementation guidelines.

Code Example

Let's take a look at how to display native ads using views loaded dynamically from xib files. This can be a very useful approach when using GADAdLoaders configured to request multiple formats.

Lay out UIViews in the xib file

The first step is to lay out the UIViews that will display native ad assets. You can do this in the Interface Builder as you would when creating any other xib file. Here's how the layout for an app install ad might look:

And here's how the layout for a content ad might look:

Note the Custom Class value in the top right of both of the images. It's set to GADNativeAppInstallAdView and GADNativeContentAdView. These are the ad view classes that are used to display a GADNativeAppInstallAd and GADNativeContentAd. For system-defined formats, you'll need to use the ad view class that matches the ad format you intend the layout to show.

Once the views are in place and you've assigned the correct ad view class to the layout, you need to link the ad view's asset outlets to the UIViews you've created. Here's how you might link the ad view's asset outlets to the UIViews created for an app install ad:

And here's how you might link the ad view's asset outlets to the UIViews created for a content ad:

In the outlet panel, the outlets in GADNativeAppInstallAdView and GADNativeContentAdView have been linked to the UIViews laid out in the Interface Builder. This lets the SDK know which UIView displays which asset, and also which assets are clickable.

Display the ad

Once the layout is complete and the outlets are linked, the last step is to add code to your app that displays an ad once it has loaded. Here's a method to display an app install ad in the view defined above:

Swift

// Mark: - GADNativeAppInstallAdLoaderDelegate

func adLoader(_ adLoader: GADAdLoader,
    didReceive nativeAppInstallAd: GADNativeAppInstallAd) {
  // Create and place the ad in the view hierarchy.
  let appInstallAdView = Bundle.main.loadNibNamed("NativeAppInstallAdView", owner: nil,
      options: nil)?.first as! GADNativeAppInstallAdView
  // TODO: Make sure to add the GADNativeAppInstallAdView to the view hierarchy.

  // Associate the app install ad view with the app install ad object. This is
  // required to make the ad clickable.
  appInstallAdView.nativeAppInstallAd = nativeAppInstallAd

  // Populate the app install ad view with the app install ad assets.
  // Some assets are guaranteed to be present in every app install ad.
  (appInstallAdView.headlineView as! UILabel).text = nativeAppInstallAd.headline
  (appInstallAdView.iconView as! UIImageView).image = nativeAppInstallAd.icon?.image
  (appInstallAdView.bodyView as! UILabel).text = nativeAppInstallAd.body
  (appInstallAdView.imageView as! UIImageView).image =
      (nativeAppInstallAd.images?.first as! GADNativeAdImage).image
  (appInstallAdView.callToActionView as! UIButton).setTitle(
      nativeAppInstallAd.callToAction, for: UIControlState.normal)

  // Other assets are not, however, and should be checked first.
  let starRatingView = appInstallAdView.starRatingView
  if let starRating = nativeAppInstallAd.starRating {
    (starRatingView as! UIImageView).image = imageOfStarsFromStarRating(starRating)
    starRatingView?.isHidden = false
  } else {
    starRatingView?.isHidden = true
  }

  let storeView = appInstallAdView.storeView
  if let store = nativeAppInstallAd.store {
    (storeView as! UILabel).text = store
    storeView?.isHidden = false
  } else {
    storeView?.isHidden = true
  }

  let priceView = appInstallAdView.priceView
  if let price = nativeAppInstallAd.price {
    (priceView as! UILabel).text = price
    priceView?.isHidden = false
  } else {
    priceView?.isHidden = true
  }

  // In order for the SDK to process touch events properly, user interaction
  // should be disabled on all views associated with the GADNativeAppInstallAdView.
  // Since UIButton has userInteractionEnabled set to true by default, views of
  // this type must explicitly set userInteractionEnabled to false.
  (appInstallAdView.callToActionView as! UIButton).isUserInteractionEnabled = false
}

Objective-C

#pragma mark GADNativeAppInstallAdLoaderDelegate implementation

- (void)adLoader:(GADAdLoader *)adLoader
    didReceiveNativeAppInstallAd:(GADNativeAppInstallAd *)nativeAppInstallAd {
  // Create and place ad in view hierarchy.
  GADNativeAppInstallAdView *appInstallAdView =
      [[[NSBundle mainBundle] loadNibNamed:@"NativeAppInstallAdView"
                                     owner:nil
                                   options:nil] firstObject];
  // TODO: Make sure to add the GADNativeAppInstallAdView to the view hierarchy.

  // Associate the app install ad view with the app install ad object. This is required to make the
  // ad clickable.
  appInstallAdView.nativeAppInstallAd = nativeAppInstallAd;

  // Populate the app install ad view with the app install ad assets.
  // Some assets are guaranteed to be present in every app install ad.
  ((UILabel *)appInstallAdView.headlineView).text = nativeAppInstallAd.headline;
  ((UIImageView *)appInstallAdView.iconView).image = nativeAppInstallAd.icon.image;
  ((UILabel *)appInstallAdView.bodyView).text = nativeAppInstallAd.body;
  ((UIImageView *)appInstallAdView.imageView).image =
      ((GADNativeAdImage *)[nativeAppInstallAd.images firstObject]).image;
  [((UIButton *)appInstallAdView.callToActionView)setTitle:nativeAppInstallAd.callToAction
                                                  forState:UIControlStateNormal];

  // Other assets are not, however, and should be checked first.
  if (nativeAppInstallAd.starRating) {
    ((UIImageView *)appInstallAdView.starRatingView).image =
        [self imageForStars:nativeAppInstallAd.starRating];
    appInstallAdView.starRatingView.hidden = NO;
  } else {
    appInstallAdView.starRatingView.hidden = YES;
  }

  if (nativeAppInstallAd.store) {
    ((UILabel *)appInstallAdView.storeView).text = nativeAppInstallAd.store;
    appInstallAdView.storeView.hidden = NO;
  } else {
    appInstallAdView.storeView.hidden = YES;
  }

  if (nativeAppInstallAd.price) {
    ((UILabel *)appInstallAdView.priceView).text = nativeAppInstallAd.price;
    appInstallAdView.priceView.hidden = NO;
  } else {
    appInstallAdView.priceView.hidden = YES;
  }

  // In order for the SDK to process touch events properly, user interaction should be disabled on
  // all views associated with the GADNativeAppInstallAdView. Since UIButton has
  // userInteractionEnabled set to YES by default, views of this type must explicitly set
  // userInteractionEnabled to NO.
  appInstallAdView.callToActionView.userInteractionEnabled = NO;
}

And here's a method to display a content ad in the view defined above:

Swift

// Mark: - GADNativeContentAdLoaderDelegate

func adLoader(_ adLoader: GADAdLoader,
    didReceive nativeContentAd: GADNativeContentAd) {
  // Create and place the ad in the view hierarchy.
  let contentAdView = Bundle.main.loadNibNamed(
      "NativeContentAdView", owner: nil, options: nil)?.first as! GADNativeContentAdView
  // TODO: Make sure to add the GADNativeContentAdView to the view hierarchy.

  // Associate the content ad view with the content ad object. This is required
  // to make the ad clickable.
  contentAdView.nativeContentAd = nativeContentAd

  // Populate the content ad view with the content ad assets.
  // Some assets are guaranteed to be present in every content ad.
  (contentAdView.headlineView as! UILabel).text = nativeContentAd.headline
  (contentAdView.bodyView as! UILabel).text = nativeContentAd.body
  (contentAdView.imageView as! UIImageView).image =
      (nativeContentAd.images?.first as! GADNativeAdImage).image
  (contentAdView.advertiserView as! UILabel).text = nativeContentAd.advertiser
  (contentAdView.callToActionView as! UIButton).setTitle(
      nativeContentAd.callToAction, for: UIControlState.normal)

  // Other assets are not, however, and should be checked first.
  let logoView = contentAdView.logoView
  if let logoImage = nativeContentAd.logo?.image {
    (logoView as! UIImageView).image = logoImage
    logoView?.isHidden = false
  } else {
    logoView?.isHidden = true
  }

  // In order for the SDK to process touch events properly, user interaction
  // should be disabled on all views associated with the GADNativeContentAdView.
  // Since UIButton has userInteractionEnabled set to true by default, views of
  // this type must explicitly set userInteractionEnabled to false.
  (contentAdView.callToActionView as! UIButton).isUserInteractionEnabled = false
}

Objective-C

#pragma mark GADNativeContentAdLoaderDelegate implementation

- (void)adLoader:(GADAdLoader *)adLoader
    didReceiveNativeContentAd:(GADNativeContentAd *)nativeContentAd {
  // Create and place ad in view hierarchy.
  GADNativeContentAdView *contentAdView =
      [[[NSBundle mainBundle] loadNibNamed:@"NativeContentAdView"
                                     owner:nil
                                   options:nil] firstObject];
  // TODO: Make sure to add the GADNativeContentAdView to the view hierarchy.

  // Associate the content ad view with the content ad object. This is required
  // to make the ad clickable.
  contentAdView.nativeContentAd = nativeContentAd;

  // Populate the content ad view with the content ad assets.
  // Some assets are guaranteed to be present in every content ad.
  ((UILabel *)contentAdView.headlineView).text = nativeContentAd.headline;
  ((UILabel *)contentAdView.bodyView).text = nativeContentAd.body;
  ((UIImageView *)contentAdView.imageView).image =
      ((GADNativeAdImage *)[nativeContentAd.images firstObject]).image;
  ((UILabel *)contentAdView.advertiserView).text = nativeContentAd.advertiser;
  [((UIButton *)contentAdView.callToActionView)setTitle:nativeContentAd.callToAction
                                               forState:UIControlStateNormal];

  // Other assets are not, however, and should be checked first.
  if (nativeContentAd.logo && nativeContentAd.logo.image) {
    ((UIImageView *)contentAdView.logoView).image = nativeContentAd.logo.image;
    contentAdView.logoView.hidden = NO;
  } else {
    contentAdView.logoView.hidden = YES;
  }

  // In order for the SDK to process touch events properly, user interaction
  // should be disabled on all views associated with the GADNativeContentAdView.
  // Since UIButton has userInteractionEnabled set to YES by default, views
  // of this type must explicitly set userInteractionEnabled to NO.
  contentAdView.callToActionView.userInteractionEnabled = NO;
}

As you can see, the code examples above disable user interaction for the UIButton that displays the call to action. If you use UIButtons to display native ad assets, you'll also need to disable their user interaction so that the Google Mobile Ads SDK can properly receive and process UI events. Because of this extra step, it's frequently best to avoid UIButtons entirely and use UILabel and UIImageView instead.

Our GitHub repository has the complete implementations for Native custom rendering app install ads and content ads written in both Swift and Objective-C.

Download DFP Custom Rendering Example

Native video

In addition to images, text, and numbers, some native ads contain video assets. Not every ad will have one and apps are not required to display videos when they're included with an ad.

GADMediaView

Video assets are displayed to users via GADMediaView. This is a UIView that can be defined in a xib file or constructed dynamically. It should be placed within the view hierarchy of a GADNativeAdView, as with any other asset view.

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

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

This autopopulation of the GADMediaView with an available image asset does not always work when using mediation. Because not all mediation adapters guarantee that they'll create a media view for every ad, it's possible for a blank one to be returned for mediated ads. Publishers using mediation should check the hasVideoContent property of an ad's GADVideoController, to see if it contains a video asset, before displaying theGADMediaView. If there is no video content, publishers should display an image view that they populate manually with a relevant image.

Here's a snippet from the Custom Rendering Sample (Swift | Objective-C) that checks hasVideoContent and uses a UIImageView instead of GADMedaView when no video asset is present in the ad:

Swift

// The UI for this controller constrains the image view's height to match the
// media view's height, so by changing the one here, the height of both views
// are being adjusted.
if (nativeAppInstallAd.videoController.hasVideoContent()) {
  // The video controller has content. Show the media view.
  appInstallAdView.mediaView?.isHidden = false
  appInstallAdView.imageView?.isHidden = true

  // This app uses a fixed width for the GADMediaView and changes its height to
  // match the aspect ratio of the video it displays.
  let heightConstraint = NSLayoutConstraint(
        item: appInstallAdView.mediaView!,
        attribute: .height,
        relatedBy: .equal,
        toItem: appInstallAdView.mediaView!,
        attribute: .width,
        multiplier: CGFloat(1.0 / nativeAppInstallAd.videoController.aspectRatio()),
        constant: 0)
  heightConstraint.isActive = true

  // By acting as the delegate to the GADVideoController, this ViewController
  // receives messages about events in the video lifecycle.
  nativeAppInstallAd.videoController.delegate = self
} else {
  // If the ad doesn't contain a video asset, the first image asset is shown in
  // the image view. The existing lower priority height constraint is used.
  appInstallAdView.mediaView?.isHidden = true
  appInstallAdView.imageView?.isHidden = false

  let firstImage: GADNativeAdImage? = nativeAppInstallAd.images?.first as? GADNativeAdImage
  (appInstallAdView.imageView as? UIImageView)?.image = firstImage?.image
}

Objective-C

// The UI for this controller constrains the image view's height to match the
// media view's height, so by changing the one here, the height of both views
// are being adjusted.
if (nativeAppInstallAd.videoController.hasVideoContent) {
  // The video controller has content. Show the media view.
  appInstallAdView.mediaView.hidden = NO;
  appInstallAdView.imageView.hidden = YES;

  // This app uses a fixed width for the GADMediaView and changes its height to
  // match the aspect ratio of the video it displays.
  NSLayoutConstraint *heightConstraint =
  [NSLayoutConstraint constraintWithItem:appInstallAdView.mediaView
                               attribute:NSLayoutAttributeHeight
                               relatedBy:NSLayoutRelationEqual
                                  toItem:appInstallAdView.mediaView
                               attribute:NSLayoutAttributeWidth
                              multiplier:(1 / nativeAppInstallAd.videoController.aspectRatio)
                                constant:0];
  heightConstraint.active = YES;

  // By acting as the delegate to the GADVideoController, this ViewController
  // receives messages about events in the video lifecycle.
  nativeAppInstallAd.videoController.delegate = self;
} else {
  // If the ad doesn't contain a video asset, the first image asset is shown in
  // the image view. The existing lower priority height constraint is used.
  appInstallAdView.mediaView.hidden = YES;
  appInstallAdView.imageView.hidden = NO;

  GADNativeAdImage *firstImage = nativeAppInstallAd.images.firstObject;
  ((UIImageView *)appInstallAdView.imageView).image = firstImage.image;
}

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

GADVideoController

The GADVideoController class is used to retrieve information about video assets. GADNativeAppInstallAd and GADNativeContentAd both offer a videoController property that exposes the GADVideoController for each ad:

Swift

let vc1 = myAppInstallAd.videoController
let vc2 = myContentAd.videoController

Objective-C

GADVideoController *vc1 = myAppInstallAd.videoController
GADVideoController *vc2 = myContentAd.videoController

This property is never nil, even when the ad doesn't contain a video asset.

GADVideoController offers the following methods for querying video state:

  • hasVideoContent - True if the ad includes a video asset, false otherwise.
  • aspectRatio - The aspect ratio of the video (width/height) or zero (if no video asset is present).

Apps can also set a GADViewControllerDelegate for the GADViewController to be notified of events in the lifecycle of a video asset. GADViewControllerDelegate offers a single optional message, videoControllerDidEndVideoPlayback, which is sent when a video completes playback.

Here's an example of GADViewControllerDelegate in action:

Swift

class ViewController: UIViewController, GADNativeAppInstallAdLoaderDelegate,
    GADVideoControllerDelegate

  func adLoader(_ adLoader: GADAdLoader, didReceive nativeAppInstallAd:
                GADNativeAppInstallAd) {
    ...
    nativeAppInstallAd.videoController.delegate = self
    ...
  }

  ...
  func videoControllerDidEndVideoPlayback(_ videoController: Any!) {
    // Here apps can take action knowing video playback is finished.
    // This is handy for things like unmuting audio, and so on.
  }
}

Objective-C

@interface ViewController () 

- (void)adLoader:(GADAdLoader *)adLoader
    didReceiveNativeAppInstallAd:(GADNativeAppInstallAd) *)nativeAppInstallAd {
  ...
  nativeAppInstallAd.videoController.delegate = self;
  ...
}

...

- (void)videoControllerDidEndVideoPlayback:(GADVideoController *)videoController {
  // Here apps can take action knowing video playback is finished.
  // This is handy for things like unmuting audio, and so on.
}

@end

Load custom native ad formats

Like their system-defined counterparts, custom native ad formats are loaded using GADAdLoader objects. Including the kGADAdLoaderAdTypeNativeCustomTemplate constant in the adTypes array when initializing a GADAdLoader will configure it to request custom native formats when loading ads.

GADNativeCustomTemplateAdLoaderDelegate

The protocol for loading custom templates has two methods. The first is used by GADAdLoader to find out which template IDs it should request:

Swift

public func nativeCustomTemplateIDs(for adLoader: GADAdLoader) -> [Any]

Objective-C

- (NSArray *)nativeCustomTemplateIDsForAdLoader:(GADAdLoader *)adLoader;

Every custom native ad format has a corresponding template ID that identifies it. When this method is called, your app should return an array containing the template IDs of the formats it's prepared to display.

The second message is sent when the custom template ad has loaded, much like those for system-defined formats:

Swift

public func adLoader(_ adLoader: GADAdLoader,
    didReceive nativeCustomTemplateAd: GADNativeCustomTemplateAd)

Objective-C

- (void)adLoader:(GADAdLoader *)adLoader
    didReceiveNativeCustomTemplateAd:(GADNativeCustomTemplateAd *)nativeCustomTemplateAd;

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 will be discussed more in the next section.

Display custom native ad formats

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

  1. Because GADNativeCustomTemplateAd is meant to handle any of the custom native ad formats you create, it doesn't have named asset accessors. Instead, it offers methods like imageForKey: and stringForKey: that take the Variable ID of a template field as an argument.
  2. There is no dedicated ad view class like GADNativeContentAdView to use with GADNativeCustomTemplateAd. You are free to use whatever interface makes sense for your user experience.
  3. Because there is no dedicated ad view class, you do not need to register any of the views you use to display the ad's assets.

Here is an example of an ad view capable of displaying a simple custom native ad:

MySimpleNativeAdView.h

Swift

import UIKit
import GoogleMobileAds

/// Custom native ad view class with template ID 10063170.
class MySimpleNativeAdView: UIView {

  /// Weak references to this ad's asset views.
  @IBOutlet weak var headlineView: UILabel!
  @IBOutlet weak var mainImageView: UIImageView!
  @IBOutlet weak var captionView: UILabel!

  ...

  /// Populates the ad view with the custom native ad object.
  func populateWithCustomNativeAd(_ customNativeAd: GADNativeCustomTemplateAd) {
    ...
  }
}

Objective-C

@import UIKit;
@import GoogleMobileAds;

/// View representing a custom native ad format with template ID 10063170.
@interface MySimpleNativeAdView : UIView

// Weak references to this ad's asset views.
@property(weak, nonatomic) IBOutlet UILabel *headlineView;
@property(weak, nonatomic) IBOutlet UIImageView *mainImageView;
@property(weak, nonatomic) IBOutlet UILabel *captionView;

/// Populates the ad view with the custom native ad object.
- (void)populateWithCustomNativeAd:(GADNativeCustomTemplateAd *)customNativeAd;

@end

MySimpleNativeAdView.m (excerpt)

Swift

...
func populateWithCustomNativeAd(_ customNativeAd: GADNativeCustomTemplateAd) {
  self.customNativeAd = customNativeAd

  // Populate the custom native ad assets.
  headlineView.text = self.customNativeAd.stringForKey("Headline")
  mainImageView.image = self.customNativeAd.imageForKey("MainImage")?.image
  captionView.text = self.customNativeAd.stringForKey("Caption")
}
...

Objective-C

...
- (void)populateWithCustomNativeAd:(GADNativeCustomTemplateAd *)customNativeAd {
  self.customNativeAd = customNativeAd;

  // Populate the custom native ad assets.
  self.headlineView.text = [customNativeAd stringForKey:@"Headline"];
  self.mainImageView.image = [customNativeAd imageForKey:@"MainImage"].image;
  self.captionView.text = [customNativeAd stringForKey:@"Caption"];
}
...

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 the GADNativeCustomTemplateAd.mediaView property 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:

Swift

...
  /// Populates the ad view with the custom native ad object.
  func populate(withCustomNativeAd customNativeAd: GADNativeCustomTemplateAd) {
    if customNativeAd.videoController.hasVideoContent(),
      let mediaView = customNativeAd.mediaView {
      updateMainView(mediaView)
    } else {
      // Assumes your native format has an image asset with the name MainImage.
      let image: UIImage? = customNativeAd.image(forKey: "MainImage")?.image
      updateMainView(UIImageView(image: image))
    }
  }

  private func updateMainView(_ mainView:UIView) {
    // Assumes you have a placeholder view for your media content.
    // Remove all the placeholder's subviews.
    for subview: UIView in mainPlaceholder.subviews {
      subview.removeFromSuperview()
    }
    mainPlaceholder.addSubview(mainView)
    // Size the media view to fill our container size.
    mainView.translatesAutoresizingMaskIntoConstraints = false
    let viewDictionary: [AnyHashable: Any] = ["mainView":mainView]
    mainPlaceholder.addConstraints(NSLayoutConstraint.constraints(
      withVisualFormat: "H:|[mainView]|", options: [], metrics: nil,
      views: viewDictionary as? [String : Any] ?? [String : Any]()))
    mainPlaceholder.addConstraints(NSLayoutConstraint.constraints(
      withVisualFormat: "V:|[mainView]|", options: [], metrics: nil,
      views: viewDictionary as? [String : Any] ?? [String : Any]()))
  }
...

Objective-C

...
- (void)populateWithCustomNativeAd:(GADNativeCustomTemplateAd *)ad {
  UIView *mainView = nil;
  if (ad.videoController.hasVideoContent) {
    mainView = ad.mediaView;
  } else {
    // Assumes your native format has an image asset with the name MainImage.
    UIImage *image = [ad imageForKey:@"MainImage"].image;
    mainView = [[UIImageView alloc] initWithImage:image];
  }
  // Assumes you have a placeholder view for your media content.
  for (UIView *subview in self.mainPlaceholder.subviews) {
    [subview removeFromSuperview];
  }
  [self.mainPlaceholder addSubview:mainView];

  // Size the main view to fill our container size.
  [mainView setTranslatesAutoresizingMaskIntoConstraints:NO];
  NSDictionary *viewDictionary = NSDictionaryOfVariableBindings(mainView);
  [self.mainPlaceholder
      addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mainView]|"
                                                             options:0
                                                             metrics:nil
                                                               views:viewDictionary]];
  [self.mainPlaceholder
      addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mainView]|"
                                                             options:0
                                                             metrics:nil
                                                               views:viewDictionary]];
}
...

See GADVideoController 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.

Handle custom native ad format clicks and impressions

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

Record impressions

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

Swift

myCustomTemplateAd.recordImpression()

Objective-C

[myCustomTemplateAd recordImpression];

The SDK prevents duplicate impressions from being recorded for a single request, should your app accidentally call the method multiple times for the same ad.

Report clicks

To report to the SDK that a click has occurred on an asset view, call the performClickOnAssetWithKey: method on the corresponding GADNativeCustomTemplateAd 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 view that corresponded to that asset, your code would look like this:

Swift

myCustomTemplateAd.performClickOnAsset(withKey: "MainImage")

Objective-C

[myCustomTemplateAd performClickOnAssetWithKey:@"MainImage"];

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

Respond to custom click actions

GADNativeCustomTemplateAd has a property customClickHandler which is of type GADNativeAdCustomClickHandler

Swift

typealias GADNativeAdCustomClickHandler = (assetID: String) -> Void

Objective-C

typedef void (^GADNativeAdCustomClickHandler)(NSString *assetID);

This is a block (Objective-C) / closure (Swift) that accepts an assetID as an input parameter, which identifies the asset that has been clicked on.

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 customClickHandler block in Objective-C or closure in Swift, if one was set.
  2. Loop through the ad's Deeplink URLs and open the first one for which a matching app can be found.
  3. Open a browser and navigate to the ad's traditional Destination URL.

The customClickHandler property accepts a block in Objective-C and a closure in Swift. If you set a block or closure, the SDK will run it and take no further action. If you set a nil value, however, the SDK will fall back to the deeplink and/or destination URLs registered with the ad.

Custom click handlers allow your app to decide for itself the best action to take in response to a click, whether it's updating the UI, presenting another view controller, or merely logging the click. Here's an example that shows an alert:

Swift

myCustomTemplateAd.customClickHandler = { assetID in
  if assetID == "MainImage" {
    let alertView = UIAlertView(title: "Custom Click",
        message: "You just clicked on the image!",
        delegate: self,
        cancelButtonTitle: "OK")
    alertView.alertViewStyle = .default
    alertView.show()
  }
}
myCustomTemplateAd.performClickOnAsset(withKey: "MainImage")

Objective-C

[self.customTemplateAd setCustomClickHandler:^(NSString *assetID){
  if ([assetID isEqualToString:@"MainImage"]) {
    [[[UIAlertView alloc] initWithTitle:@"Custom Click"
                                message:@"You just clicked on the image!"
                               delegate:self
                      cancelButtonTitle:@"OK"
                      otherButtonTitles:nil] show];
  }
}];
[self.customTemplateAd performClickOnAssetWithKey:@"MainImage"];

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. Please note that at the current time, publishers should not use the testDevices property with native ad requests. Using the above ad unit ID with no devices registered via the testDevices property is the current best practice for testing.

Native backfill ads

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

/6499/example/native-backfill

It will serve 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 iOS
Need help? Visit our support page.