ios-guidelines | Native Ads

InMobi Native ads seamlessly blend in with your app’s content, maximizing user engagement without compromising on user experience. You can choose and customize the layout that best matches the design of your app. It is ideal for news, utility and communication apps.

InMobi Native Ads can have video and/or static image both. Depending on the placement you can opt for:

  • In-Feed Ad - a muted autoplay HD video or a simple static image ad.
  • Splash Ad - blends in the launch screen of apps and monetize user time when the app is loading in the background. These ads can also be a muted autoplay HD video ad or a simple static image ad.

Static Feed Ad

InFeed Video Ad

Splash Video Ad

Follow these simple steps and start monetizing with Native ads:

Setting up a Native Ad Placement

  1. Create a Native Content placement.

  2. In-Feed Video Ad Placement

    1. Select FEED as the Native Ad Layout.
    2. For In-Feed Video, select either of the aspect ratio 256:135 or 16:9. Both the aspect ratios will have default static native fallback enabled with similar aspect ratio.


    Static Feed Ad Placement

    1. Select FEED as the Native Ad Layout.

    2. In the integration code, please ensure -(UIView*)primaryViewOfWidth:(CGFloat)width <br>Specify width = 25 while fetching your primaryView. It will just show the AdChoices icon and fire the ad render events.

    Splash Video Ad Placement

    • Select SPLASH as the Native Ad Layout.

    • Select the desired aspect ratio. Default value for the aspect ratio will be 9:16.

    Others (China only)

    • Select Others as the Native Ad Layout.

    • Select aspect ratio 16:9. This will have default static native fallback enabled with similar aspect ratio.
    • A new sub field is added in Others layout called Native Layout Type. It has the following values: “Native Interstitial”, “Native Page”, “Native Banner”, “Native Focus”, “Native Lock Screen”, “Native Other”.
    • Default value will be Native Interstitial in Native layout type field.

    Pre-Roll Ad Integration

    • Select Pre-roll as the Native Ad Layout.

    • Save the Pre-roll native placement layout.

Native Ad APIs

The IMNative Class contains the following objects:

  • NSString* adTitle - Returns the title for the ad.
  • NSString* adDescription - Returns the description for the ad.
  • UIImage* adIcon - Returns icon image for the ad.
  • NSString* adCtaText - Returns click to action text for the ad.
  • NSString* adRating - Returns rating for the ad (optional).
  • NSURL* adLandingPageUrl - Returns landing URL for the ad.
  • BOOL isAppDownload - Returns whether the ad is for downloading an app.
  • NSString* customAdContent - This will have additional information (description, image URL, etc.), which can be used to create custom UI around the primary view of ad.

The IMNative Class supports the following functions:

  • -(UIView*)primaryViewOfWidth:(CGFloat)width - Returns a UIView of specified width. This is the main ad content in your native ad. It will return a view of the same aspect ratio that you selected on the InMobi dashboard while creating the native placement. All impression render events are also fired automatically when this primary view is displayed on the screen.

    If you have selected Feed Layout while creating your placement, specify width = 25 while fetching your primaryView. It will just show the AdChoices Icon and fire the ad render events.

  • -(void)load - Function to load an ad into memory.
  • -(BOOL)isReady - True implies that the ad is ready to be displayed.
  • -(void)reportAdClickAndOpenLandingPage - This function fires the click events and opens the landing page. You need not open landing page on your own while using this function.
  • -(void)recyclePrimaryView - Call this function whenever the ad goes out of the visible area on the screen. Also, call this before loading a native ad again on the same object.

