This guide is intended for publishers who want to use AdMob Mediation to load and display native ads from a network that isn't one of AdMob's Supported ad networks. See Custom Events for information about using AdMob Mediation to load and display banner, interstitial, or rewarded display ads.
Custom events are mediation adapter classes capable of requesting ads from another network. When you add the name of one of these classes to the mediation settings for an ad unit, the SDK can instantiate and use it to retrieve ads. Native custom event classes need to be able to do 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
GADMediatedNativeAdto 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 custom event project at our GitHub repository.
Prerequisites
To implement an AdMob custom event, 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 objects 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.
Request native ads
The requestNativeAdWithParameter: method
Custom event classes must implement the GADCustomEventNativeAd protocol,
which includes a method used by the Google Mobile Ads SDK to request
native ads from the custom event:
- (void)requestNativeAdWithParameter:(NSString *)serverParameter
request:(GADCustomEventRequest *)request
adTypes:(NSArray *)adTypes
options:(NSArray *)options
rootViewController:(UIViewController *)rootViewController;
When this method is called, the custom event should asynchronously
request a native ad. Four of the parameters for requestNativeAdWithParameter:
carry information that the custom event can use in making its request:
serverParameter- When adding a custom event to an ad unit's mediation configuration, publishers can enter a string value to be passed along with each request. This parameter holds that value (typically another ad unit ID, which was issued by the mediated network).request- AGADCustomEventRequestobject, which contains properties specific to a single request, such as which native formats are requested.GADCustomEventRequestalso includes properties for targeting information provided by publishers at request time.adTypes- AnNSArraycontaining constants that indicate which native formats are requested. Possible values includekGADAdLoaderAdTypeNativeContentandkGADAdLoaderAdTypeNativeAppInstall.options- AnNSArraycontainingGADAdLoaderOptionsobjects that indicate the publisher's preferences for loading ads.
In addition to the parameters carrying request information, the
rootViewController parameter provides a reference to the
UIViewController in which the ad is to be displayed.
Here's a code snippet from our example custom event
project
that shows an implemented requestNativeAdWithParameter: method:
SampleCustomEventNativeAd.m (excerpt)
- (void)requestNativeAdWithParameter:(NSString *)serverParameter
request:(GADCustomEventRequest *)request
adTypes:(NSArray *)adTypes
options:(NSArray *)options
rootViewController:(UIViewController *)rootViewController {
SampleNativeAdLoader *adLoader = [[SampleNativeAdLoader alloc] init];
SampleNativeAdRequest *sampleRequest = [[SampleNativeAdRequest alloc] init];
// Part of the custom event's job is to examine the properties of the GADCustomEventRequest and
// 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;
}
// This custom event uses the server parameter to carry an ad unit ID, which is the most common
// use case.
adLoader.adUnitID = serverParameter;
adLoader.delegate = self;
[adLoader fetchAd:sampleRequest];
}
This is a sample custom event that mediates to an imaginary ad network
via a mock "Sample SDK." The custom event uses the information provided
in the requestNativeAdWithParameter: parameters to request an ad from
the Sample SDK's SampleNativeAdLoader. It also assigns itself as the
delegate for theSampleNativeAdLoader, so it can forward events from
the Sample SDK back to the Google Mobile Ads SDK. That process is the
topic of the next section.
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 custom events 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, the mediated ad network only ever provides app install ads,
and the publisher requests content ads alone, your custom event should not
request an app install ad anyway and then try to map it to the content ad
format. Instead, it should call the delegate's
customEventNativeAd:didFailToLoadWithError: 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 custom events as one of the parameters in the
requestNativeAdWithParameter: method. Custom events 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 custom event
must return actual image assets rather than just the URLs. In this case,
if the SDK being adapted only ever provides URLs for images, then the custom
event 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 custom event 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 GADCustomEventNativeAd protocol includes a
delegate (of type GADCustomEventNativeAdDelegate), which the custom
event can use to forward them.
It's part of a custom event's job to act as a "man-in-the-middle,"
listening for events from the mediated SDK, and then sending the
corresponding GADCustomEventNativeAdDelegate protocol message to
the delegate as appropriate. Your custom event needs to be aware of
the following messages :
customEventNativeAd:didReceiveMediatedNativeAd:- This message should be sent when a custom event successfully loads a native ad. It takes a single parameter of typeGADMediatedNativeAd, which the custom event should use to pass an "adapted" version of the native ad it just loaded (GADMediatedNativeAdclasses are covered in the next section).customEventNativeAd:didFailToLoadWithError:- When the custom event tries and fails to load a native ad, it should use this method to report the failure. It takes a singleNSErrorparameter, which should contain information specific to the failure.
Here's an example of how this works in our example custom event project:
SampleCustomEventNativeAd.m (excerpt)
@interface SampleCustomEventNativeAd () <SampleNativeAdLoaderDelegate>
@end
@implementation SampleCustomEventNativeAd
@synthesize delegate;
...
#pragma mark SampleNativeAdLoaderDelegate implementation
- (void)adLoader:(SampleNativeAdLoader *)adLoader
didReceiveNativeAppInstallAd:(SampleNativeAppInstallAd *)nativeAppInstallAd {
SampleMediatedNativeAppInstallAd *mediatedAd = [[SampleMediatedNativeAppInstallAd alloc]
initWithSampleNativeAppInstallAd:nativeAppInstallAd];
[self.delegate customEventNativeAd:self didReceiveMediatedNativeAd:mediatedAd];
}
- (void)adLoader:(SampleNativeAdLoader *)adLoader
didReceiveNativeContentAd:(SampleNativeContentAd *)nativeContentAd {
SampleMediatedNativeContentAd *mediatedAd =
[[SampleMediatedNativeContentAd alloc] initWithSampleNativeContentAd:nativeContentAd];
[self.delegate customEventNativeAd:self didReceiveMediatedNativeAd:mediatedAd];
}
- (void)adLoader:(SampleNativeAdLoader *)adLoader
didFailToLoadAdWithErrorCode:(SampleErrorCode)errorCode {
NSError *error = [NSError errorWithDomain:customEventErrorDomain code:errorCode userInfo:nil];
[self.delegate customEventNativeAd:self didFailToLoadWithError:error];
}
...
@end
The class implements the Sample SDK's SampleNativeAdLoaderDelegate protocol.
In SampleCustomEventNativeAd.m (excerpt)
the custom event class itself was assigned to the SampleNativeAdLoader
as its delegate:
adLoader.delegate = self;
This ensures that the Sample SDK sends messages back to the custom event when it has success or failure to report. The custom event then sends the appropriate message to its own delegate, forwarding the event to the Google Mobile Ads SDK. In short, the Google Mobile Ads SDK listens to the custom event, 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 custom
event. The custom event creates a new NSError object with the
SampleErrorCode provided by the Sample SDK, and then sends it to its
own delegate via the customEventNativeAd:didFailToLoadWithError: 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, when a custom event receives a native ad
object from its mediated network's SDK, it should use a subclass of
GADMediatedNativeAd to "map" the mediated SDK's native ad object so
it matches 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.
Custom events 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 custom event project:
SampleMediatedNativeAppInstallAd.h (excerpt)
@interface SampleMediatedNativeAppInstallAd : NSObject<GADMediatedNativeAppInstallAd>
- (instancetype)initWithSampleNativeAppInstallAd:
(SampleNativeAppInstallAd*)sampleNativeAppInstallAd;
@end
SampleMediatedNativeAppInstallAd.m (excerpt)
@implementation SampleMediatedNativeAppInstallAd
- (instancetype)initWithSampleNativeAppInstallAd:
(nonnull SampleNativeAppInstallAd *)sampleNativeAppInstallAd {
if (!sampleNativeAppInstallAd) {
return nil;
}
self = [super init];
if (self) {
_sampleAd = sampleNativeAppInstallAd;
_extras = @{SampleCustomEventExtraKeyAwesomeness : _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 = @{SampleCustomEventExtraKeyAwesomeness : _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 custom event 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 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, a custom event'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:(id<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,
GADCustomEventNativeAd protocol offers two optional messages:
handlesUserClicks and handlesUserImpressions. Returning a YES
from one of these indicates the custom event tracks that type of
occurrence 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 custom event and use mediatedNativeAdDidRecordImpression:
and mediatedNativeAd:didRecordClickOnAssetWithName: to report them.
Custom events 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. Custom events 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 custom events that track impressions for themselves to report an impression back to the Google Mobile Ads SDK. This is required for reporting purposes.mediatedNativeAdDidRecordClick:- Similarly, custom events that track their own clicks should 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.
Use a custom event
To use a custom event, you need to add it to the mediation configuration for an ad unit. This is done in the AdMob interface. (Create a custom event provides detailed instructions for editing an ad unit's mediation configuration).
When you add the custom event to an ad unit's mediation configuration, you'll be asked for three pieces of information:
Class Name- This is the class name of your custom event.Label- This is the label you'd like AdMob's interface to use to represent the custom event when it displays the ad unit's mediation sources. It's just for you, as it only ever appears on AdMob.comParameter- This is a string value that is passed to the custom event whenever requests for this ad unit are made. Typically this value is set to an ad unit ID from the mediated network.
Here's a screenshot of an example custom event entry:

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