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 managermode
- Your mode parameter as provided by your Taboola account managerplacement
- Your placement parameter as provided by your Taboola account managerpageUrl
- The full URL of public web page which reflects the current screen's contentpageId
- An internal identification for the current screen's content. Pass this along the page URL to set the item ID as your internal IDpageType
- Your page type parameter as provided by your Taboola account managertargetType
- 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 isYes
[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 valuedidFailToLoadPlacementNamed
- 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 thedetailedErrorCodes
feature flag;NO_ITEMS
(no fill by Taboola),WRONG_PARAMS
(wrong "tb_mode" was used),RESPONSE_ERROR
,TIMEOUT
(connectivity issue),UNKNOWN_ERROR
, andINTERNAL_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
- Set the same
viewId
value for each taboolaWidget object before fetching content. TheviewId
value must be a string of digits. We recommend using the current epoch timestamp. In any case, theviewId
value can not exceed 19 digits. - 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
Parameters | Below 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
Updated 23 days ago