In-Feed Ad Integration

  1. Import the InMobi SDK header files.
    #import <InMobiSDK/InMobiSDK.h>
    		
  2. Declare an ad position in your feed where you want to show ad. Example is to show ad at 4th position.
    #define IM_AD_INSERTION_POSITION 4
    		
  3. Declare a native Ad instance in your ViewController.m
    @interface TableViewController () <IMNativeDelegate>
    @property(nonatomic,strong) IMNative *InMobiNativeAd;
    @end
    		
  4. Your final ViewDidLoad Code should look like:
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.InMobiNativeAd = [[IMNative alloc] initWithPlacementId:<Insert InMobi 
                              placement ID here>];
        self.InMobiNativeAd.delegate = self;
        [self.InMobiNativeAd load];
        //Your app content
    }
    		
  5. Implement IMNativeDelegate methods for the success callback. The success callback indicates that the ad is ready to be shown on the screen. Here you should add the InMobiNativeAd Object to your TableView's data source.
    -(void)nativeDidFinishLoading:(IMNative*)native{
        [self.tableData insertObject:native atIndex:IM_AD_INSERTION_POSITION];
        [self.tableView reloadData];
        NSLog(@"Native Ad did finish loading");
    }
    		
  6. Rendering native ads and impression tracking

    You have successfully received a native ad when you get the callback nativeAdDidFinishLoading. The following example shows how to fetch the adView in your tableView delegate cellForRowAtIndexPath.

    Note: Impression events will be fired only when the Native Ad's primary view is in visible area of the screen.

     - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    	InFeedTableCell *cell = (InFeedTableCell *)[tableView 
                           dequeueReusableCellWithIdentifier:@"InFeedTableCell"];
    	NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"InFeedTableCell" 
                            owner:self options:nil];
    	cell = [nib objectAtIndex:0];
    	id slide = [self.tableData objectAtIndex:indexPath.row];
    	if ([self isAdAtIndexPath:indexPath]) {
            	IMNative * currentNativeAd = slide;
            	cell.iconImageView.image = currentNativeAd.adIcon;
           		cell.titleLabel.text = currentNativeAd.adTitle;
            	cell.subTitleLabel.text = @"Sponsored";
           		cell.descriptionLabel.text = currentNativeAd.adDescription;
            	cell.ctaLabel.text = currentNativeAd.adCtaText;
    		//Calculate your feed's primaryImageViewWidth and use it to fetch and
                     Ad Primary view of same width.
            	UIView* AdPrimaryViewOfCorrectWidth = [currentNativeAd 
                   primaryViewOfWidth:primaryImageViewWidth];
    		//Set the frame of Ad Primary View same as that of your feed's Primary 
                     View
    		AdPrimaryViewOfCorrectWidth.frame = primaryImageViewFrame;
                  [cell addSubview:AdPrimaryViewOfCorrectWidth];
                  UITapGestureRecognizer *singleTapAndOpenLandingPage = 
                  [[UITapGestureRecognizer alloc] initWithTarget:currentNativeAd 
                  action:@selector(reportAdClickAndOpenLandingPage)];
            	cell.ctaLabel.userInteractionEnabled = YES;
            	[cell.ctaLabel addGestureRecognizer:singleTapAndOpenLandingPage];
        	}
    	else{
    		//Your App’s TableCell implementation
    	}
            return cell;
    }
    		
  7. You need to recycle the Native Ad's Primary view, every time your ad goes out of the screen area. This is to optimize memory usage as well as ensuring that the AdView does not conflict with your app’s native views. Call recyclePrimaryView method on the InMobiNativeAd object every time the ad goes out of the visible area. In a TableView, this can be called in the didEndDisplayingCell Method:
    - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
        if([self isAdAtIndexPath:indexPath]){
            [self.InMobiNativeAd recyclePrimaryView];
        }
    }
    		

    Note: After calling the recyclePrimaryView, if you want to add the view again on the screen, you must fetch it from [self.InMobiNativeAd primaryViewOfWidth:<custom width>] as the previous view would have been recycled. If you have added it in the cellForRowAtIndexPath delegate (as mentioned in step 8), you don’t have to do anything here.

  8. Refreshing the ad - You will need to refresh the ad at various points to optimize ad exposure to your users. To refresh the ad, you will need to call the following functions in the same order.

    Note: It is important to remove the IMNative object from your tableData and destroy the current ad object. Then you need to create a new object and call load on it. Also, you should recycle the Primary View before destroying your existing object.

    -(void)refreshInMobiStrandAd {
       [self.tableData removeObject:self.InMobiNativeAd];
       [self.tableView reloadData];
       [self.InMobiNativeAd recyclePrimaryView];
       self.InMobiNativeAd = [[IMNative alloc] initWithPlacementId:<Insert InMobi 
       placement ID here>];
       self.InMobiNativeAd.delegate = self;
       [self.InMobiNativeAd load];
    }
    		
  9. Handling Orientation Change - You will need to calculate the new width for Ad Primary View on orientation change and call the [self.InMobiNativeAd primaryViewOfWidth:<custom width>] method again to replace the current Ad Primary View with the new view.
  10. You should set the InMobiNativeAd object and its delegate to nil in the dealloc method of your ViewController class. Do ensure you recycle the view before deallocating to remove all references to the adView.
    -(void)dealloc {
    	[self.InMobiNativeAd recyclePrimaryView];
    	self.InMobiNativeAd.delegate = nil;
    	self.InMobiNativeAd = nil;
    }
    		

