Introduction Download SDK and Sample App Integrating with the SDK Setup Smartfeed UIStackView Integration – Step 1: Storyboard – Step 2: Set Up Constraints – Step 3: In Code – ViewDidLoad – Step 4: In Code – Setup SmartFeedManager – Step 5: In Code – Update UITableView Constraint – Step 6: In Code – Update UICollectionView Constraint – Step 7: In Code – Fetch More Recommendations Smartfeed Delegate Smartfeed RTB Support Smartfeed Video Item
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.
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, in this guide we’ll want to use UICollectionView
.
UIStackView Integration
Step 1: Storyboard
In order to get this solution to work, the view hierarchy structure is super important. Please notice the recommended way to structure the View Controller hierarchy:
- UIScrollView
- UIStackView
- UITableView (contains the article content)
- UICollectionView (contains the Smartfeed content)
Step 2: Set Up Constraints
1) “Equals” constraint: UIStackView.width == UIScrollView.width 2) “Equals” constraint: UICollectionView.width == UIView.width (top-level view). 3) “Height” constraint: UITableView – give it some initial height (650 for example) and create an Outlet to be used in code later on. 4) “Height” constraint: UICollectionView – give it some initial height (650 for example) and create an Outlet to be used in code later on.
Step 3: In Code – ViewDidLoad
First we want to disable the scrolling on both UITableView and UICollectionView. We do that because in runtime we will update the “height” constraints we set in “step 2” according to the “content size” (example will follow).
We also want to set ourselves as the scrollview delegate.
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
tableView.isScrollEnabled = false
sfCollectionView.isScrollEnabled = false
setupSmartFeed()
...
...
// Your code is here
}
Step 4: In Code – Setup SmartFeedManager
func setupSmartFeed() {
self.smartFeedManager = SmartFeedManager(url: OBConf.baseURL, widgetID: OBConf.widgetID, collectionView: self.sfCollectionView)
self.smartFeedManager.delegate = self
self.smartFeedManager.isInMiddleOfScreen = true
self.smartFeedManager.outbrainSectionIndex = 0
self.smartFeedManager.useDefaultCollectionViewDelegate = true
self.smartFeedManager.fetchMoreRecommendations() // start fetching manually because Smartfeed is in the middle
}
We initilize SmartFeedManager with:
1) baseURL – the current article URL
2) widgetID – an additional Outbrain widget ID — different from the primary widgetID (has to be configured to be of type “smartfeed”, please consult with you account manager for more details).
3) collectionView – the collection view instance.
More Notes:
1) We set outbrainSectionIndex since the CollectionView will contain only the Smartfeed.
2) useDefaultCollectionViewDelegate
will set the SDK as the delegate of the CollectionView.
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 5: In Code – Update UITableView Constraint
We’ll need to update the height constraints of the UITableView by using the code below in willDisplay:cell:
if (indexPath.row == originalArticleItemsCount-1) {
let height = self.tableView.contentSize.height
print("set tableView height to: \(height)")
self.tableViewHeight.constant = height
self.view.setNeedsLayout()
}
Step 6: In Code – Update UICollectionView Constraint
We’ll need to update the height constraints of the UICollectionView by using the code below in smartfeedIsReadyWithRecs
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.sfCollectionView.reloadData()
}
let height = self.sfCollectionView.collectionViewLayout.collectionViewContentSize.height
print("set collectionview height to: \(height)")
self.sfCollectionViewHeight.constant = height
self.view.setNeedsLayout()
}
Step 7: In Code – Fetch More Recommendations
It is the app developer responsibility to fetch more recommendations to the feed as the user scrolls down. Remember, the first load is happening in setupSmartFeed()
.
Here is a suggestion of how app developer may implement the “fetch more” functionality in code:
extension ArticleStackViewController : UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y + 400 >= (scrollView.contentSize.height - scrollView.frame.size.height)) {
if (self.smartFeedManager.hasMore) {
if self.lastFetchMoreRecommendationFireTime + 0.4 < NSDate().timeIntervalSince1970 {
self.lastFetchMoreRecommendationFireTime = NSDate().timeIntervalSince1970
self.smartFeedManager.fetchMoreRecommendations()
}
}
}
}
}
(Optional): Implement Custom UI
For more information please refer to: iOS SDK – Smartfeed UICollectionView Custom UI
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
.
@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:
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)
}
func userTapped(onVideoRec url: URL) {
print("You tapped on video rec")
let safariVC = SFSafariViewController(url: url)
self.navigationController?.present(safariVC, animated: true, completion: nil)
}
func userTappedOnOutbrainLabeling() {
print("You tapped on Outbrain Labeling")
let url = Outbrain.getAboutURL()
let safariVC = SFSafariViewController(url: url)
self.navigationController?.present(safariVC, animated: true, completion: nil)
}
}
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)
}
Smartfeed Video Item
OBSmartFeed
supports recommendations of type “in-widget” Video. Which is a video on top of existing “display recommendations” (see example below). OBSmartfeed will try to load a video rec if configured in the widget settings. If video will be available, it will be played on top of the widget it was configured on. When the video is finished or closed, the “display recommendations” will be show again.
See demo video below: