<br />

## Custom ad formats

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

> [!NOTE]
> **Note:** You can request custom native formats and system-defined simultaneously with a single `GADAdLoader` if you have an ad unit that's configured to serve multiple ad formats. Ad Manager will select the best native creative associated with one of the formats you've requested.

### GADCustomNativeAdLoaderDelegate

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

### Swift

```swift
public func customNativeAdFormatIDs(for adLoader: AdLoader) -> [Any]
```

### Objective-C

```objective-c
- (NSArray *)customNativeAdFormatIDsForAdLoader:(AdLoader *)adLoader;
```

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

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

### Swift

```swift
public func adLoader(_ adLoader: AdLoader,
    didReceive customNativeAd: CustomNativeAd)
```

### Objective-C

```objective-c
- (void)adLoader:(AdLoader *)adLoader
    didReceiveCustomNativeAd:(CustomNativeAd *)customNativeAd;
```

### Format IDs

The format IDs used to uniquely refer to custom native ad formats
can be found in the Ad Manager UI
under the **Native** section inside the **Delivery**
dropdown:

![](https://developers.google.com/static/ad-manager/mobile-ads-sdk/images/ad-manager-custom-template-list.png)

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

![](https://developers.google.com/static/ad-manager/mobile-ads-sdk/images/ad-manager-custom-template-example.png)

From here, individual fields can be added, edited, and removed. Note the
**Name** of each of the assets. The name is the key used to get the data for
each asset when displaying your custom native ad format.

### Displaying custom native ad formats

Custom native ad formats differ from system-defined ones in that publishers
have the power to define their own list 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 `GADCustomNativeAd` 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 name of the field as an argument.
2. There is no dedicated ad view class like `GADNativeAdView` to use with `GADCustomNativeAd`. You are free to use whatever view that 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

```swift
import UIKit
import GoogleMobileAds

/// Custom native ad view class with format 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: CustomNativeAd) {
    ...
  }
}
```

### Objective-C

```objective-c
@import UIKit;
@import GoogleMobileAds;

/// View representing a custom native ad format with format 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:(GADCustomNativeAd *)customNativeAd;

@end
```

### MySimpleNativeAdView.m (excerpt)

### Swift

```swift
...
func populateWithCustomNativeAd(_ customNativeAd: CustomNativeAd) {
  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

```objective-c
...
- (void)populateWithCustomNativeAd:(GADCustomNativeAd *)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"];
}
...
```

## Render the AdChoices icon

As part of [Supporting the Digital Services Act (DSA)](https://support.google.com/admanager/answer/14335032),
reservation ads served in the European Economic Area (EEA) require an
AdChoices icon and a link to [Google's About This Ad page](https://support.google.com/adsense/troubleshooter/1631343).
When implementing custom native ads, you are responsible for rendering the
AdChoices icon. It is important you take steps to render and set the click
listener for the AdChoices icon when rendering the main ad assets.

The following example renders the AdChoices icon and configures
click behavior.

> [!IMPORTANT]
> **Important:** Set the AdChoices icon at least 15 pixels by 15 pixels.

### Swift

```swift
class MySimpleNativeAdView: UIView {
  @IBOutlet weak var adChoicesView: UIImageView!

  override func awakeFromNib() {
    super.awakeFromNib()

    // Enable clicks on AdChoices.
    adChoicesView.addGestureRecognizer(
      UITapGestureRecognizer(
        target: self,
        action: #selector(performClickOnAdChoices(_:))))
    adChoicesView.isUserInteractionEnabled = true
  }

  @objc func performClickOnAdChoices(_ sender: UIImage!) {
    customNativeAd.performClickOnAsset(withKey:
      NativeAssetIdentifier.adChoicesViewAsset.rawValue)
  }

  func populate(withCustomNativeAd customNativeAd: CustomNativeAd) {

    // Render the AdChoices image.
    let adChoicesKey = NativeAssetIdentifier.adChoicesViewAsset.rawValue
    let adChoicesImage = customNativeAd.image(forKey: adChoicesKey)?.image
    adChoicesView.image = adChoicesImage
    adChoicesView.isHidden = adChoicesImage == nil
    ...
  }
}

```

### Objective-C

```objective-c
@interface MySimpleNativeAdView ()

@property(nonatomic, weak) IBOutlet UIImageView *adChoicesView;

@end

@implementation MySimpleNativeAdView

- (void)awakeFromNib {
  [super awakeFromNib];
  // Enable clicks on AdChoices.
  [self.adChoicesView addGestureRecognizer:[[UITapGestureRecognizer alloc]
                                            initWithTarget:self
                                            action:@selector(performClickOnAdChoices:)]];
  self.adChoicesView.userInteractionEnabled = YES;
}

- (void)performClickOnAdChoices:(UITapGestureRecognizer *)sender {
    [self.customNativeAd performClickOnAssetWithKey:GADNativeAdChoicesViewAsset];
}

- (void)populateWithCustomNativeAd:(GADCustomNativeAd *)customNativeAd {
  // Render the AdChoices image.
  GADNativeAdImage *adChoicesAsset = [customNativeAd
    imageForKey:GADNativeAdChoicesViewAsset];
  self.adChoicesView.image = adChoicesAsset.image;
  self.adChoicesView.hidden = (adChoicesAsset == nil);
  ...
}
```

> [!IMPORTANT]
> **Key Point:** If you use [Image download control](https://developers.google.com/ad-manager/mobile-ads-sdk/ios/native/options.md.txt#image_download_control) to request only image URLs, the AdChoices asset respects this setting and only returns the image URL.

### Native video for custom native ad formats

When [creating a custom format](https://support.google.com/admanager/answer/7661908),
you have the option to make the format eligible for video.

In your app implementation, use the
[`GADCustomNativeAd.mediaContent`](https://developers.google.com/ad-manager/mobile-ads-sdk/ios/api/reference/Classes/GADCustomNativeAd.md.txt#mediacontent)
property to get the ad's
[`GADMediaContent`](https://developers.google.com/ad-manager/mobile-ads-sdk/ios/api/reference/Classes/GADMediaContent.md.txt) instance.
To determine whether the ad contains video content, check the
[`hasVideoContent`](https://developers.google.com/ad-manager/mobile-ads-sdk/ios/api/reference/Classes/GADMediaContent.md.txt#-hasvideocontent)
property. If the ad has video
content, create a
[`GADMediaView`](https://developers.google.com/ad-manager/mobile-ads-sdk/ios/api/reference/Classes/GADMediaView.md.txt) view, assign the
`mediaContent` property, and add the media view to your view hierarchy. If the
ad doesn't have video content, render an alternate asset such as an image.

The following example checks if the ad has video content, and displays an image
in place if a video isn't available:

### Swift

```swift
func populate(withCustomNativeAd customNativeAd: CustomNativeAd) {
  // Remove all the media placeholder's subviews.
  for subview: UIView in mainPlaceholder.subviews {
    subview.removeFromSuperview()
  }

  // This custom native ad has both a video and image associated with it. Use the video
  // asset if available, or fall back to the image asset.
  let mainView: UIView
  if customNativeAd.mediaContent.hasVideoContent {
    let mediaView = MediaView()
    mediaView.mediaContent = customNativeAd.mediaContent
    mainView = mediaView
  } else {
    let image: UIImage? = customNativeAd.image(forKey: "MainImage")?.image
    mainView = UIImageView(image: image)
  }
  mainPlaceholder.addSubview(mainView)

  // Size the media view to fill the container size.
  mainView.translatesAutoresizingMaskIntoConstraints = false
  NSLayoutConstraint.activate([
    mainView.leadingAnchor.constraint(equalTo: mainPlaceholder.leadingAnchor),
    mainView.trailingAnchor.constraint(equalTo: mainPlaceholder.trailingAnchor),
    mainView.topAnchor.constraint(equalTo: mainPlaceholder.topAnchor),
    mainView.bottomAnchor.constraint(equalTo: mainPlaceholder.bottomAnchor),
  ])
}
```

### Objective-C

```objective-c
- (void)populateWithCustomNativeAd:(GADCustomNativeAd *)customNativeAd {
  // Remove all the media placeholder's subviews.
  for (UIView *subview in self.mainPlaceholder.subviews) {
    [subview removeFromSuperview];
  }

  // This custom native ad has both a video and image associated with it. Use the video
  // asset if available, or fall back to the image asset.
  UIView *mainView = nil;
  if (customNativeAd.mediaContent.hasVideoContent) {
    GADMediaView *mediaView = [[GADMediaView alloc] init];
    mediaView.mediaContent = customNativeAd.mediaContent;
    mainView = mediaView;
  } else {
    UIImage *image = [customNativeAd imageForKey:@"MainImage"].image;
    mainView = [[UIImageView alloc] initWithImage:image];
  }
  [self.mainPlaceholder addSubview:mainView];

  // Size the media view to fill the container size.
  mainView.translatesAutoresizingMaskIntoConstraints = NO;
  [NSLayoutConstraint activateConstraints:@[
    [mainView.leadingAnchor constraintEqualToAnchor:self.mainPlaceholder.leadingAnchor],
    [mainView.trailingAnchor constraintEqualToAnchor:self.mainPlaceholder.trailingAnchor],
    [mainView.topAnchor constraintEqualToAnchor:self.mainPlaceholder.topAnchor],
    [mainView.bottomAnchor constraintEqualToAnchor:self.mainPlaceholder.bottomAnchor],
  ]];
}
```

> [!NOTE]
> **Note:** Unlike standard native ads, which populate an image in the `GADMediaView` view when video is unavailable, a custom native ad's `mediaContent` property doesn't automatically populate an image if the ad doesn't contain video.

For details about customizing a custom native ad video, see the
[`GADVideoController`](https://developers.google.com/ad-manager/mobile-ads-sdk/ios/api/reference/Classes/GADVideoController.md.txt)
class.

For an implementation of custom native video, view the Ad Manager
Custom Rendering example in
[Swift](https://github.com/googleads/googleads-mobile-ios-examples/tree/main/Swift/admanager/AdManagerCustomRenderingExample)
and
[Objective-C](https://github.com/googleads/googleads-mobile-ios-examples/tree/main/Objective-C/admanager/AdManagerCustomRenderingExample).

### 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 native ad, just call the
`recordImpression` method on the corresponding `GADCustomNativeAd`:

### Swift

```swift
myCustomNativeAd.recordImpression()
```

### Objective-C

```objective-c
[myCustomNativeAd recordImpression];
```

The SDK prevents duplicate impressions from being recorded for a single request,
if your app accidentally calls 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
`GADCustomNativeAd` and pass in the name of the asset that was clicked.
For example, if you had an asset in your custom format called "MainImage"
and wanted to report a click on the view that corresponded to that asset,
your code would look like this:

### Swift

```swift
myCustomNativeAd.performClickOnAsset(withKey: "MainImage")
```

### Objective-C

```objective-c
[myCustomNativeAd 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

`GADCustomNativeAd` has a property `customClickHandler` which is of type
`GADNativeAdCustomClickHandler`

### Swift

```swift
typealias NativeAdCustomClickHandler = (assetID: String) -> Void
```

### Objective-C

```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 native 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

```swift
myCustomNativeAd.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()
  }
}
myCustomNativeAd.performClickOnAsset(withKey: "MainImage")
```

### Objective-C

```objective-c
[self.customNativeAd 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.customNativeAd performClickOnAssetWithKey:@"MainImage"];
```

> [!IMPORTANT]
>
> At first, it might seem strange that custom click handlers 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.

## 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:

`/21775744923/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:

`/21775744923/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 format IDs
before going live!