SDK DocumentationRecipesAnnouncementsSupport Forum
AndroidiOSAnnouncementsSupport Forum
SDK Documentation

Feed via Native

📍

DEPRECATION NOTICE

On March 31, 2025, Taboola will sunset SDK 2.

Before then, please make sure to migrate to SDK 3 for iOS.

For CocoaPods, import TaboolaSDK into your bridging header.

#import <TaboolaSDK/TaboolaSDK.h>
import TaboolaSDK

For Carthage, import the framework:

#import <TaboolaFramework/TaboolaFramework.h>
import TaboolaFramework

Step 2: Initialize Taboola

Create a PublisherInfo object and init Taboola

PublisherInfo *publisherInfo = [[PublisherInfo alloc]initWithPublisherId:@"publisherId"];

[Taboola initWithPublisherInfo:publisherInfo];
let publisherInfo = PublisherInfo.init(publisherId: "publisherId")
Taboola.initWith(publisherInfo)
  • publisherId - Your publisher ID as provided to you by Taboola account manager

Step 3: Adding the TaboolaView

Using Frames

TaboolaView* taboolaView = [[TaboolaView alloc] initWithFrame:<CGRect>];
let taboolaView = TaboolaView()

Using Constraints

Starting from iOS SDK 2.3.7, it is possible to create a taboolaView using constraints

TaboolaView* taboolaView = [[TaboolaView alloc] init];
[taboolaView setConstraintsOn: YES];
let taboolaView = TaboolaView()
taboolaView.setConstraintsOn(true)

Step 4: Set the TaboolaView Object Properties

For your production properties, contact your account manager.
For testing properties, see further down in this page.

// An identification of a Taboola recommendation unit UI template (you might use different UI templates in different parts of the app, in which case you will need to get the applicable mode for each UI template) 
taboolaView.mode = @"my-mode";

// An identification of your publisher account on the Taboola system 
taboolaView.publisher = @"my-publisher";

// Sets the page type of the page on which the feed is displayed (one of article, photo, video, home, category, search) If you're not sure what is the right value, contact your account manager.
taboolaView.pageType = @"my-page-type";

// Sets the canonical URL for the page on which the feed is displayed
taboolaView.pageUrl = @"my-page-url";

//Sets the publisher internal ID for the page on which the feed is displayed
taboolaView.pageId = @"my-page-id";

// An identification of a specific placement in the app (you might place Taboola recommendation units in multiple placements in the app, in which case you should get applicable placement ids for each such placement) 
taboolaView.placement = @"my-placement";

//The target type of the page on which the widget is displayed. If you're not sure what is the right value, contact your account manager.
taboolaView.targetType = @"my-target-type";
// An identification of a Taboola recommendation unit UI template (you might use different UI templates in different parts of the app, in which case you will need to get the applicable mode for each UI template) 
taboolaView.mode = "my-mode"

// An identification of your publisher account on the Taboola system 
taboolaView.publisher = "my-publisher"

// Sets the page type of the page on which the widget is displayed (one of article, photo, video, home, category, search) If you're not sure what is the right value, contact your account manager.
taboolaView.pageType = "my-page-type"

// Sets the canonical URL for the page on which the widget is displayed
taboolaView.pageUrl = "my-page-url"

//Sets the publisher internal ID for the page on which the widget is displayed
taboolaView.pageId = "my-page-id"

// An identification of a specific placement in the app (you might place Taboola recommendation units in multiple placements in the app, in which case you should get applicable placement ids for each such placement) 
taboolaView.placement = "my-placement"

//The target type of the page on which the widget is displayed. If you're not sure what is the right value, contact your account manager.
taboolaView.targetType = "my-target-type"
  • publisher - Your publisher id parameter as provided by your Taboola account manager
  • mode - Your mode parameter as provided by your Taboola account manager
  • placement - Your placement parameter as provided by your Taboola account manager
  • pageUrl - The full URL of public web page which reflects the current screen's content
  • pageId - An internal identification for the current screen's content. Pass this along the page URL to set the item ID as your internal ID
  • pageType - Your page type parameter as provided by your Taboola account manager
  • targetType - Your target type parameter as provided by your Taboola account manager

Step 5: Fetch Content

To show the feed, call fetchContent when the screen (view) loads

- (void)viewDidLoad{
	[super viewDidLoad];

	// Load taboolaView with testing values
	taboolaView.delegate = self;
	taboolaView.ownerViewController = self;
	taboolaView.mode = @"thumbs-feed-01";
	taboolaView.publisher = @"sdk-tester";
	taboolaView.pageType = @"article";
	taboolaView.pageUrl = @"http://blog.taboola.com";
	taboolaView.placement = @"Feed without video";
	taboolaView.targetType = @"mix";

	// Fill taboolaView with recommendations 
	[taboolaView fetchContent];
}
override func viewDidLoad() {
        super.viewDidLoad()
        
        // Load taboolaView with testing values
				taboolaView.delegate = self
        taboolaView.ownerViewController = self
        taboolaView.mode = "thumbs-feed-01"
        taboolaView.publisher = "sdk-tester"
        taboolaView.pageType = "article"
        taboolaView.pageUrl = "http://blog.taboola.com"
        taboolaView.placement = "Feed without video"
        
        // Fill taboolaView with recommendations 
        taboolaView.fetchContent()
    }

