Introduction
Download SDK and Sample App
Integrating with the SDK
Setup Smartfeed
UITableView Integration
Step 1: Create SmartFeedManager
Step 2: Connect Your Data Source to SmartFeedManager
Smartfeed Optional Properties
Smartfeed Delegate
Smartfeed RTB Support
(Optional) Smartfeed In Middle of UITableView
(Optional) Read More Button


Introduction

Outbrain Smartfeed is a brand new way for publishers to integrate Outbrain recommendations in their native app in a way that feels natural to their users (infinite scrolling at the end of the original article) and seamless for app developers to integrate.

See example of how Smartfeed works below:



Download SDK and Sample App

Download links are available at Outbrain SDK – Documentation & Download Links


Integrating with the SDK

Smartfeed is an integral part of the SDK, therefore you must integrate and init the SDK according to the instructions in our main developers guide page.


Important: Please make sure to cover iOS 14 Changes, specifically the “SKAdNetwork support” and “App Install” part.


Setup Smartfeed

Finally we get to the interesting part of this guide, here are the actual steps necessary for app developers to make use of Smartfeed in their application.

SmartFeedManager is the Class responsible for managing the Smartfeed. You should create an instance of SmartFeedManager in the relevant UIViewController where the original article is displayed.

The SmartFeedManager constructor can work with both: UICollectionView and UITableView. The integration is pretty similar, please refer to the one relevant to you.


Important: The `SmartFeedManager` should be a “property” in the UIViewController since the instance has to be alive while the UIViewController is alive (in other words, if `SmartFeedManager` will be a local variable it will be deallocated while the screen is still active).


UITableView Integration


Step 1: Create SmartFeedManager

We recommend to setup SmartFeedManager in viewDidLoad method, for example:

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.delegate = self
    tableView.dataSource = self
    let spinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
    spinner.startAnimating()
    spinner.frame = CGRect(x: 0, y: 0, width: self.tableView.frame.width, height: 44)
    self.tableView.tableFooterView = spinner;
    self.setupSmartFeed()
}

func setupSmartFeed() {
    let baseURL = currentArticleDemoUrl
    self.smartFeedManager = SmartFeedManager(url: baseURL, widgetID: smartFeedWidgetID, tableView: self.tableView)
    self.smartFeedManager.delegate = self

    // Optional
    self.setupCustomUIForSmartFeed()
}


We initilize SmartFeedManager with:

1) baseURL – the current article URL

2) widgetID – an additional Outbrain widget ID – different from the primary widgetID id (has to be configured to be of type “smartfeed”, please consult with you account manager for more details).

3) tableView – the table view instance.


Please note: as the sample code above shows, it is recommended to set the SmartFeedManager `delegate` property in order to handle clicks on recommendations in the feed (and clicks on “Ad Choices” icon in case of recommendation of type OPA. It is also possible to not set the `delegate` property and let the SDK default delegate do the work for you. Read more about Smartfeed Delegate.



We will explain about setupCustomUIForSmartFeed() later on in this guide.


(Optional) set the widget index

By default the “widget index” for the Smartfeed is 0, however in case there are additional Outbrain widgets on the screen besides the Smartfeed, it’s possible to set the “widget index” via:

self.smartFeedManager.outbrainWidgetIndex = 2


Step 2: Connect Your Data Source to SmartFeedManager

SmartFeedManager should be called from key methods in the table view data source.

The methods you should call SmartFeedManager are:

1)
func numberOfSections(in tableView: UITableView) -> Int

2)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

3)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

4)
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)

5)
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat



numberOfSections

Smartfeed recommendations will be added into a separate section in the collection view to not interfere with the original data source implementation.

func numberOfSections(in tableView: UITableView) -> Int {
    self.smartFeedManager.outbrainSectionIndex = 1 // update smartFeedManager with outbrain section index, must be the last one.
    return self.smartFeedManager.numberOfSectionsInTableView()
}