Splash Ad Integration

  1. Splash experience can be implemented using the same IMNative Class.
  2. You should use self.InMobiNativeAd.isReady function to determine if the ad is ready to be shown. Sometimes, your main thread may be occupied and hence you may not receive nativeDidFinishLoading in time. Hence, its better to proactively check if the ad is ready just after your cut-off time has elapsed.
  3. IMPORTANT: You should NOT dismiss the ad if the second screen of the ad is in display. You can check this in the nativeWillPresentScreen and not dismiss the ad if this delegate is fired. Sample implementation is as follows:
    @property(nonatomic,strong) bool *isSecondScreenDisplayed;// Use this to check if second screen has to be shown or not 
    -(void)nativeWillPresentScreen:(IMNative*)native{
        NSLog(@"Native Ad will present screen");
        isSecondScreenDisplayed = YES;
    }
    		
  4. You should recycle the Primary View before dismissing the ad. This can be implemented as follows:
    @property (nonatomic, strong) UIView* SplashAdView; // Use this view to check for visibility of splash screen 
    -(void)dismissAd{
        if(isSecondScreenDisplayed){
            NSLog(@"DO NOT DISMISS THE AD WHILE THE SCREEN IS BEING DISPLAYED");
        }
        else{
            self.SplashAdView.hidden = true;
            [self.InMobiNativeAd recyclePrimaryView];
            self.InMobiNativeAd = nil;
        }
    }
    		

Pre-Roll Ad Integration

  1. Pre-Roll Video experience can be implemented using the same IMNative Class. You will need to dismiss the ad view in the following delegate:
    -(void)nativeDidFinishPlayingMedia:(IMNative *)native{
        [self dismissAd];
    }
    		
  2. The Pre-Roll ad can be dismissed as follows:
    @property (nonatomic, strong) UIView* PrerollAdView; //Use this to store the primaryView returned by the IMNative instance.
    -(void)dismissAd{
        self.PrerollAdView.hidden = true;
        [self.InMobiNativeAd recyclePrimaryView];
        self.InMobiNativeAd = nil;
    }
    		

Advanced

You can perform the following steps to get additional callbacks. Implement the following delegate methods in your ViewController.m file:

-(void)nativeDidFinishLoading:(IMNative*)native{
    NSLog(@"Native Ad load Successful"); // Ad is ready to be displayed
}
-(void)native:(IMNative*)native didFailToLoadWithError:(IMRequestStatus*)error{
    NSLog(@"Native Ad load Failed"); // No Fill or error
}
-(void)nativeWillPresentScreen:(IMNative*)native{
    NSLog(@"Native Ad will present screen"); //Full Screen experience is about to be presented
}
-(void)nativeDidPresentScreen:(IMNative*)native{
    NSLog(@"Native Ad did present screen"); //Full Screen experience has been presented
}
-(void)nativeWillDismissScreen:(IMNative*)native{
    NSLog(@"Native Ad will dismiss screen"); //Full Screen experience is going to be dismissed
}
-(void)nativeDidDismissScreen:(IMNative*)native{
    NSLog(@"Native Ad did dismiss screen"); //Full Screen experience has been dismissed
}
-(void)userWillLeaveApplicationFromNative:(IMNative*)native{
    NSLog(@"User leave"); //User is about to leave the app on clicking the ad
}
-(void)native:(IMNative *)native didInteractWithParams:(NSDictionary *)params{
    NSLog(@"User clicked"); // Called when the user clicks on the ad.
}
-(void)nativeAdImpressed:(IMNative *)native{
    NSLog(@"User viewed the ad"); // Called when impression event is fired.
}
-(void)nativeDidFinishPlayingMedia:(IMNative*)native{
    NSLog(@"The Video has finished playing"); // Called when the video has finished playing. Used for preroll use-case
}
-(void)native:(IMNative *)native rewardActionCompletedWithRewards:(NSDictionary *)rewards{
    NSLog(@"Rewarded"); // Called when the user is rewarded to watch the ad.
}
-(void)userDidSkipPlayingMediaFromNative:(IMNative*) native {
    NSLog(@"User has skipped playing media"); // Called when the user has opted to skip the media being shown. 
}
-(void)native:(IMNative*)native adAudioStateChanged:(BOOL)audioStateMuted {
     if (audioStateMuted) {
        NSLog(@"Inline video-ad audio state changed to mute");
    } else {
        NSLog(@"Inline video-ad audio state changed to unmute");
    }
   //This is called when inline video audio state changes.
}
	

