Bid floors in AdMob Pro
Setup in AdMob Pro
Set two Ad Units per Ad Format in the AdMob dashboard. Create as many Mediation groups as you want, each with difference floor and include both Ad Units in each group. In every mediation group create the same KVP value parameter with different Value. When integrating in code, you'll have to map provided bid floor from Nefta insights to the value corresponding mediation group.
Requesting user floor price insights
Via the SDK, partners will request user specific floor price insight key-values:
- User value bid floor price:
._interstitial._floorPriceor._rewarded._floorPrice.
NeftaPlugin._instance!.GetInsights(Insights.Interstitial, previousInsight: track._insight, callback: { insights in
self.Log("Load with insights: \(insights)")
if let insight = insights._interstitial {
track._insight = insight
track._floorPrice = insight._floorPrice
// map floorPrice to your AdMob Pro mediation group configuration
// sample KVP mapping:
var mediationGroup = "low";
if track._floorPrice > 100
{
mediationGroup = "high";
}
else if track._floorPrice > 50
{
mediationGroup = "medium";
}
let extras = GADExtras()
extras.additionalParameters = [ "mediation group key": mediationGroup ]
track._request = GADRequest()
track._request!.register(extras)
GADNeftaAdapter.onExternalMediationRequest(with: insight, request: track._request!, adUnitId: track._adUnitId)
self.Log("Loading \(track._adUnitId) as Optimized with \(mediationGroup)")
Task {
do {
let interstitial = try await GADInterstitialAd.load(withAdUnitID: track._adUnitId, request: track._request)
DispatchQueue.main.async {
track.OnLoad(interstitial: interstitial)
}
} catch {
DispatchQueue.main.async {
track.OnLoadFail(error: error)
}
}
}
} else {
track.AfterLoadFail()
}
}, timeout: 5)NeftaPlugin._instance.GetInsights(Insights.INTERSTITIAL, track._insight, (Insights insights) -> {
Log("LoadWithInsights: " + insights);
if (insights._interstitial != null) {
track._insight = insights._interstitial;
track._floorPrice = track._insight._floorPrice;
// map floorPrice to your AdMob Pro mediation group configuration
// sample KVP mapping:
String mediationGroup = "low";
if (track._floorPrice > 100)
{
mediationGroup = "high";
}
else if (track._floorPrice > 50)
{
mediationGroup = "medium";
}
Bundle extras = new Bundle();
extras.putString("mediation group key", mediationGroup);
track._request = new AdRequest.Builder().addNetworkExtrasBundle(AdMobAdapter.class, extras).build();
NeftaAdapter.OnExternalMediationRequestWithInsight(track._insight, track._request, track._adUnitId);
Log("Loading " + track._adUnitId + " as Optimized with " + mediationGroup);
InterstitialAd.load(_activity, track._adUnitId, track._request, track._loadCallbacks);
} else {
track.AfterLoadFail();
}
}, 5);Adapter.GetInsights(Insights.Interstitial, track.Insight, (Insights insights) =>
{
var insight = insights._interstitial;
if (insight != null)
{
track.Insight = insight;
track.FloorPrice = insight._floorPrice;
track.Request = new AdRequest();
// map floorPrice to your AdMob Pro mediation group configuration
// sample KVP mapping:
string mediationGroup = "low";
if (track.FloorPrice > 100)
{
mediationGroup = "high";
}
else if (track.FloorPrice > 50)
{
mediationGroup = "medium";
}
track.Request.Extras = new Dictionary<string, string>()
{
{ "mediation group key", mediationGroup },
};
Adapter.OnExternalMediationRequest(insight, track.Request, insight._adUnit);
SetStatus($"Loading {insight._adUnit} as Optimized with {track.FloorPrice}");
InterstitialAd.Load(insight._adUnit, track.Request, track.OnLoadCallback);
}
else
{
track.RestartAfterFailedLoad();
}
}, 5);
Validate returned valuesIt is crucial a partner checks the values received are valid. Only if a valid response is received, a partner should proceed with using the values.
You are guaranteed to receive the callback in the same thread with all keys that you specified in the request.
Log outcome of ad opportunity
After a partner has received user insights, validated the response and requested an ad in MAX using the recommended_*_ad_unit_id field, the partner should log the outcome of the ad opportunity in order to continuously maximise ad revenue uplift.
When the ad successfully loads, log the response using the following function:
GADNeftaAdapter.onExternalMediationRequestLoad(withInterstitial: _dynamicInterstitial, request: _dynamicRequest!)@Override
public void onAdLoaded(@NonNull InterstitialAd ad) {
NeftaAdapter.OnExternalMediationRequestLoaded(ad, _dynamicRequest);
}Adapter.OnExternalMediationRequestLoaded(ad, _dynamicRequest);When the ad fails to load, log the response using the following function:
GADNeftaAdapter.onExternalMediationRequestFail(_dynamicRequest!, error: error)@Override
public void onAdFailedToLoad(@NonNull LoadAdError adError) {
NeftaAdapter.OnExternalMediationRequestFailed(_dynamicRequest, adError);
}Adapter.OnExternalMediationRequestFailed(_dynamicRequest, error);When an ad successfully shows log the impression with this:
func onPaid(adValue: GADAdValue) {
GADNeftaAdapter.onExternalMediationImpression(withInterstitial: _presentingInterstitial, adValue: adValue)
}@Override
public void onPaidEvent(@NonNull AdValue adValue) {
NeftaAdapter.OnExternalMediationImpression(_presentingInterstitial, adValue);
}Adapter.OnExternalMediationImpression(_presentingInterstitial, adValue);And when receiving click callback:
func adDidRecordClick(_ ad: GADFullScreenPresentingAd) {
GADNeftaAdapter.onExternalMediationClick(withInterstitial: _presentingInterstitial)
}@Override
public void onAdClicked() {
NeftaAdapter.OnExternalMediationClick(_presentingInterstitial);
}Adapter.OnExternalMediationClick(_presentingInterstitial);Initial Ad Unit has no fill
If the initially recommended ad unit doesn't return an ad:
- Re-request the bid floor price and recommended ad unit id: the new floor price takes into account the previous no-fill event and is adjusted in real time. You can repeat this process for each ad opportunity. However, latency should be considered if requesting multiple times per ad opportunity. Nefta will help in balancing fill %, revenue uplift and latency.
- Request an ad from AdMob using an AdUnit without a floor price - a default ad unit.
Example code
Full example:
- Native iOS: https://github.com/Nefta-io/NeftaAMAdapter-iOS/blob/main/AMIntegration/Rewarded.swift
- Native Android: https://github.com/Nefta-io/NeftaAMAdapter-Android/blob/main/AdMobIntegration/src/main/java/com/nefta/am/Rewarded.java
- Unity: https://github.com/Nefta-io/NeftaAMAdapter-Unity/blob/main/Assets/AdDemo/Rewarded.cs
Updated 12 days ago