Native Mediation Adapters

This guide is intended for networks who want to create an AdMob mediation adapter to load and display native ads from one of AdMob's Supported ad networks. Mediation adapters are classes capable of requesting ads from another network and adapting them to work with the Google Mobile Ads SDK. That means doing the following things:

  • Request native ads from a mediated network.
  • Forward events from the mediated network's SDK to the Google Mobile Ads SDK.
  • Use a GADMediatedNativeAd to map mediated native ad objects to AdMob's native ad interface.

Each of these tasks is covered below. You can also find the full source for a sample mediation adapter project at our GitHub repository.

Prerequisites

To implement an AdMob mediation adapter, you must first integrate the Mobile Ads SDK into your project. You may also want to first read about making an ad request and how mediation works.

The Sample SDK

The code used in this guide is taken from our sample custom event project, which also includes a "Sample SDK." In order for the project to illustrate how to build a custom event that mediates another ad network's SDK, it needed an SDK to mediate, so we created a mock called the Sample SDK.

The Sample SDK features classes similar to what you'd find in an ad network's production SDK. There are request classes like SampleNativeAdRequest, ad loaders like SampleNativeAdLoader, and other classes, constants, and protocols used to simulate a real network's SDK. The ads that it produces are mocks, though, and no additional network traffic is generated.

Initialization

Mediation Adapter classes must implement the GADMAdNetworkAdapter protocol. Among other things, this protocol includes an initializer method accepting an instance of GADMAdNetworkConnector. Adapters should maintain a reference to the connector, so they can use it later to retrieve request information and send messages back to the Google Mobile Ads SDK:

- (instancetype)initWithGADMAdNetworkConnector:(id<GADMAdNetworkConnector>)connector {
  self = [super init];
  if (self) {
    _connector = connector;
  }
  return self;
}

Request native ads

The getNativeAdWithAdTypes:options: method

The GADMAdNetworkAdapter protocol also includes a method used by the Google Mobile Ads SDK to request native ads from the adapter:

- (void)getNativeAdWithAdTypes:(NSArray *)adTypes options:(NSArray *)options;

When this method is called, the adapter should asynchronously request a native ad from the mediated network's SDK. The parameters for GADMAdNetworkAdapter carry information that the adapter can use in making its request:

  • adTypes - An NSArray containing constants that indicate which native formats are requested. Possible values include kGADAdLoaderAdTypeNativeContent and kGADAdLoaderAdTypeNativeAppInstall.
  • options - An NSArray containing GADAdLoaderOptions objects that indicate the publisher's preferences for loading ads.

In addition to the parameters carrying request information, the adapter can also use properties of the GADMAdNetworkConnector provided in its initializer. These include credentials and publisher ID values, as well as targeting information like gender and location (if provided by the publisher).

SampleAdapter.m (excerpt)

Here's a code snippet from our example adapter project that shows an implemented getNativeAdWithAdTypes: method:

- (void)getNativeAdWithAdTypes:(NSArray *)adTypes options:(NSArray *)options {
  self.nativeAdLoader = [[SampleNativeAdLoader alloc] init];
  self.nativeAdLoader.adUnitID = [self.connector credentials][@"ad_unit"];
  self.nativeAdLoader.delegate = self;

  SampleNativeAdRequest *sampleRequest = [[SampleNativeAdRequest alloc] init];

  // Part of the adapter's job is to examine the ad types and options, and then
  // create a request for the mediated network's SDK that matches them.
  for (NSString *adType in adTypes) {
    if ([adType isEqual:kGADAdLoaderAdTypeNativeContent]) {
      sampleRequest.contentAdsRequested = YES;
    } else if ([adType isEqual:kGADAdLoaderAdTypeNativeAppInstall]) {
      sampleRequest.appInstallAdsRequested = YES;
    }
  }

  for (GADNativeAdImageAdLoaderOptions *imageOptions in options) {
    if (![imageOptions isKindOfClass:[GADNativeAdImageAdLoaderOptions class]]) {
      continue;
    }

    sampleRequest.shouldRequestPortraitImages =
        imageOptions.preferredImageOrientation ==
        GADNativeAdImageAdLoaderOptionsOrientationPortrait;
    sampleRequest.shouldDownloadImages = !imageOptions.disableImageLoading;
    sampleRequest.shouldRequestMultipleImages = imageOptions.shouldRequestMultipleImages;
  }

  [self.nativeAdLoader fetchAd:sampleRequest];
}

This is a sample adapter that mediates an imaginary ad network via a mock "Sample SDK." The adapter class uses the information provided in its connector and the parameters of getNativeAdWithAdTypes: to request an ad from the Sample SDK's SampleNativeAdLoader. It also assigns itself as the delegate for SampleNativeAdLoader, so it can forward events from the Sample SDK back to the Google Mobile Ads SDK.