🚧

Important!

  • To maintain good UX - please fetch content as soon as the screen loads and not when the user reaches the Taboola area on the screen
  • When working with UIPageViewController, Please fetch the widget content only when the view is visible to the user
  • Make sure you load the taboolaView object only from the main UI thread

Step 6: Set the cell height (In UICollectionView or UITableView)

Taboola Feed is using a static height. Please give the cell containing the feed a static height:

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
	CGSizeMake(self.view.frame.size.width, TaboolaView.widgetHeight));
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        CGSize(width:self.view.frame.width,height: TaboolaView.widgetHeight())
    }

Step 7: Set the scrolling behavior

Taboola Feed has a fixed size, usually in the bottom of the screen. When the user is scrolling down the screen, and the Feed is taking up the entire screen, the scrolling is switched from the app into Taboola Feed.

There are two ways of doing so:

  • Handled by Taboola's SDK - The SDK will detect when the Feed is taking over the screen and will handover the scroll from the app into the Feed.
  • Manually by the app - in case the app is implementing it own custom scrolling by listening to the native OS scroll listener

In addition to the above two ways, the publisher can retain the scrollling back at any time by using the taboolaView.releaseScroll method

Handled by Taboola's SDK
Set the setInterceptScroll function to true in order to let Taboola's SDK to identify when it's the right moment to conduct the scroll switch from your app to Taboola's Feed

// To enable scroll switch between the scrollView and taboolaView
[taboolaView setInterceptScroll:YES];
taboolaView.setInterceptScroll(true)

Manually by the app
To manually hand over the scroll from the app into the Feed, you need to listen to the scrollViewDidScroll that notifies when the Feed is on the top of the screen and is scrolled up.

[self.taboolaView setOverrideScrollIntercept:YES];

//Add the TaboolaView delegate function
- (void)scrollViewDidScrollToTopTaboolaView:(UIView*)taboolaView

//Listen to the UIScrollView delegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
taboolaView.overrideScrollIntercept = true

//Add the TaboolaView delegate function
func scrollViewDidScroll(toTopTaboolaView taboolaView: UIView!)

//Listen to the UIScrollView delegate
override func scrollViewDidScroll(_ scrollView: UIScrollView)

Example:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    NSLog(@"scrollViewDidScroll! %f",scrollView.contentOffset.y);
    
    [self didEndScrollOfParentScroll];
}

-(BOOL)didEndScrollOfParentScroll {
    float height = self.collectionView.frame.size.height;
    float contentYoffset = self.collectionView.contentOffset.y;

    if (@available(iOS 11.0, *)) {
        contentYoffset = contentYoffset - self.collectionView.adjustedContentInset.bottom;
    }
    else {
        contentYoffset = contentYoffset - self.collectionView.contentInset.bottom;
    }

    float distanceFromBottom = self.collectionView.contentSize.height - contentYoffset;
    if (distanceFromBottom < height && self.collectionView.scrollEnabled && self.collectionView.contentSize.height > 0) {
        self.collectionView.scrollEnabled = NO;
        NSLog(@"did finish scrolling");
        [self.taboolaView setScrollEnable:YES];
        [self.taboolaView startProgressBarAnimation];
        return YES;
    }
    
    return NO;
}

- (void)scrollViewDidScrollToTopTaboolaView:(UIView*)taboolaView {
    if (self.taboolaView.scrollEnable) {
        NSLog(@"did finish scrolling taboola");
        [self.taboolaView setScrollEnable:NO];
        self.collectionView.scrollEnabled = YES;
        [self.taboolaView startProgressBarAnimation];
    }

}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        self.didEndScrollOfParentScroll()
    }
    
    func didEndScrollOfParentScroll() {
        if let cv = collectionView {
            let height = cv.frame.size.height
            var contentYoffset = cv.contentOffset.y
            
            if #available(iOS 11.0, *) {
                contentYoffset = contentYoffset - cv.adjustedContentInset.bottom
            } else {
                contentYoffset = contentYoffset - cv.contentInset.bottom
            }
            
            let distanceFromBottom = cv.contentSize.height - contentYoffset
            
            if distanceFromBottom < height && cv.isScrollEnabled && cv.contentSize.height > 0 {
                collectionView?.isScrollEnabled = false
                taboolaCell!.taboolaView.scrollEnable = true
                
                print("did finish scrolling")
            }
        }
        
    }
    
    func scrollViewDidScroll(toTopTaboolaView taboolaView: UIView!) {
        if taboolaCell!.taboolaView.scrollEnable {
            print("did finish scrolling taboola")
            collectionView?.isScrollEnabled = true
            taboolaCell!.taboolaView.scrollEnable = false
        }
    }

