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)
Contact Sales Engineering
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
- For Banner Ads:
-
-
- Pass parameter for the SPX Adspace ID:
adSpaceId=<YOUR_SPX_ADSPACE_ID>
- Pass parameter for the 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
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 |
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();
Further Examples of the U.S. Privacy String 1YNN: User has not made a choice to opt-out 1NYY: User has made a choice to opt-out 1—: A Digital Property has determined to use a U.S. Privacy string version 1 and that CCPA does not apply to the transaction.
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);
});
adViewDidLoadAd
or adViewDidFailToLoadAd
events, clear KVPs in the GAM request and make another request to get new bids.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.");
}
});
});
Last Modified: March 15, 2022 at 3:28 pm