Respect native ad formats

As noted above, the adTypes array includes information about which native ad formats the publisher is requesting. It is extremely important that adapters respect this choice and return only those formats that the publisher indicated they're prepared to display. Otherwise, they could cause the publisher's rendering code to fail.

If, for example, your ad network only ever provides app install ads, and the publisher requests content ads alone, your adapter should not request an app install ad anyway and then try to map it to the content ad format. Instead, it should call the connector's adapter:didFailAd: method with an error code of kGADErrorInvalidRequest.

GADAdLoaderOptions

When making a request for native ads, publishers provide an array of GADAdLoaderOptions objects to specify their preferences for that request, such as how image assets should be returned. These are in turn provided to mediation adapters as one of the parameters in the getNativeAdWithAdTypes:options: method. Adapters should iterate over the options array, and act in accordance with the preferences it contains.

For example, if the options array contains a GADNativeAdImageAdLoaderOptions object with its shouldDownloadImages value set to true, the adapter must return actual image assets rather than just URLs. In this case, if the SDK being adapted only provides URLs for images, then the adapter must use those URLs to download the image files and make their data available to the publisher.

Forward events to the Mobile Ads SDK

A few things can happen when a mediation adapter tries to load a native ad from its mediated network. The SDK could successfully return a native ad, it could come back with an error, or it might simply report that no ads are available. It's important for the Google Mobile Ads SDK to be aware of these events, so the GADMAdNetworkConnector protocol includes a number of messages that the adapter can use to forward them.

It's part of an adapter's job to act as a "man-in-the-middle," listening for events from the mediated SDK, and then sending the corresponding GADMAdNetworkConnector protocol message as appropriate. Your adapter needs to be aware of the following messages:

  • adapter:didReceiveMediatedNativeAd - This message should be sent when an adapter successfully loads a native ad. It takes a single parameter of type GADMediatedNativeAd, which the adapter should use to pass a "mapped" version of the native ad it just loaded (GADMediatedNativeAd classes are covered in the next section).
  • adapter:didFailAd - When the adapter tries and fails to load a native ad, it should use this method to report the failure. It takes an NSError parameter, which contains information specific to the failure.

Here's an example of how this works in our example adapter project:

SampleAdapter.m (excerpt)

@interface SampleAdapter () <SampleBannerAdDelegate, SampleInterstitialAdDelegate,
                             SampleNativeAdLoaderDelegate>

...

/// Connector from Google Mobile Ads SDK to receive ad configurations.
@property(nonatomic, weak) id<GADMAdNetworkConnector> connector;

@end

@implementation SampleAdapter

...

#pragma mark SampleNativeAdLoaderDelegate implementation

- (void)adLoader:(SampleNativeAdLoader *)adLoader
    didReceiveNativeAppInstallAd:(SampleNativeAppInstallAd *)nativeAppInstallAd {
  SampleAdapterMediatedNativeAppInstallAd *mediatedAd =
      [[SampleAdapterMediatedNativeAppInstallAd alloc]
          initWithSampleNativeAppInstallAd:nativeAppInstallAd];
  [self.connector adapter:self didReceiveMediatedNativeAd:mediatedAd];
}

- (void)adLoader:(SampleNativeAdLoader *)adLoader
    didReceiveNativeContentAd:(SampleNativeContentAd *)nativeContentAd {
  SampleAdapterMediatedNativeContentAd *mediatedAd =
      [[SampleAdapterMediatedNativeContentAd alloc]
        initWithSampleNativeContentAd:nativeContentAd];
  [self.connector adapter:self didReceiveMediatedNativeAd:mediatedAd];
}

- (void)adLoader:(SampleNativeAdLoader *)adLoader
    didFailToLoadAdWithErrorCode:(SampleErrorCode)errorCode {
  NSError *error = [NSError errorWithDomain:adapterErrorDomain code:errorCode userInfo:nil];
  [self.connector adapter:self didFailAd:error];
}

@end

Notice that the class implements the Sample SDK's SampleNativeAdLoaderDelegate protocol. If you recall from the code example above that covered making requests, the adapter class assigned itself to the SampleNativeAdLoader as a delegate:

self.nativeAdLoader.delegate = self;

This ensures that the Sample SDK sends messages back to the adapter when it has success or failure to report. The adapter then sends the appropriate message to its connector, forwarding the event to the Google Mobile Ads SDK. In short, the Google Mobile Ads SDK listens to the adapter, which is listening to the mediated SDK.

