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
Step 3 (Optional): Implement Custom UI
Smartfeed Delegate
Smartfeed Viewability
Smartfeed RTB Support
Outbrain Logo


Introduction

Important: Outbrain SDK version 3.0.0 which introduce Smartfeed for the first time, is currently in closed beta.

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

Sample App

Please download Smartfeed sample app with this download link.

SDK 3.0.0

Please download Outbrain SDK 3.0.0.rc1 with this download link.


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.


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() {
    guard let publisherLogoImage = UIImage(named: "cnn-logo") else {
        return
    }
    let baseURL = currentArticleDemoUrl
    self.smartFeedManager = SmartFeedManager(url: baseURL, widgetID: smartFeedWidgetID, tableView: self.tableView, publisherName: "CNN", publisherImage: publisherLogoImage)
    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.

4) publisherName – the name of the publisher to be displayed in the “More from ..” Box (see in screenshot below).

5) publisherImage – The UIImage of the publisher logo to be displayed in the “More from ..” Box (see in screenshot below).


Please note: as the sample code above show, we have 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. Read more about Smartfeed Delegate.



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


An example of where we use publisherName and publisherImage




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 {
    return (self.smartFeedManager.smartFeedItemsArray.count > 0) ? 2 : 1
}


numberOfRowsInSection

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 0 {
        return originalArticleItemsCount
    }
    else {
        return self.smartFeedManager.smartFeedItemsArray.count
    }
}


cellForRowAt

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

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

    // Your app original implementation
}


willDisplay

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 == 1 { // Outbrain
        return self.smartFeedManager.tableView(tableView, heightForRowAt: indexPath)
    }

    return UITableViewAutomaticDimension;
}


Step 3 (Optional): Implement Custom UI

By default, Smartfeed just works, “out of the box”, by implementing steps 1-2 smartfeed will be available on the view controller you set it on. Nevertheless, if you’d like to customize the appearance of the Smartfeed cells, you can definitely do it.


The following cells can be customize by implementing their xib and registering it (code example will follow):

1) AppSFHorizontalItemCell.xib – to implement the UI for each cell item in the horizontal carousel.

2) AppSFCollectionViewCell.xib – to implement the UI for “Single” Smartfeed collection view cell.




Customize Carousel Item Cell


Important: It will be very helpful to take an example from the Smartfeed sample app.

1) Create a xib file by the name AppSFHorizontalItemCell.xib.

2) xib should contain UICollectionViewCell at the parent of all views.

3) In the xib set the class for UICollectionViewCell to be SFCollectionViewCell or descendent of SFCollectionViewCell.

4) SFCollectionViewCell has Outlets 5 outlets, you must connect the following 2: recImageView, recTitleLabel

5) Set the cell reusable identifier as “AppSFHorizontalItemCell”.

6) Important In setupCustomUIForSmartFeed() (in the sample code above) run the following code:

let bundle = Bundle.main
let horizontalCellNib = UINib(nibName: "AppSFHorizontalItemCell", bundle: bundle)
self.smartFeedManager.registerHorizontalItemNib(horizontalCellNib, forCellWithReuseIdentifier: "AppSFHorizontalItemCell")


Customize Single Cell

1) Create a xib file by the name AppSFTableViewCell.xib.

2) xib should contain UITableViewCell at the parent of all views.

3) In the xib set the class for UITableViewCell to be AppSFTableViewCell or descendent of AppSFTableViewCell.

4) AppSFTableViewCell has Outlets 5 outlets, you must connect all of them.

5) Set the cell reusable identifier as “AppSFTableViewCell”.

6) Important In setupCustomUIForSmartFeed() (in the sample code above) run the following code:

let bundle = Bundle.main
let singleCellNib = UINib(nibName: "AppSFTableViewCell", bundle: bundle)
self.smartFeedManager.registerSingleItemNib(singleCellNib, forCellWithReuseIdentifier: "AppSFTableViewCell")


Smartfeed Delegate

Please note as the sample code above show, we have to set the SmartFeedManager delegate property in order to handle clicks on recommendations in the feed,

@protocol SmartFeedDelegate

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

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

@end



An example for delegate implementation might be:

extension ArticleCollectionViewController : SmartFeedDelegate {
    func userTapped(on rec: OBRecommendation) {
        print("You tapped rec \(rec.content).")
        guard let url = Outbrain.getUrl(rec) else {
            print("Error: no url for rec.")
            return
        }
        let safariVC = SFSafariViewController(url: url)
        self.navigationController?.present(safariVC, animated: true, completion: nil)
    }

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


Smartfeed Widget Viewability

According to our instructions regarding widget viewability – app developers should implement the text at the widget header with OBLabel and call:

Outbrain.register(obLabel, withWidgetId: smartFeedWidgetID, andUrl: currentArticleDemoUrl)


See example for using OBLabel to display “Sponsored” in the sample app:




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)
}




According to our instructions regarding Outbrain widget labeling – app developers should implement a click handler on Outbrain logo in the following way:

guard let url = Outbrain.getAboutURL() else {
  return
}
let safariVC = SFSafariViewController(url: url)
viewController.present(safariVC, animated: true, completion: nil)