numberOfRowsInSection

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section < self.smartFeedManager.outbrainSectionIndex {
        return originalArticleItemsCount
    }
    else {
        return self.smartFeedManager.smartFeedItemsCount()
    }
}


cellForRowAt

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    if indexPath.section == self.smartFeedManager.outbrainSectionIndex { // Outbrain
        return self.smartFeedManager.tableView(tableView, cellForRowAt: indexPath)
    }    
        // Your app original implementation
    }


willDisplay


Important: SmartFeedManager method `willDisplay` must be called for every IndexPath in the feed, not only the ones in outbrainSectionIndex. This helps `SmartFeedManager` to know which cells are currently viewed by the user and when to load more items into the Smartfeed.


func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    self.smartFeedManager.tableView(tableView, willDisplay: cell, forRowAt: indexPath)

    // App Developer should configure the app cells here..
}


heightForRowAt

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath.section == self.smartFeedManager.outbrainSectionIndex { // Outbrain
        return self.smartFeedManager.tableView(tableView, heightForRowAt: indexPath)
    }

    return UITableViewAutomaticDimension;
}


(Optional): Implement Custom UI

Please note: By default, Smartfeed just works, “out of the box”, by implementing steps 1-2 Smartfeed will be available in the Activity you set it on. Nevertheless, if you’d like to customize the appearance of the “Smartfeed View” in the RecycleView, you can definitely do it.

For more information please refer to: iOS SDK – Smartfeed UITableView Custom UI


Smartfeed Optional Properties


smartFeedManager.disableCellShadows

Setting this property to “true” will disable shadows on each Smartfeed cell.


smartFeedManager.displaySourceOnOrganicRec

Setting this property to “true” will display the “source name” label on organic recs as well.


smartFeedManager.horizontalContainerMargin

Setting this property to value of 20.0 for example, will add margin on the “left” and “right” sides of the horizontal cell.


smartFeedManager.darkMode

Setting this property to “true” will change the Smartfeed colors scheme to “dark mode”


smartFeedManager.outbrainWidgetIndex

Set this value if there are more Outbrain widgets on the screen where the Smartfeed is displayed.


smartFeedManager.externalID

Setting this property will add extid param to all ODB requests with the value of externalID param.


Smartfeed Delegate

Since SDK v3.7.0, app developers can now skip on the SmartFeedDelegate implementation, in which case the SDK will handle all Smartfeed clicks by default implementation, i.e. open all links in SFSafariViewController.


Please note: It is recommended for the app developer to implement the `SmartFeedDelegate` protocol and set the `SmartFeedManager` `delegate` property in order to handle clicks on recommendations, Outbrain label and RTB icon in the feed.


@protocol SmartFeedDelegate

-(void) userTappedOnRecommendation:(OBRecommendation *_Nonnull)rec;

-(void) userTappedOnAdChoicesIcon:(NSURL *_Nonnull)url;

-(void) userTappedOnVideoRec:(NSURL *_Nonnull)url;

-(void) userTappedOnOutbrainLabeling;

@end


An example for delegate implementation might be:


-(void) userTappedOnRecommendation:(OBRecommendation *_Nonnull)rec {
    if (rec.appInstall) {
        [Outbrain openAppInstallRec:rec inNavController:self.navigationController];
        return;
    }
    NSURL *url = [Outbrain getUrl:rec];
    [self presentSFSafariViewController:url];
}

-(void) userTappedOnAdChoicesIcon:(NSURL *_Nonnull)url {
    [self presentSFSafariViewController:url];
}

-(void) userTappedOnVideoRec:(NSURL *_Nonnull)url {
    [self presentSFSafariViewController:url];
}

-(void) userTappedOnOutbrainLabeling {
    NSURL *url = Outbrain.getOutbrainAboutURL;
    [self presentSFSafariViewController:url];
}