releaseScroll method
When the scrolling is controlled by Taboola, after the scroll switch, there are situations where the screen goes back to the top. Usually, it happens after orientation change, after the user clicks an iten and etc. To gain back control over the scrolling, invoke the releaseScroll method

//After oreintation change:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
	[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[_taboolaView releaseScroll];
	[self reloadViews];
}

//After back-to-top gesture
- (void)scrollCollectionToTop {
if (@available(iOS 11.0, *)) {
	// the content hides under NavigationBar on iOS 11.0 and above.
	[self.collectionView setContentOffset:CGPointMake(0, -self.navigationController.navigationBar.frame.size.height) animated:NO];
} else {
[self.collectionView setContentOffset:CGPointZero animated:NO];
	}
[_taboolaView releaseScroll];
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
	super .viewWillTransition(to: size, with: coordinator)
  taboolaFeed.releaseScroll()
 }

 func scrollCollectionToTop() {
 	guard let navigationController = navigationController else {
  return
 }

collectionView.setContentOffset(CGPoint(x: 0, y: -navigationController.navigationBar.frame.size.height), animated: true)
	taboolaFeed.releaseScroll()
}

Step 8: Show the progress bar

A loading progress bar will show up when switching the scroll to the Taboola Feed. The progress bar will preserve a good UX for your users and smooth the experience when moving the scroll from your app into Taboola Feed.