Implementing Backfill

InMobi's SDK can run both HTML and native units against your native placement. You can run the following ad sizes depending on the real-estate reserved for your native placement.

  • 320x50 HTML Banner
  • 300x250 HTML Banner
  • 320x480 HTML Full screen Banner
  • 320x568 HTML Full screen Banner
To switch this on, you need to reach out to your respective partner manager with the preferred backfill size. Also, you will need to handle this in your code as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
	InFeedTableCell *cell = (InFeedTableCell *)[tableView 
                       dequeueReusableCellWithIdentifier:@"InFeedTableCell"];
	NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"InFeedTableCell" 
                        owner:self options:nil];
	cell = [nib objectAtIndex:0];
	id slide = [self.tableData objectAtIndex:indexPath.row];
	if ([self isAdAtIndexPath:indexPath]) {
		IMNative *currentNativeAd = slide;
        	NSString *customJSONstring = currentNativeAd.customAdContent;
       		NSData *data = [customJSONstring dataUsingEncoding:NSUTF8StringEncoding];
        	NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        	BOOL isBackFillBanner = [[jsonDict objectForKey:@"isHTMLResponse"] boolValue];
		if (isBackFillBanner) {
		 {
			IMNative * currentNativeAd = slide;
			//Depending on the selected backfill size, provide accurate width below
			UIView* AdPrimaryViewOfCorrectWidth = [currentNativeAd primaryViewOfWidth:250];
			AdPrimaryViewOfCorrectWidth.frame = CGRectMake((_screenWidth-300)/2, 0, 300, 250);
           		[cell addSubview:AdPrimaryViewOfCorrectWidth];
		}
		else
		{
			//continue with the current native implementation
        		IMNative * currentNativeAd = slide;
        		cell.iconImageView.image = currentNativeAd.adIcon;
       			cell.titleLabel.text = currentNativeAd.adTitle;
        		cell.subTitleLabel.text = @"Sponsored";
       			cell.descriptionLabel.text = currentNativeAd.adDescription;
        		cell.ctaLabel.text = currentNativeAd.adCtaText;
			//Calculate your feed's primaryImageViewWidth and use it to fetch and Ad Primary view of same width.
        		UIView* AdPrimaryViewOfCorrectWidth = [currentNativeAd primaryViewOfWidth:primaryImageViewWidth];
			//Set the frame of Ad Primary View same as that of your feed's Primary View
			AdPrimaryViewOfCorrectWidth.frame = primaryImageViewFrame;
           		 [cell addSubview:AdPrimaryViewOfCorrectWidth];
           		 UITapGestureRecognizer *singleTapAndOpenLandingPage = 
              		[[UITapGestureRecognizer alloc] initWithTarget:currentNativeAd 
              		action:@selector(reportAdClickAndOpenLandingPage)];
        		cell.ctaLabel.userInteractionEnabled = YES;
        		[cell.ctaLabel addGestureRecognizer:singleTapAndOpenLandingPage];
    		}
	}	
	else {
		//Your App’s TableCell implementation
	}
        return cell;
}
	

Note:

  • To detect if the response is backfill, the customAdContent will contain the string isHTMLResponse.
  • Do NOT scale the width of the HTML banner response. For e.g. if you selected backfill of 300x250, make sure the provided width is hardcoded 250.
  • Do NOT add the CTA button in case of backfill response. The clicks will not be monetized in case you add this button alongside the ad.

Retrieving CreativeID

At times, there are rogue advertisers who escape all the ad quality checks and end up compromising the user experience on the app by showcasing either an irrelevant, distasteful or disrupting creative to the user. To combat such situations, you can retrieve the creativeID of the ad instance and report back to your InMobi point of contact with the encrypted creativeID.

mNativeAd.creativeId // mNativeAd is an example instance.