-(void) presentSFSafariViewController:(NSURL *_Nonnull)url {
    SFSafariViewController *safariVC = [[SFSafariViewController alloc]initWithURL:url entersReaderIfAvailable:NO];
    UINavigationController *navigationController = (UINavigationController *)[UIApplication sharedApplication].keyWindow.rootViewController;
    [navigationController presentViewController:safariVC animated:true completion:^{}];
}


Smartfeed RTB Support

SmartFeedManager supports RTB “out of the box”, i.e. the displaying of the “Ad Choices” icon is done for you. All you, as the app developer, should do, is make sure to implement the click handling for the ad choices icon. On click you should open the provided URL in a browser. See example code below:


func userTapped(onAdChoicesIcon url: URL) {
    print("You tapped onAdChoicesIcon")
    let safariVC = SFSafariViewController(url: url)
    self.navigationController?.present(safariVC, animated: true, completion: nil)
}




(Optional) Smartfeed In Middle of UITableView


Important: The support for Smartfeed in the middle of UITableView is available in SDK >= v3.7.5

Smartfeed can also be integrated in the middle of the screen so that additional non-Outbrain content can be placed below it. In order to achieve that, app developer should make the following changes.

App developer should make use of smartfeedIsReadyWithRecs() method of SmartFeedDelegate as shown below:


Please note: it is highly recommended to take example from “Smartfeed” sample app. In file `ViewController.swift`, in method `viewDidLoad` make sure to set `performSegue(withIdentifier: “showTableMidPageVC“, sender: nil)`. Take example from ArticleMidPageTableViewController.


In Corresponding ViewController


self.smartFeedManager = SmartFeedManager(url: Const.baseURL, widgetID: Const.widgetID, tableView: self.tableView)
self.smartFeedManager.delegate = self
self.smartFeedManager.isInMiddleOfScreen = true
self.smartFeedManager.outbrainSectionIndex = 1 // update smartFeedManager with outbrain section index
self.smartFeedManager.fetchMoreRecommendations() // start fetching manually because Smartfeed is in the middle


In Corresponding SmartFeedDelegate


func smartfeedIsReadyWithRecs() {
    if (!self.smartfeedIsReady) {
        // only for the first time run reloadData() after that the Smartfeed will take care of updating itself
        self.smartfeedIsReady = true
        self.collectionView.reloadData()
    }
}


In Corresponding Data Source


func numberOfSections(in tableView: UITableView) -> Int {
    if self.smartfeedIsReady {
        // numberOfSections including Smartfeed
        return 3
    }
    else {
        return 2
    }
}

// number of rows in table view
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if self.smartfeedIsReady && section == self.smartFeedManager.outbrainSectionIndex {
        return self.smartFeedManager.smartFeedItemsCount()
    }
    else {
        return articleSectionItemsCount
    }
}

// create a cell for each table view row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    // create a new cell if needed or reuse an old one
    var cell:UITableViewCell?

    if self.smartfeedIsReady && indexPath.section == self.smartFeedManager.outbrainSectionIndex 
    { // Outbrain
        return self.smartFeedManager.tableView(tableView, cellForRowAt: indexPath)
    }

    // Continue with app implementation 

}


func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if self.smartfeedIsReady && indexPath.section == self.smartFeedManager.outbrainSectionIndex { // Outbrain
        self.smartFeedManager.tableView(tableView, willDisplay: cell, forRowAt: indexPath)
        if (self.smartFeedManager.hasMore && indexPath.row + 3 >= self.smartFeedManager.smartFeedItemsCount()) {
            // manually fetch more recommendations when feed is near the end
            self.smartFeedManager.fetchMoreRecommendations()
        }

        return
    }

    // App Developer should configure the app cells here..

}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if self.smartfeedIsReady && indexPath.section == self.smartFeedManager.outbrainSectionIndex { // Outbrain
        return self.smartFeedManager.tableView(tableView, heightForRowAt: indexPath)
    }

    // Continue with app implementation 

}


(Optional) Read More Button

Read the instructions on this page to learn how to use the “Read More” functionality to increase RPM performance for your Smartfeed.