Introduction
Download SDK and Sample App
Integrating with the SDK
Setup Smartfeed
RecycleView Integration
Step 1: Create OBSmartFeed
Step 2: Connect Your Adapter to OBSmartFeed
OBSmartFeed Listener
OBSmartFeed Advanced Listener
OBSmartFeed Optional Properties
OBSmartFeed RTB Support
OBSmartFeed Video Item
(Optional) Smartfeed In Middle of RecycleView
(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

SDK 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.

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


Important: The `OBSmartFeed` should be an “instance variable” in the Activity since the instance has to be alive while the Activity is alive (in other words, if `OBSmartFeed` will be a local variable it will be collected by the Garbage Collector while the screen is still active).


RecycleView Integration


Step 1: Create OBSmartFeed

We recommend to setup OBSmartFeed in the Activity onCreate method, for example:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    this.obSmartFeed = new OBSmartFeed(getString(R.string.outbrain_sample_url), OUTBRAIN_WIDGET_ID, 
    recyclerView, this);
    mAdapter.setOBSmartFeed(obSmartFeed); // connects RecycleView adapter to the OBSmartFeed instance
    this.obSmartFeed.start();  // start OBSmartFeed
    ...
    ...
    // Your code is here
}


We initilize OBSmartFeed 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) RecycleView – the recycle view instance.

4) OBSmartFeedListener (usually the current Activity).


Please note: as the sample code above shows, it is recommended to implement `OBSmartFeedListener` methods in the Activity in order to receive the events of: clicks on recommendations in the feed and clicks on “Ad Choices” icon in case of recommendation of type OPA. It is also possible to skip the `OBSmartFeedListener` implementation and let the SDK default listener do the work for you. Read more about OBSmartFeed Listener


Connecting Adapter to OBSmartFeed

Please notice the line of code where we call:

mAdapter.setOBSmartFeed(obSmartFeed);

This is mandatory for the Adapter to have a reference to the OBSmartFeed instance since we have to call it at key Adapter methods (we’ll explain more below).


Start OBSmartFeed

Please notice the line of code where we call:

this.obSmartFeed.start();

This is mandatory for the SmartFeed to work as expected.


(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:

this.obSmartFeed.setWidgetIndex(2);


Step 2: Connect Your Adapter to OBSmartFeed

OBSmartFeed should be called from key methods in the RecycleView.Adapter.

The methods you should call OBSmartFeed are:

1) public int getItemCount()

2) public int getItemViewType(int position)

3) public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)

4) public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)



getItemCount

Smartfeed recommendations will be added to the collection view at the bottom. Therefore we need to implement the method as follows

public int getItemCount() {
    return ORIGINAL_RECYCLE_VIEW_SIZE + this.obSmartFeed.getSmartFeedItemCount();
}


getItemViewType

public int getItemViewType(int position) {
    switch (position) {
        case 0:
            return ARTICLE_HEADER_VIEW_TYPE;
        case 1:
            return TEXT_VIEW_TYPE;
        case 2:
            return TEXT_VIEW_TYPE;
        case 3:
            return TEXT_VIEW_TYPE;
        default:
            return this.obSmartFeed.getItemViewType(position, ORIGINAL_RECYCLE_VIEW_SIZE);
    }
}


onCreateViewHolder

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View v;
    switch (viewType) {
        case TEXT_VIEW_TYPE:
            v = inflater.inflate(R.layout.article_text_row, parent, false);
            TextItemViewHolder tvh = new TextItemViewHolder(v);
            return tvh;
        case ARTICLE_HEADER_VIEW_TYPE:
            v = inflater.inflate(R.layout.article_header_row, parent, false);
            ImageItemViewHolder ivh = new ImageItemViewHolder(v);
            return ivh;
        default:
            return this.obSmartFeed.onCreateViewHolder(parent, viewType);
    }
}


