Unified Bidding | Android Integration

Unified Bidding Integration Guide for Publishers with Smaato or GAM as a Primary Ad Server

(Android NextGen SDK version 21.7.1)

Introduction

Smaato’s in-app header bidding solution, Unified Bidding, is a holistic bidding model that uses real-time pricing competition to provide publishers with maximum competition and control over their inventory.

Take advantage of the our in-app header bidding solution by integrating with the Smaato NextGen SDK today.




Your Advantage

We are observing more and more demand partners moving away from multiple integrations. Following the TradeDesk’s public announcement that they will only allow one integration per supply source, many other demand partners are now following suit.

Currently, we have seen up to 230% higher revenue when comparing Smaato Unified Bidding versus TAM integrations. We have also observed around a 300% increase in revenue via the direct connection due to the additional revenue accumulated.

GAM Setup Process

For each price point (of each line item you set up in SPX), you will need to create one line item in GAM.

You will also want to add a new Dynamic Key (with no value defined) called “smaub”, on Inventory >> Key-Values. For more information, see here

GAM Dashboard Setup

1. Go to the GAM Dashboard

2. Click on “Create Mediation Group” button

3. Select Ad format as per your needs. Possible options are Banner, Interstitial, Native, and Rewarded.

4. Set the desired parameters in the next tab.

5. On “Add Ad Unit” option under “Ad Unit“, select the ad unit that needs to be targeted with mediation.

6. Under “Ad sources“, click on “ADD CUSTOM EVENT

    • Provide Label and your desired eCPM
    • Under “Configure ad units“, provide the class name details:
      • For Banner Ads: SMAAdMobSmaatoBannerAdapter
      • For Interstitial Ads: SMAAdMobSmaatoInterstitialAdapter
      • For Rewarded Video Ads: SMAAdMobSmaatoRewardedVideoAdapter
      • For Native Ads: SMAAdMobSmaatoNativeAdapter
    • Pass parameter for the SPX Adspace ID:
      • adSpaceId=<YOUR_SPX_ADSPACE_ID>

6. Next, set the eCPM of the price that you want to target, for example, $0.10.

7. Don’t add day/time or day/part targeting.

8. Don’t add frequency capping.

In the Custom Targeting >> Key-Values targeting section you need to select “smaub” as your targeted key, and enter a value, for each line item that you have created. Please make sure that the value is “smaato_cpm:” and the price rate of the Line Item and repeat this process for each Line Item.

For example:

  • For $0.10 enter the value smaato_cpm:0.10
  • For $1.30 enter the value smaato_cpm:1.30
  • For $20.00 enter the value smaato_cpm:20.00

Integrate the NextGen SDK

Set up your account on SPX

https://spx.smaato.com/

Configure your Android project

Add the following repository setup to your project’s main build.gradle file:

allprojects {
    repositories {
        google()
        jcenter()
        maven {
            url "https://s3.amazonaws.com/smaato-sdk-releases/"
        }
    }
}

Set the compile options to Java 8, (i.e. place the following line into your application module build.gradle file):

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

Add dependencies to your application module build.gradle file.

For Banner ads, then make sure the following dependencies are in place:

implementation 'com.smaato.android.sdk:admob-banner-adapter:21.7.1'
implementation 'com.smaato.android.sdk:smaato-sdk-unified-bidding:21.7.1'

For Interstitial ads, then make sure the following dependencies are in place:

implementation 'com.smaato.android.sdk:admob-interstitial-adapter:21.7.1'
implementation 'com.smaato.android.sdk:smaato-sdk-unified-bidding:21.7.1'

For Rewarded ads, then make sure the following dependencies are in place:

implementation 'com.smaato.android.sdk:admob-rewarded-video-adapter:21.7.1'
implementation 'com.smaato.android.sdk:smaato-sdk-unified-bidding:21.7.1'

For Native ads, make sure the following dependencies are in place:

implementation 'com.smaato.android.sdk:admob-native-adapter:21.7.1'
implementation 'com.smaato.android.sdk:smaato-sdk-unified-bidding:21.7.1'

Add the following permissions to your application AndroidManifest.xml file:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

If your application targets Android 5.0 (API level 21) or higher, then you need to add the following line to your application AndroidManifest.xml file:

<uses-feature android:name="android.hardware.location.network" />

If your application targets Android 9 Pie (API level 28) or higher, in order to send HTTP requests (so that more Ads can be shown), then you need to configure the networkSecurityConfig attribute in the application tag in AndroidManifest.xml:

android:networkSecurityConfig="@xml/network_security_config"

Now create the network_security_config.xml in the XML resource directory with:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

For more details regarding the Network security configuration, please see the official Google documentation: https://developer.android.com/training/articles/security-config

Proguard Configuration

If you’re using Proguard in your project, please add the following lines to your Proguard config file, as per your requirements:

	-keep public class com.smaato.sdk.** { *; }
	-keep public interface com.smaato.sdk.** { *; }

Initialize the NextGen SDK

Add the following to your YourApplication.OnCreate() method, to initialize the Smaato SDK. Additionally, it is recommended to configure the SDK with user information. This is an optional step and can be implemented at a later time.

import android.app.Application;
import com.smaato.sdk.core.AdContentRating;
import com.smaato.sdk.core.Config;
import com.smaato.sdk.core.Gender;
import com.smaato.sdk.core.SmaatoSdk;
import com.smaato.sdk.core.log.LogLevel;

public class YourApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        // // initialize SDK first!
        Config config = Config.builder()
                // log errors only
                .setLogLevel(LogLevel.ERROR)
                // allow HTTPS traffic only
                .setHttpsOnly(true)
                .build();
        // initialize the Smaato SDK
        SmaatoSdk.init(this, config, "SMAATO_PUBLISHER_ID");
      
        // You can also initialize the Smaato SDK without configuration:
        // SmaatoSdk.init(this, "SMAATO_PUBLISHER_ID");

        // optional configuration
        SmaatoSdk.setSearchQuery("bitcoin, lamborghini, san-francisco");
        SmaatoSdk.setGender(Gender.MALE); // usually set after user logs in
        SmaatoSdk.setAge(40); // usually set after user logs in
        // allow the Smaato SDK to automatically get the user's location
        SmaatoSdk.setGPSEnabled(true);
    }
}

Important Note: Starting from NextGen SDK version 21.2.1, the new GPSEnabled flag allows the SDK to automatically get the user’s location when permission is given by the user. By default, this flag is set to off and the user location will not be provided in the ad request. To enable this the GPSEnabled flag must be set to yes.

Important Details About GDPR

The General Data Protection Regulation (GDPR) was created to provide European users with greater transparency and control over their personal information. As a publisher, you should integrate a Consent Management Platform (CMP) and request for user, vendor, and purpose consents as outlined in IAB Europe’s IAB Tech Lab – CMP API v2. You can find an example implementation of a web-based CMP and the corresponding native wrappers here in the IAB’s GDPR-Transparency-and-Consent-Framework.

You can also make your own custom CMP. The collected end-user consent information needs to be stored in SharedPreferences using the following keys:

 

Transparency and Consent Framework v2:

Key Type Description
IABTCF_gdprApplies Number

1 = Subject to GDPR
0 = Not subject to GDPR
-1 or unset = Undetermined (default before initialization)

IABTCF_TCString String

Base64-encoded consent string as defined in IAB Tech Lab – Consent string and vendor list formats v2

Sample of GDPR Saving in SharedPreferences

import android.content.SharedPreferences;
import android.preference.PreferenceManager;

...
// User is not subject to GDPR
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context_here);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("IABTCF_gdprApplies", 0);
editor.commit();
// Use this example above to set values for the rest of the GDPR keys

Important Details About CCPA

The California Consumer Privacy Act (CCPA) was created to provide California consumers with greater transparency and control over their personal information.

For more information about the CCPA regulation, please check out the Smaato FAQ. You can also review the IAB’s U.S. Privacy String documentation.

For Publishers with California-Based Users

As a publisher, you need to make sure to request consent from California-based users (to give or refuse consent / to opt-out or opt-in ) about private data transfer. This answer should be saved in SharedPreferences with key “IABUSPrivacy_String” in the US Privacy String format (CCPA Opt-Out Storage Format).

The Smaato NextGen SDK reads this value in the key “IABUSPrivacy_String” if it exists and uses this as an optional parameter for all ad requests.

Sample of CCPA Saving in SharedPreferences

import android.content.SharedPreferences;
import android.preference.PreferenceManager;

...
// save the user's consent
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context_here);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("IABUSPrivacy_String", "1YNN"); // for example "1YNN"
editor.commit();

 

Ads for Testing Purposes

Adspace ID Type Description
130626424 Rich Media Banner / Med-rect / Leaderboard / Skyscraper
130635694 Static Image Banner / Med-rect / Leaderboard / Skyscraper
130635706 MRAID Banner / Med-rect / Leaderboard / Skyscraper
133150211 Rich Media / Video Interstitial (Video with an end-card + Rich Media Interstitial for 320×480, 480×320, 1024×768 & 768×1024)
133149967 Video Skippable Video
133149969 Rewarded Rewarded Video
133149968 Rewarded Rewarded Video without an end-card
130783664 Native Native with static image main creative

Supported Callbacks

Banners

Callback Message Reason
onBannerLoaded This will be invoked when an advertisement is successfully received.
onBannerFailed This will be invoked when an advertisement request is failed or time-to-live of the ad has been expired.
onBannerClicked This will be invoked when a click event is registered for an advertisement.
onBannerImpression This will be invoked when an impression occurred.

Interstitials

Callback Message Reason
onInterstitialLoaded This will be invoked when an advertisement is successfully received
onInterstitialFailed This will be invoked when there was an error during loading/showing an ad or time-to-live of the ad has been expired.
onInterstitialShown This will be invoked when a Fullscreen Interstitial Ad ad is opened.
onInterstitialDismissed This will be invoked when a Fullscreen Interstitial Ad ad is closed.
onInterstitialClicked This will be invoked when a user clicks on an ad.
onInterstitialImpression This will be invoked when an impression occurred.

Rewarded Video

Callback Message Reason
onRewardedVideoLoadSuccess This will be invoked when the Rewarded Video Ad is successfully received.
onRewardedVideoLoadFailure This will be invoked when there was an error during loading/showing an ad or time-to-live of the Rewarded Video Ad is expired.
onRewardedVideoPlaybackError This will be invoked when there is an error during the Rewarded Video Ad playback.
onRewardedVideoClosed This will be invoked when the Rewarded Video Ad is closed.
onRewardedVideoClicked This will be invoked when the Rewarded Video Ad is clicked.
onRewardedVideoStarted This will be invoked when the Rewarded Video Ad starts playing.
onRewardedVideoCompleted This will be invoked when the Rewarded Video Ad is completed and the user should be rewarded.

Prebid a Banner Request

AdManagerAdView adView = new AdManagerAdView(this);
adView.setAdSizes(AdSize.BANNER);
adView.setAdUnitId("YOUR_GAM_AD_UNIT_ID");
UnifiedBidding.prebidBanner(/*"SMAATO_ADSPACE_ID"*/, UBBannerSize.XX_LARGE_320x50, (ubBid,  prebidRequestError) -> {
   if (ubBid != null) {
       // Let's assume this is the max price of your line items (you will want to change this float to yours)
       float maxPrice = 0.1F;
 
       String bidKeyword;
       if (ubBid.bidPrice > maxPrice) {
           bidKeyword = String.format(Locale.US, "smaato_cpm:%.2f", maxPrice);
       } else {
           bidKeyword = ubBid.mopubPrebidKeyword;
       }
       AdManagerAdRequest kvpRequest = new AdManagerAdRequest.Builder().build();
       Map ubKVP = new HashMap();
       ubKVP.put("smaub", bidKeyword);
       kvpRequest.customTargeting = ubKVP;
   } else if (prebidRequestError != null) {
       /* Timber.e(prebidRequestError.error.toString()) */
   }
      adView.loadAd(kvpRequest);
});

Prebid an Interstitial Request

private AdManagerInterstitialAd mAdManagerInterstitialAd;
UnifiedBidding.prebidInterstitial(/*"SMAATO_ADSPACE_ID"*/, (ubBid,  prebidRequestError) -> {
   if (ubBid != null) {
       // Let's assume this is the max price of your line items (you will want to change this float to yours)
       float maxPrice = 0.1F;
 
       String bidKeyword;
       if (ubBid.bidPrice > maxPrice) {
           bidKeyword = String.format(Locale.US, "smaato_cpm:%.2f", maxPrice);
       } else {
           bidKeyword = ubBid.mopubPrebidKeyword;
       }
       AdManagerAdRequest kvpRequest = new AdManagerAdRequest.Builder().build();
       Map ubKVP = new HashMap();
       ubKVP.put("smaub", bidKeyword);
       kvpRequest.customTargeting = ubKVP;
       
   } else if (prebidRequestError != null) {
       /* Timber.e(prebidRequestError.error.toString()) */
   }
      AdManagerInterstitialAd.load(this,"YOUR_GAM_AD_UNIT_ID", kvpRequest,
        new AdManagerInterstitialAdLoadCallback() {
      @Override
      public void onAdLoaded(@NonNull AdManagerInterstitialAd interstitialAd) {
        // The mAdManagerInterstitialAd reference will be null until
        // an ad is loaded.
        mAdManagerInterstitialAd = interstitialAd;
        Log.i(TAG, "onAdLoaded");
      }

      @Override
      public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
        // Handle the error
        Log.i(TAG, loadAdError.getMessage());
        mAdManagerInterstitialAd = null;
      }
    });
});

Prebid a Rewarded Video Request

private RewardedAd mRewardedAd;
  private final String TAG = "MainActivity";

UnifiedBidding.prebidRewardedInterstitial("SMAATO_ADSPACE_ID", prebidListener);
 
private final UnifiedBidding.PrebidListener prebidListener = (ubBid, ubBidRequestError) ->
            Threads.runOnUi(() -> {
                if (ubBidRequestError != null) {
                    Log.d(TAG, "SmaatoSdk PreBid error: " + ubBidRequestError.error);
                }
 
                if (ubBid == null) {
                    Log.d(TAG, "SmaatoSdk PreBid error: empty response");
                    return;
                }
 
                SmaatoRewardedVideoMediationSettings settings = new SmaatoRewardedVideoMediationSettings();
                settings.put(
                    SmaatoRewardedVideoMediationSettings.UNIQUE_ID_KEY,
                    ubBid.metadata.get(SmaatoRewardedVideoMediationSettings.UNIQUE_ID_KEY)
                );
             
                AdManagerAdRequest kvpRequest = new AdManagerAdRequest.Builder().build();
                Map ubKVP = new HashMap();
                ubKVP.put("smaub", ubBid.mopubPrebidKeyword);
                kvpRequest.customTargeting = ubKVP;
             
                
                RewardedAd.load(this, "YOUR_GAM_AD_UNIT_ID", kvpRequest, new RewardedAdLoadCallback() {
                  @Override
                  public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
                  // Handle the error.
                  Log.d(TAG, loadAdError.getMessage());
                  mRewardedAd = null;
                  }

                 @Override
                 public void onAdLoaded(@NonNull RewardedAd rewardedAd) {
                 mRewardedAd = rewardedAd;
                 Log.d(TAG, "Ad was loaded.");
                 }
               });
             
       });

Doc Feedback Product Feedback

Last Modified: March 15, 2022 at 3:28 pm