Share your feedback about the Google Mobile Ads SDK! Take the annual survey.

Custom Native Ad Formats

Custom 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 Ad Manager 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.

Displaying 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 Ad Manager Custom Rendering example for a working example of native video in action.

Handling custom native ad clicks and impressions

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

Recording 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.

Reporting 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.

Responding 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"];

Testing 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 Ad Manager 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)

Native backfill ads

To test the behavior of native backfill ads, use this Ad Manager 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!