onBindViewHolder

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    TextItemViewHolder tvh;

    switch (position) {
        case 0:
            break;
        case 1:
            tvh = (TextItemViewHolder)holder;
            tvh.textView.setText(tvh.textView.getContext().getResources().getString(R.string.article_txt_1));
            break;
        case 2:
            tvh = (TextItemViewHolder)holder;
            tvh.textView.setText(tvh.textView.getContext().getResources().getString(R.string.article_txt_2));
            break;
        case 3:
            // ...
            break;
        default:
            this.obSmartFeed.onBindViewHolder(holder, position, ORIGINAL_RECYCLE_VIEW_SIZE);
    }


(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: Android SDK – Smartfeed Custom UI


OBSmartFeed Listener



App developer can now use OBSmartFeedDefaultListener as a default listener instead of implementing one. In this case the app developer should init OBSmartFeed with following constructor method:


this.obSmartFeed = new OBSmartFeed(getString(R.string.outbrain_sample_url), widgetID, recyclerView);



It is recommended for the app developer to set the OBSmartFeedListener in order to catch click events in the Smartfeed.


public interface OBSmartFeedListener {
    void userTappedOnRecommendation(OBRecommendation rec);

    void userTappedOnAdChoicesIcon(String url);

    void userTappedOnAboutOutbrain();

    void userTappedOnVideo(String url);

    void onOutbrainRecsReceived(ArrayList<OBRecommendation> recommendations, String widgetId);
}



An example for OBSmartFeedListener implementation might be:


@Override
public void userTappedOnRecommendation(OBRecommendation rec) {
    Log.i(LOG_TAG, "userTappedOnRecommendation: " + rec.getContent());
    String url = Outbrain.getUrl(rec);
    CatalogUtils.openURLInBrowser(url, this);
}

@Override
public void userTappedOnAdChoicesIcon(String url) {
    Log.i(LOG_TAG, "userTappedOnAdChoicesIcon: " + url);
    CatalogUtils.openURLInBrowser(url, this);
}

@Override
public void userTappedOnAboutOutbrain() {   
   String aboutOutbrainUrl = Outbrain.getOutbrainAboutURL(this);
   CatalogUtils.openURLInBrowser(aboutOutbrainUrl, this);
}

@Override
public void userTappedOnVideo(String url) {
    Log.i(LOG_TAG, "userTappedOnVideo: " + url);
    CatalogUtils.openURLInBrowser(url, this);
}

@Override
    public void onOutbrainRecsReceived(ArrayList<OBRecommendation> recommendations, String widgetId) {
    Log.i(LOG_TAG, "recommendations received for widgetID: " + widgetId);
}


(Optional) OBSmartFeed Advanced Listener

SmartFeed supports additional listener in order to enable wider access to events that occur in the SmartFeed.

In your activity, set OBSmartFeedAdvancedListener (usually the current Activity):

this.obSmartFeed.setAdvancedListener(this);


public interface OBSmartFeedAdvancedListener {

    /**
     * This method help the app developer to be notified on when new recommendations are being returned by Outbrain server
     * @param recommendations array of recommendations currently returned from Outbrain server.
     * @param widgetId The widget id of the corresponding request (may be one of the sub-widgets for example.
     */
    void onOutbrainRecsReceived(ArrayList<OBRecommendation> recommendations, String widgetId);

    /**
     * If the Smartfeed attemps to play a video within the feed, it may check with the app if there is a video currently playing in the app.
     * The goal is to avoid a collision of 2 videos playing at the same time.
     * @return true if video is currently playing in the app
     */
    boolean isVideoCurrentlyPlaying();

    /**
     * This method is relevant only in case Smartfeed is displayed in the middle of the feed (not at the end)
     * The OBSmartFeed will notify the app developer when the Smartfeed is ready with recs to be displayed so the
     * RecycleView adapter can integrate Outbrain recs within the feed.
     *
     */
    void smartfeedIsReadyWithRecs();
}


OBSmartFeed Optional Properties

this.obSmartFeed.setExternalID(String externalID)
Setting this property will add extid param to all ODB requests with the value of externalID param



this.obSmartFeed.displaySourceOnOrganicRec = true;
By default the Smartfeed will not show the “source” for organic recs, only the rec title will be displayed (i.e. “CNN News” for example will not be shown in CNN app). In order to change this default, use this method.



this.obSmartFeed.setDarkMode(true)
Setting this property to “true” will change the Smartfeed colors scheme to “dark mode”



this.obSmartFeed.setTheme(new PublisherTheme());
Setting this property change the default “Light\Dark” theme colors of the SDK to the publisher custom colors. See:

class PublisherTheme implements SFTheme {
    @Override
    public int primaryColor() {
        return Color.rgb(0, 0, 204);
    }

    @Override
    public int sfHeaderColor() {
        return Color.WHITE;
    }

    @Override
    public int cardShadowColor() {
        return Color.GRAY;
    }

    @Override
    public int recTitleTextColor(boolean isPaid) {
        return isPaid ? Color.WHITE : Color.rgb(128, 128, 128);
    }

    @Override
    public int pageIndicatorSelectedColor() {
        return Color.WHITE;
    }

    @Override
    public int getReadMoreModuleGradientResourceId() {
        return com.outbrain.OBSDK.R.drawable.read_more_gradient_dark;
    }
}


Smartfeed RTB Support

OBSmartFeed 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 via OBSmartFeedListener. On click you should open the provided URL in a browser. See example code below:


@Override
public void userTappedOnAdChoicesIcon(String url) {
    Log.i(LOG_TAG, "userTappedOnAdChoicesIcon: " + url);
    CatalogUtils.openURLInBrowser(url, this);
}




OBSmartfeed 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:





(Optional) Smartfeed In Middle of RecycleView


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

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.


Please note: it is highly recommended to take example from “Catalog” sample app, make sure to set `SmartFeedMidFeedActivity` with the MAIN and LAUNCHER intent filters in the AndroidManifest.xml file. Take example from SmartFeedMidFeedActivity and ArticleMidFeedListAdapter.


In Corresponding Activity

App developer should implement the AdvancedListener interface and isInMiddleOfRecycleView flag set to “true”.

Additionally app developer need to set RECYCLE_VIEW_SIZE_BEFORE_SMARTFEED and pass it on to the SDK so OBSmartFeed can “know” where exactly to place the new Smartfeed items.


this.obSmartFeed = new OBSmartFeed(<ArticleURL>, widgetID, recyclerView, this);
this.obSmartFeed.setAdvancedListener(this);
this.obSmartFeed.isInMiddleOfRecycleView = true;
mAdapter.setOBSmartFeed(obSmartFeed);
this.obSmartFeed.start();


In Corresponding Adapter


@Override
public int getItemViewType(int position) {
    if (this.obSmartFeed.isPositionBelongToSmartfeed(position, RECYCLE_VIEW_SIZE_BEFORE_SMARTFEED)) {
        return this.obSmartFeed.getItemViewType(position, RECYCLE_VIEW_SIZE_BEFORE_SMARTFEED);
    }

    final int afterSmartfeedOffset = RECYCLE_VIEW_SIZE_BEFORE_SMARTFEED + this.obSmartFeed.getSmartFeedItemCount();

    // Items after the Smartfeed can be calculated via `afterSmartfeedOffset`

    .....
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());

    if (this.obSmartFeed.isViewTypeBelongToSmartfeed(viewType)) {
        return this.obSmartFeed.onCreateViewHolder(parent, viewType);
    }

    // Continue with app implementation
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    TextItemViewHolder tvh;

    if (this.obSmartFeed.isPositionBelongToSmartfeed(position, RECYCLE_VIEW_SIZE_BEFORE_SMARTFEED)) {
        this.obSmartFeed.onBindViewHolder(holder, position, RECYCLE_VIEW_SIZE_BEFORE_SMARTFEED);
        return;
    }

    // Continue with app implementation
}


In OBSmartFeedAdvancedListener

@Override
public void smartfeedIsReadyWithRecs() {
    this.mAdapter.notifyDataSetChanged();
}


(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.