The adLoader:didFailToLoadAdWithErrorCode: method above is a great example of how this works. When the Sample SDK fails to load an ad, it sends an adLoader:didFailToLoadAdWithErrorCode: message to the adapter. The adapter creates a new NSError object with the SampleErrorCode provided by the Sample SDK, and then sends it to the connector via the adapter:didFailAd: message. In this way, a Sample SDK event is turned into a Google Mobile Ads SDK event.

Map native ads

Different SDKs have their own unique formats for native ads. One SDK might return objects that contain a "title" field, for instance, while another might have "headline." Additionally, the methods used to track impressions and process clicks may vary from one SDK to another. To smooth out these wrinkles, adapters should define and use subclasses of GADMediatedNativeAd to "map" their mediated SDK's native ad objects so they match the interface expected by the Google Mobile Ads SDK.

Each of AdMob's system-defined native ad formats has a corresponding GADMediatedNativeAd class: GADMediatedNativeAppInstallAd for app install ads, and GADMediatedNativeContentAd for content ads. Adapters should create subclasses of these to map the native ad objects provided by their mediated SDK.

Here's an example mapper class from our example mediation adapter project:

SampleAdapterMediatedNativeAppInstallAd.h (excerpt)

@interface SampleAdapterMediatedNativeAppInstallAd : NSObject<GADMediatedNativeAppInstallAd>

- (instancetype)initWithSampleNativeAppInstallAd:
        (nonnull SampleNativeAppInstallAd*)sampleNativeAppInstallAd NS_DESIGNATED_INITIALIZER;

@end

SampleAdapterMediatedNativeAppInstallAd.m (excerpt)

@implementation SampleAdapterMediatedNativeAppInstallAd

- (instancetype)initWithSampleNativeAppInstallAd:
        (nonnull SampleNativeAppInstallAd *)sampleNativeAppInstallAd {
  if (!sampleNativeAppInstallAd) {
    return nil;
  }

  self = [super init];
  if (self) {
    _sampleAd = sampleNativeAppInstallAd;
    _extras = @{SampleAdapterExtraKeyAwesomeness : _sampleAd.degreeOfAwesomeness};

    if (_sampleAd.image) {
      _mappedImages = @[ [[GADNativeAdImage alloc] initWithImage:_sampleAd.image] ];
    } else {
      NSURL *imageURL = [[NSURL alloc] initFileURLWithPath:_sampleAd.imageURL];
      _mappedImages =
          @[ [[GADNativeAdImage alloc] initWithURL:imageURL scale:_sampleAd.imageScale] ];
    }

    if (_sampleAd.icon) {
      _mappedIcon = [[GADNativeAdImage alloc] initWithImage:_sampleAd.icon];
    } else {
      NSURL *iconURL = [[NSURL alloc] initFileURLWithPath:_sampleAd.iconURL];
      _mappedIcon = [[GADNativeAdImage alloc] initWithURL:iconURL scale:_sampleAd.iconScale];
    }
  }
  return self;
}

- (NSString *)headline {
  return self.sampleAd.headline;
}

- (NSArray *)images {
  return self.mappedImages;
}

- (NSString *)body {
  return self.sampleAd.body;
}

- (GADNativeAdImage *)icon {
  return self.mappedIcon;
}

- (NSString *)callToAction {
  return self.sampleAd.callToAction;
}

- (NSDecimalNumber *)starRating {
  return self.sampleAd.starRating;
}

- (NSString *)store {
  return self.sampleAd.store;
}

- (NSString *)price {
  return self.sampleAd.price;
}

- (NSDictionary *)extraAssets {
  return self.extras;
}

- (id<GADMediatedNativeAdDelegate>)mediatedNativeAdDelegate {
  return self;
}

#pragma mark - GADMediatedNativeAdDelegate implementation

- (void)mediatedNativeAdDidRecordImpression:(id<GADMediatedNativeAd>)mediatedNativeAd {
  if (self.sampleAd) {
    [self.sampleAd recordImpression];
  }
}

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd
    didRecordClickOnAssetWithName:(NSString *)assetName
                             view:(UIView *)view
                   viewController:(UIViewController *)viewController {
  if (self.sampleAd) {
    [self.sampleAd handleClickOnView:view];
  }
}

@end

Let's first take a look at the initializer and some of the work it's doing.

Hold a reference to the mediated native ad object

The initializer accepts an instance of SampleNativeAppInstallAd as its only parameter. This is the native ad class used by the Sample SDK for its app install ads. The mapper needs a reference to the mediated ad object so it can pass on click and impression events, so it stores one as sampleAd.

Create an NSDictionary to hold extra assets

Some mediated networks may provide additional assets beyond those in the AdMob native ad formats. The GADMediatedNativeAd protocol includes a method called extraAssets that the Google Mobile Ads SDK uses to retrieve any of these "extra" assets from your mapper. The initializer above creates an NSDictionary and fills it with the extra assets provided by the Sample SDK (in this case, a single NSString value called degreeOfAwesomeness). This NSDictionary is used as a return value by the extraAssets method later on:

_extras = @{SampleAdapterExtraKeyAwesomeness : _sampleAd.degreeOfAwesomeness};

Map image assets

Mapping image assets is a little more complicated than mapping simpler data types like NSString or double. Images might be downloaded automatically or simply returned as URL values. Their pixel density can also vary. To help mediation adapter developers manage these details, the Google Mobile Ads SDK provides the GADNativeAdImage class. Image asset information (whether it's actual UIImage objects or just .NSURL values) should be returned to the Google Mobile Ads SDK using this class. Here's how the mapper class handles creating a GADNativeAdImage to hold the icon image for its app install ad:

if (_sampleAd.icon) {
  _mappedIcon = [[GADNativeAdImage alloc] initWithImage:_sampleAd.icon];
} else {
  NSURL *iconURL = [[NSURL alloc] initFileURLWithPath:_sampleAd.iconURL];
  _mappedIcon = [[GADNativeAdImage alloc] initWithURL:iconURL scale:_sampleAd.iconScale];
}

If you recall from the section on making requests, publishers can use a GADNativeAdImageAdLoaderOptions object to specify that native ad images shouldn't be automatically downloaded. Here, the mapper checks to see if the image was downloaded already, and creates a GADNativeAdImage with the appropriate information—either a UIImage, or a matching pair of NSURL and scale values.

With the initializer covered, let's move on to the work being done elsewhere in the class.

Return mapped assets

This mapper class inherits methods from GADMediatedNativeAppInstallAd that correspond to the expected assets for an app install ad. The Google Mobile Ads SDK calls these methods to retrieve the assets, so your mapper class should return the appropriate value. For most assets, this is pretty simple:

- (NSString *)headline {
  return self.sampleAd.headline;
}

For some assets, however, data types may not match or some other type of conversion may be required. It's the mapper's job to handle these details, and the asset methods are a good place to do it.

AdChoices

Your adapter is responsible for placing your AdChoices icon in Google's native ad view. You should use of the didRenderInView: and didUntrackView: delegate methods in GADMediatedNativeAdDelegate to add and remove your AdChoices view.

The adapter must also respect the publisher's preference of AdChoices location by checking if any options are of type GADNativeAdViewAdOptions that have the preferredAdChoicesPosition property set. If a preferred corner is not specified, AdChoices should be rendered in the top right corner.

A sample implementation of how to respect the publisher's AdChoices placement and render the AdChoices icon is shown below:

@interface SampleMediatedNativeAd ()<GADMediatedNativeAdDelegate> {

  /// Ad networks should provide their own AdChoices view.
  SampleAdChoicesView *_adChoicesView;

  /// Note: GADNativeAdViewAdOptions requires GoogleMobileAds SDK v7.12.0 or higher.
  GADNativeAdViewAdOptions *_nativeAdViewAdOptions;
}

- (void)getNativeAdWithAdTypes:(NSArray *)adTypes options:(NSArray *)options {

  if(options != nil) {
          for (GADAdLoaderOptions *loaderOptions in options) {
              if ([loaderOptions isKindOfClass:[GADNativeAdViewAdOptions class]]) {
                   _nativeAdViewAdOptions = (GADNativeAdViewAdOptions *)loaderOptions;
              }
              // You can similarly check for other options (GADNativeAdImageAdLoaderOptions).
          }
        }

   // Request your native ad here.
 }

#pragma mark - GADMediatedNativeAdDelegate

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd
         didRenderInView:(UIView *)view
          viewController:(UIViewController *)viewController {
  if (!_adChoicesView) {
    // Create or retrieve your AdChoices view.
  }
  // Place AdChoices View in mediated network's view.
  [view addSubview:_adChoicesView];

  switch (_nativeAdViewAdOptions.preferredAdChoicesPosition) {
    case GADAdChoicesPositionTopLeftCorner:
      // Adjust placement of _adChoicesView frame to top left corner.
      break;
    case GADAdChoicesPositionBottomLeftCorner:
      // Adjust placement of _adChoicesView frame to bottom left corner.
      break;
    case GADAdChoicesPositionBottomRightCorner:
      // Adjust placement of _adChoicesView frame to bottom right corner.
      break;
    case GADAdChoicesPositionTopRightCorner:
      // Fall through.
    default:
      // Default placement of AdChoices icon is the top right corner.
      // Adjust placement of _adChoicesView frame to top right corner.
      break;
  }

}

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd
          didUntrackView:(UIView *)view {
    // Remove SampleAdChoices view from its parent.
    [_adChoicesView removeFromSuperview];
}

Impression and click events

It's important that the mediated network's SDK be notified any time an impression or click occurs, so mapper classes are expected to provide the Google Mobile Ads SDK with a delegate object to use for this purpose. This is done via the mediatedNativeAdDelegate method. In the example above, the mapper class serves as its own delegate and returns itself:

- (id<GADMediatedNativeAdDelegate>)mediatedNativeAdDelegate {
  return self;
}

Because different networks handle processing clicks and impressions differently, the GADMediatedNativeAdDelegate protocol accommodates two different approaches.

Handle clicks and impressions within the mapper itself

If the mediated native ad objects provide methods to record clicks and impressions, an adapter's mapper classes can use them. This is the most common approach. GADMediatedNativeAdDelegate includes two methods, mediatedNativeAdDidRecordImpression: and mediatedNativeAd:didRecordClickOnAssetWithName:, which mappers should override and use to call the corresponding method on the mediated native ad object.

Here's how the SampleMediatedNativeAppInstallAd handles this:

- (void)mediatedNativeAdDidRecordImpression<GADMediatedNativeAd>)mediatedNativeAd {
  if (self.sampleAd != nil) {
    [self.sampleAd recordImpression];
  }
}

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd
    didRecordClickOnAssetWithName:(NSString *)assetName
                             view:(UIView *)view
                   viewController:(UIViewController *)viewController {
  if (self.sampleAd != nil) {
    [self.sampleAd handleClick:view];
  }
}