You can control the UI indicator visibility and color by using the following functions:

  • setProgressBarColor:@"#4286f4" - sets the color of the UI indicator, by default the value is dark blue
  • `setProgressBarDuration(3) - sets the progress bar duration in seconds, the default value is 0.7 seconds
  • setProgressBarEnabled:Yes - Activate/deactivate the progress bar when the automatic scroll switch is enabled. The default value is Yes
[taboolaView setInterceptScroll:YES];
[self.taboolaView setProgressBarEnabled:Yes];
[self.taboolaView setProgressBarColor:@"#4286f4"];
[self.taboolaView setProgressBarDuration: 3];
taboolaView.setInterceptScroll(true)
taboolaView.setProgressBarEnabled(true)
taboolaView.setProgressBarColor("#4286f4")
taboolaView.setProgressBarDuration(3)
  • startProgressBarAnimation - shows the progress bar on the bottom of the screen, when you manually controlling the scroll switch

Step 9: Additional Integration Information (Optional)

This section describes some optional points in the integration.

Delegates

To receive client-side callbacks, the client can set a delegate for each widget. The following events are available:

  • didLoadPlacementNamed - Triggered after the TaboolaView is successfully rendered; returns the placement name and the updated height value
  • didFailToLoadPlacementNamed - Triggered after the TaboolaView fails to render; returns the placement name and the error string value. Since iOS SDK 2.5.0, it is possible to get the detailed error strings by activating the detailedErrorCodes feature flag; NO_ITEMS (no fill by Taboola), WRONG_PARAMS (wrong "tb_mode" was used), RESPONSE_ERROR, TIMEOUT (connectivity issue), UNKNOWN_ERROR, and INTERNAL_1

Example:

taboolaView.delegate = self;
[taboolaView setExtraProperties:@{@"detailedErrorCodes":@"true"}];

- (void)taboolaView:(UIView *)taboolaView didLoadPlacementNamed:(NSString *)placementName withHeight:(CGFloat)height;

- (void)taboolaView:(UIView *)taboolaView didFailToLoadPlacementNamed:(NSString *)placementName withErrorMessage:(NSString *)error;
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        taboolaView.delegate = self
        taboolaView.setExtraProperties(["detailedErrorCodes": true])
    }
}

extension ViewController: TaboolaViewDelegate {    
    func taboolaView(_ taboolaView: UIView!, didLoadPlacementNamed placementName: String!, withHeight height: CGFloat) {
        print("Placement \(String(describing: placementName)) loaded successfully. height \(height)");
    }
    
    func taboolaView(_ taboolaView: UIView!, didFailToLoadPlacementNamed placementName: String!, withErrorMessage error: String!) {
        print("Placement \(String(describing: placementName)) failed to load because: %@ \(String(describing: error))");
    }
    
}

🚧

Important!

It is important to implement the didFailToLoadPlacementNamed delegate for the unlikely event of an error or no fill.

Intercepting Organic Recommendation Items Clicks

The SDK enables app developers to change the default behavior when a user clicks on an organic item. For example, you might want to create a click-through or override the default way of opening the organic recommended article.

- (BOOL)onItemClick:(NSString *)placementName withItemId:(NSString *)itemId withClickUrl:(NSString *)clickUrl isOrganic:(BOOL)organic {
	NSLog(@"Start load request on first screen: %@ isOrganic? %@", clickUrl, organic ? @"YES":@"NO");
    if (organic) {
        NSLog(@"organic items should open as native app pages.");
    }
    return YES;
}

The above method is called every time a user clicks a recommendation, immediately before triggering the default behavior. If recommendation clicks are not intercepted, they are presented by a Taboola powered in-app browser. It is also important to note that TaboolaView also fires notifications that can be caught by any object inside the app. This is in case you want to react to these notifications elsewhere in your code.

The app can intercept the click there, and returns a boolean value:

  • Returns NO - abort the default behavior (in which case the app displays the recommendation content on its own - e.g. using a custom in-app browser)

  • Returns YES - this enables the app to implement a click-through and continue with the default click handling behavior (which displays the clicked content with an in-app browser)

  • "organic" indicates whether the item clicked was an organic content recommendation or not. Best practice is to suppress the default behavior for organic items. Instead, open the relevant screen in your app which shows that piece of content.

  • Use "itemId" in organic clicks for deeplink

  • "clickUrl" is the URL with the redirect

Replacing the Default In-app Browser Icons

The file TaboolaViewResources.bundle includes the default icons for the TaboolaView in-app browser. You can replace these icons by providing an alternative TaboolaViewResources.bundle file which contains the following files:

  • back_icon.png
  • forward_icon.png

🚧

Important!

In some cases the delegates parameters can be with null value. Please make sure to handle such a case in your code.

Using more than one Taboola asset on the same screen

It is possible to add more than one Taboola asset on the same screen. For example, placing two Taboola widgets on a feed style screen. When doing so it is important to avoid duplicate items on each asset

  1. Set the same viewId value for each taboolaWidget object before fetching content. The viewId value must be a string of digits. We recommend using the current epoch timestamp. In any case, the viewId value can not exceed 19 digits.
  2. Fetch the content for the second asset only after a response is received for the first asset. Please use the didLoadPlacementNamed to listen to render is done events

To do so, please make sure you do the following:

//sets the viewId to be a string of digits (current epoch timestamp)
int timestamp = [[NSDate date] timeIntervalSince1970];
String *viewId = [NSString stringWithFormat:@"%d",timestamp];
BOOL didLoadFeed = NO;
  
//fetching content for the first Taboola item -
//for example, mid article widget
_taboolaMidArticleWidget.viewID = viewId;
[_taboolaMidArticleWidget fetchContent];

(void) taboolaView:(UIView *)
     taboolaView didLoadPlacementNamed:(NSString *)
     placementName withHeight:(CGFloat) height
{
  if (!_didLoadFeed)
    {
      _didLoadFeed = YES;	
    // We are loading the feed only when the widget finished loading- for dedup. 
      _taboolaFeed.viewID = viewId;
      [_taboolaFeed fetchContent];
    }

}
//sets the viewId to be a string of digits (current epoch timestamp)
lazy var viewId: String = {
        let timestamp = Int(Date().timeIntervalSince1970)
        return "\(timestamp)"
    }()

var didLoadFeed = false 

//fetching content for the first Taboola item -
//for example, mid article widget
taboolaMidArticleWidget.viewID = viewId
taboolaMidArticleWidget.fetchContent()

func taboolaView(_ taboolaView: UIView!, didLoadPlacementNamed placementName: String!, withHeight height: CGFloat) {
if !didLoadFeed
{ didLoadFeed = true // We are loading the feed only when the widget finished loading- for dedup. 
 taboolaFeed.viewID = viewId
 taboolaFeed.fetchContent()
}
}

Step 10: Resetting Taboola When Closing the Screen

Do not forget to reset Taboola when leaving the current screen.

- (void)dealloc
	{
		[taboolaView reset];
	}
deinit {
        taboolaView.reset()
    }

Step 11: Testing and Examples

You can find code examples on our Github repository.

You can use the following parameters for testing and development. Sponsored items are flagged with an "SC: " prefix in the title; organic items are flagged with an "OC: " prefix in the title

ParametersBelow Article Feed
publisher"sdk-tester-demo"
placement"Feed without video"
PageUrl"https://blog.taboola.com"
PageType"article"
TargetType"mix"
mode"thumbs-feed-01"

Step 10: Submit Build for QA

When you have finished the integration, contact your account manager and send a debuggable (TestFlight or other beta platform) version of your iOS project.

You're done!

Integration Support

Should you have any problems integrating the product, log a ticket with us by emailing your account manager. For a quick support you can also check our discussion forum