Testing the Integration

  1. Configure the test mode on InMobi portal.

    Go to Tools - Diagnostics and switch Test Mode to either Global ON or Selective ON.

    If you are integrating an ad unit for the first time Set Test Mode to Global ON.
    If you want to selectively turn on test traffic for a set of devices·

    You already have a prior version of the SDK integrated for this particular ad unit and therefore you should restrict your testing to only few devices
    Set Test Mode to Selective ON.

    In the device section:

    1. In the Device ID box, type the device ID.
    2. In the Device Name box, set any name.
    3. Click Add Device to add the test device.

    If you already have a device configured, you can select the device and test mode would be enabled.

    Note: You MUST turn off the test mode before going live or else your app will fail to monetize.

    Now you are all set to get test ads.

    Getting the Device ID

    The device id is basically the IDFA or IFA (Identifier for Advertising). To get device ID, the easiest approach is to set the log level of the SDK to “debug”. To enable debug logs, add this to didFinishLaunchingWithOptions method within the AppDelegate.m file, as shown below:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {    
    	//Initialize InMobi SDK with your account ID
    [IMSdk initWithAccountID:@"Insert InMobi account ID here"];
    //Set log level to Debug
    [IMSdk setLogLevel:kIMSDKLogLevelDebug]; 
    	// Do your stuff.
    	return YES;
    }
    		

    In the debug mode, the device ID will be logged on XCode developer console as: “Publisher device ID is <device-id>”

    You can enter this device id in the Device ID box.

  2. You will also get feedback on the diagnostics tab on the ad unit and ad request and this can be particularly helpful during integration.

  3. You should also see these key InMobi SDK logs in console when a native ad is successfully loaded:

    [InMobi] InMobi SDK initialized with account id: <your account id here>

    [InMobi] Fetching native ad for placement id: <your placement id here>

    [InMobi] Publisher device id is <device id here>

    [InMobi] Native ad successfully fetched for placement id: <your placement id here>

  4. Now you would also see the InMobi test ads on your application.
  5. If the SDK is not initialised correctly before creating an ad, you would typically see these logs :

    ** ERROR ** [InMobi] ___ Please initialize the SDK before creating a <ad format> ad.

    ** ERROR ** [InMobi] ___ Account id cannot be null or empty. Please provide a valid Account id.

    [InMobi] Invalid account id passed to init. Please provide a valid account id.

Common SDK Initialization Messages

Log Level Scenario Displayed Message
Error SDK is not initialized Please initialize the SDK before creating xxx ad.
Error The ATS state for Ad server URL is invalid ATS Configuration not supported. Kindly remove InMobi from the exception list.
Error Account ID provided to initializeSDKWithAccountID is empty or null. Account id cannot be null or empty. Please provide a valid Account id.
Debug Publisher passed a valid account id InMobi SDK initialized with account id:<Account-Id>
Debug When account id length is not valid Invalid account id passed to init. Please provide a valid account id.
Debug Newer version of SDK is available A newer version (ver. 6.0.1) of the InMobi SDK is available! You are currently on an older version (Ver. 6.0.0). Please download the latest InMobi SDK from http://www.inmobi.com/products/sdk/#downloads

Common Ad Lifecycle Messages

Log Level Scenario Displayed Message
Error PlacementID provided is invalid (<=0) Please provide a valid placement id to create a xx ad.
Error Invalid banner placement id is being called Please give a valid placement id before calling load
Error Current state of ad is Loading or AdAvailable An ad load is already in progress. Please wait for the load to complete before requesting for another ad. Rejected placement id: xx
Error Current state of ad is Active An ad is currently being viewed by the user. Please wait for the user to close the ad before requesting for another ad. Rejected placement id: xx
Error Ad is being refreshed before the minimum refresh interval as mentioned in config Ad cannot be refreshed before xxx secs
Error Current state of ad is not ready. Ad Load is not complete. Please wait for the Ad to be in a ready state before calling show
Error Show is called on an Interstitial ad, but the app does not currently pass a view controller Full screen ad cannot be displayed without a view controller. Please pass a view controller to present the full screen ad.
Error Current state of ad is not attached/ rendered or active. reportAdClick call made in wrong state
Debug Publisher device Id Publisher device id is <Device-ID>
Debug When Monetization is disabled from config SDK will not perform this load operation as monetization has been disabled. Please contact InMobi for further info.