Because the SampleNativeAppInstallAdMapper holds a reference to the Sample SDK's native ad object, it can simply call the appropriate method on that object to report a click or impression.

Let the mediated SDK track clicks and impressions

For ad networks that need to track clicks and impressions on their own, the GADMAdNetworkAdapter protocol offers two optional messages: handlesUserClicks and handlesUserImpressions. Returning a YES from one of these indicates the adapter tracks that type of event for itself. Returning a NO or not responding indicates that the Google Mobile Ads SDK should handle tracking clicks and impressions on behalf of the adapter and use mediatedNativeAdDidRecordImpression: and mediatedNativeAd:didRecordClickOnAssetWithName: to report them.

Adapters tracking clicks or impressions themselves can use the mediatedNativeAd:didRenderInView: message in the GADMediatedNativeAdDelegate protocol to pass the native ad's view to the mediated SDK's native ad object, so the mediated SDK can use it to do the actual tracking. The sample SDK shown so far in this guide's code examples doesn't use this approach for handling clicks and impressions, but if it did, the appropriate mediatedNativeAd:didRenderInView: method would look like this:

- (void)mediatedNativeAd:(id<GADMediatedNativeAd>)mediatedNativeAd didRenderInView:(UIView *)view {
  [self.sampleAd setNativeAdView:view];
}

GADMediatedNativeAdDelegate also includes mediatedNativeAd:didUntrackView:, which is used for the opposite purpose. Adapters should implement it to release any references to the view and if possible disassociate it from the native ad object.

GADMediatedNativeAdNotificationSource

In order for mediated native ads to report events like the presentation of a screen or recording of a click, the SDK provides the GADMediatedNativeAdNotificationSource class. It has six class methods corresponding to various events in the life of a mediated native ad, each taking a reference to the corresponding ad object:

  • mediatedNativeAdDidRecordImpression: - This method should be called by mediated native ads from adapters that track impressions for themselves to report an impression back to the Google Mobile Ads SDK. This is required for reporting purposes.
  • mediatedNativeAdDidRecordClick: - Similarly, adapters that track their own clicks should call have their mediated native ads call this method to report that a click has occurred.
  • mediatedNativeAdWillPresentScreen: - Must be called just before a mediated native ad opens an in-app modal screen.
  • mediatedNativeAdWillDismissScreen: - Must be called just before the in-app modal screen opened by the mediated native ad is dismissed.
  • mediatedNativeAdDidDismissScreen: - Must be called after an in-app modal screen opened by the mediated native ad is dismissed.
  • mediatedNativeAdWillLeaveApplication: - Must be called just before the mediated native ad causes focus to leave the application, such as when opening a destination URL in Safari.

That's it! You now have everything you need to write your own iOS mediation adapters for AdMob.

Send feedback about...

AdMob for iOS
AdMob for iOS
Need help? Visit our support page.