InMobi Native Ads support both static and video ads. You can opt for In-Feed, Splash, or Pre-Roll formats. The steps for creating a native ad placement are given below.
InMobi Native Ads support both static and video ads. You can opt for In-Feed, Splash , or Pre-Roll formats. The steps for creating a native ad placement are given below.
Once the native placement is created, you will be able to see the placement ID.

The IMNative Class contains the following objects:
@objc public var adTitle: String? - Returns the title for the ad.@objc public var adDescription: String? - Returns the description for the ad.@objc public var adIcon: IMNativeImage? - Returns icon image for the ad.@objc public var adCtaText: String? - Returns click to action text for the ad.@objc public var adRating: String? - Returns rating for the ad (optional).@objc public var advertiserName: String? - Returns advertiser name for the ad. (optional).@objc public var adChoice: UIImageView? - Returns ad choice view for the ad. (optional).The IMNative Class supports the following functions:
@objc public func load() - Function to load an ad into memory.@objc public func isReady() -> Bool - True implies that the ad is ready to be displayed.@objc public func getCustomAdContent() -> [String: Any]? - This will have additional information (description, image URL, etc.), which can be used to create custom UI around the primary view of ad.@objc public func isVideoAd() -> Bool - True implies that the ad is a video ad.@objc public func registerViewForTracking(_ view: IMNativeViewData) - Registers your native ad UI for viewability, impression, and click tracking.@objc public func getMediaView() -> UIView? - Returns the SDK-managed media view (image or video) for this ad, if available.Import the InMobi SDK header files.
#import <InMobiSDK/InMobiSDK.h>
import InMobiSDK
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
let adInsertionPosition = 4
Declare a native Ad instance in your ViewController.m.
@interface TableViewController () <IMNativeDelegate>
@property(nonatomic,strong) IMNative *InMobiNativeAd;
@end
class ViewController: UIViewController, IMNativeDelegate {
var inMobiNativeAd: IMNative?
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
}
override func viewDidLoad() {
super.viewDidLoad()
inMobiNativeAd = IMNative(placementId: <Insert InMobi plc id> )
inMobiNativeAd?.delegate = self
inMobiNativeAd?.load()
// Your app content
}
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");
}
func nativeDidFinishLoading(_ native: IMNative!) {
self.tableData.insert(native, at: IM_AD_INSERTION_POSITION)
self.tableView.reloadData()
NSLog("InMobi Native Did finished loading");
}
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.
Impression events will be fired only when the Native Ad's primary view is in visible area of the screen.
Implement the below custom cell class using storyboard.
#import <uikit uikit.h="">
@interface InFeedTableViewCell : UITableViewCell
@property (nonatomic, weak) IBOutlet UIImageView *iconImage;
@property (nonatomic, weak) IBOutlet UILabel *titleLabel;
@property (nonatomic, weak) IBOutlet UILabel *subtitleLabel;
@property (nonatomic, weak) IBOutlet UILabel *descriptionLabel;
@property (nonatomic, weak) IBOutlet UILabel *ctaLabel;
@property (nonatomic, weak) IBOutlet UIView *adView;
@property (nonatomic, weak) IBOutlet UIImageView *adChoice;
@end
</uikit>
class InFeedTableViewCell: UITableViewCell {
@IBOutlet weak var iconImage : UIImage?
@IBOutlet weak var titleLabel : UILabel?
@IBOutlet weak var subtitleLabel : UILabel?
@IBOutlet weak var descriptionLabel : UILabel?
@IBOutlet weak var ctaLabel : UILabel?
@IBOutlet weak var adView : UIView?
@IBOutlet weak var adChoice: UIImageView!
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
InFeedTableCell *cell = ( *)[tableView dequeueReusableCellWithIdentifier:@"InFeedTableCell"];
id nativeAd = [self.tableData objectAtIndex:indexPath.row];
if ([nativeAd isKindOfClass:[IMNative Class]]]) {
IMNative * currentNativeAd = nativeAd;
cell.iconImage.image = currentNativeAd.adIcon.imageview;
cell.titleLabel.text = currentNativeAd.adTitle;
cell.subtitleLabel.text = @"Sponsored";
cell.descriptionLabel.text = currentNativeAd.adDescription;
cell.ctaLabel.text = currentNativeAd.adCtaText;
// Add ad choice view
[cell.adChoice addSubview:currentNativeAd.adChoice];
cell.adChoice.userInteractionEnabled = YES;
// Add media view
UIView *mediaView = [currentNativeAd getMediaView];
[cell.adView addSubview:mediaView];
// Register native ad views for tracking
IMNativeViewDataBuilder *builder = [[IMNativeViewDataBuilder alloc] initWithParentView:self.cell];
[builder setTitleView:cell.titleLabel];
[builder setDescriptionView:cell.descriptionLabel];
[builder setCTAView:cell.ctaLabel];
[builder setIconView:(UIImageView *)cell.iconImage];
IMNativeViewData *nativePubData = [builder build];
[currentNativeAd registerViewForTracking:nativePubData];
}
else{
//Your App’s TableCell implementation
}
return cell;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = (tableView.dequeueReusableCell(withIdentifier: "InFeedTableCell")! as! InFeedTableViewCell)
if let currentNativeAd = self.tableData?[indexPath.row] as? IMNative {
cell.iconImageView.image! = currentNativeAd.adIcon?.imageview
cell.titleLabel!.text! = currentNativeAd.adTitle
cell.subtitleLabel?.text! = "Sponsored"
cell.descriptionLabel.text! = currentNativeAd.adDescription
cell.ctaLabel?.text! = currentNativeAd.adCtaText
// Add ad choice view
cell.adChoice.addSubview(currentNativeAd.adChoice)
cell.adChoice.isUserInteractionEnabled = true
// Add media view
let mediaView = currentNativeAd.getMediaView()
adView.addSubview(mediaView)
// Register native ad views for tracking
let nativePubData = IMNativeViewData.Builder(parentView: cell)
.setTitleView(cell.adTitle)
.setDescriptionView(cell.descriptionLabel)
.setIconView(cell.adIcon)
.setCTAView(cell.CtaButton)
.build()
currentNativeAd?.registerViewForTracking(nativePubData)
}
else {
// Your app's Table Cell implementations
}
return cell
}
When implementing ad placements in reusable table view cells, it’s essential to clear out any previously loaded ad before displaying a new one. To achieve this, override the prepareForReuse() method in your custom UITableViewCell subclass. This ensures that any old ad views or data are removed, preventing overlapping content, memory leaks, or incorrect ad rendering during cell reuse.
- (void)prepareForReuse {
[super prepareForReuse];
// Remove previously added ad/media subviews
for (UIView *v in self.adView.subviews) {
[v removeFromSuperview];
}
// Optionally clear icon/title/etc. if you want:
// self.iconImage.image = nil; self.titleLabel.text = nil; ...
}
override func prepareForReuse() {
super.prepareForReuse()
_ = adView.subviews.map { $0.removeFromSuperview()}
// Optionally clear icon/title/etc. if you want:
// self.iconImage.image = nil; self.titleLabel.text = nil; ...
}
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.
// Suggested approach
// Use`- (void)prepareForReuse` in UItableViewCell to clear out any ad before loading
//
-(void)refreshInMobiStrandAd {
[self.tableData removeObject:self.InMobiNativeAd];
[self.tableView reloadData];
self.InMobiNativeAd = [[IMNative alloc] initWithPlacementId:];
self.InMobiNativeAd.delegate = self;
[self.InMobiNativeAd load];
}
//Suggested approach
//Use `override func prepareForReuse()` in UItableViewCell to clear out any ad before loading
// any new Ad.
func refreshInMobiStrandAd() {
tableData = tableData?.filter({ (obj) -> Bool in
if obj is IMNative {
return false
}
return true
})
tableView.reloadData()
inMobiNativeAd = IMNative(placementId: )
inMobiNativeAd?.delegate = self
inMobiNativeAd?.load()
}
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.
autolayout to handle all orientaiton changes on your cell and views. Ad will respond to auto layout changes.You should set the InMobiNativeAd object and its delegate to nil in the dealloc method of your ViewController class.
-(void)dealloc {
self.InMobiNativeAd.delegate = nil;
self.InMobiNativeAd = nil;
}
deinit {
inMobiNativeAd?.delegate = nil
inMobiNativeAd = nil
}
IMNative Class.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, it is better to proactively check if the ad is ready just after your cut-off time has elapsed.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;
}
var isSecondScreenDisplayed: Bool = false// Use this to check if second screen has to be shown or not
func nativeWillPresentScreen(_ native: IMNative) {
print("Native Ad will present screen")
isSecondScreenDisplayed = true
}
You should set the InMobiNativeAd object and its delegate to nil.
@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 = nil;
}
}
var splashAdView: UIView? // Use this to check visibility of second screen
func dismissAd() {
if isSecondScreenDisplayed {
print("DO NOT DISMISS THE AD WHILE THE SCREEN IS BEING DISPLAYED")
}
else {
splashAdView?.isHidden = true
inMobiNativeAd = nil
}
}
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];
}
func nativeDidFinishPlayingMedia(_ native: IMNative) {
self.dismissAd()
}
You should set the InMobiNativeAd object and its delegate to nil.
@property (nonatomic, strong) UIView* PrerollAdView; //Use this to store the primaryView returned by the IMNative instance.
-(void)dismissAd{
self.PrerollAdView.hidden = true;
self.InMobiNativeAd = nil;
}
var prerollAdView: UIView? // Use this to store the primaryView returned by the IMNative instance.
func dismissAd() {
prerollAdView?.isHidden = true
inMobiNativeAd = nil
}
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 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.
}
func nativeDidFinishLoading(_ native: IMNative) {
print("Native Ad load Successful") // Ad is ready to be displayed
}
func native(_ native: IMNative, didFailToLoadWithError error: IMRequestStatus) {
print("Native Ad load Failed") // No Fill or error
}
func nativeWillPresentScreen(_ native: IMNative) {
print("Native Ad will present screen") //Full Screen experience is about to be presented
}
func nativeDidPresentScreen(_ native: IMNative) {
print("Native Ad did present screen") //Full Screen experience has been presented
}
func nativeWillDismissScreen(_ native: IMNative) {
print("Native Ad will dismiss screen") //Full Screen experience is going to be dismissed
}
func nativeDidDismissScreen(_ native: IMNative) {
print("Native Ad did dismiss screen") //Full Screen experience has been dismissed
}
func userWillLeaveApplicationFromNative(_ native: IMNative) {
print("User leave") //User is about to leave the app on clicking the ad
}
func native(_ native: IMNative, didInteractWithParams params: [String : Any]?) {
print("User clicked") // Called when the user clicks on the ad.
}
func nativeAdImpressed(_ native: IMNative) {
print("User viewed the ad") // Called when impression event is fired.
}
func nativeDidFinishPlayingMedia(_ native: IMNative) {
print("The Video has finished playing") // Called when the video has finished playing. Used for preroll use-case
}
func native(_ native: IMNative, adAudioStateChanged audioStateMuted: Bool) {
if (audioStateMuted) {
print("Inline state changed to mute")
}
else {
print("Inline state changed to unmute")
}
}
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.
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;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = (tableView.dequeueReusableCell(withIdentifier: "InFeedTableCell")! as! InFeedTableViewCell)
if let currentNativeAd = self.tableData?[indexPath.row] as? IMNative {
let customJSONstring = currentNativeAd.customAdContent
if let data = customJSONstring?.data(using: .utf8) {
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
if let isBackFillBanner = json["isHTMLResponse"] as? Bool, isBackFillBanner {
//Depending on the selected backfill size, provide accurate width below
let adPrimaryViewOfCorrectWidth: UIView = currentNativeAd.primaryView(ofWidth: 250)
adPrimaryViewOfCorrectWidth.frame = CGRect(x: (_screenWidth-300)/2, y: 0, width: 300, height: 250)
cell.addSubview(adPrimaryViewOfCorrectWidth)
} else {
//continue with the current native implementation
cell.iconImageView.image = currentNativeAd.adIcon
cell.titleLabel.text = currentNativeAd.adTitle
cell.subtitleLabel.text = "Sponsored"
cell.descriptionLabel.text = currentNativeAd.description
cell.ctaLabel?.text = currentNativeAd.adCtaText
//Calculate your feed's primaryImageViewWidth and use it to fetch and Ad Primary view of same width.
let adPrimaryViewOfCorrectWidth: UIView = currentNativeAd.primaryView(ofWidth: primaryImageViewWidth)
//Set the frame of Ad Primary View same as that of your feed's Primary View
let singleTapAndOpenLandingPage = UITapGestureRecognizer(target:currentNativeAd, action: #selector(self.reportAdClickAndOpenLandingPage))
cell.ctaLabel?.isUserInteractionEnabled = true
cell.ctaLabel?.addGestureRecognizer(singleTapAndOpenLandingPage)
}
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
}
}
return cell }
isHTMLResponse.By installing this SDK update, you agree that your Children Privacy Compliance setting remains accurate or that you will update that setting, whenever there is a change in your app's audience. You may update the app's Children Privacy Compliance settings at https://publisher.inmobi.com/my-inventory/app-and-placements.