Trusted Arbiter
Compare CloudX bids with supported third-party bids in React Native apps
Trusted Arbiter compares a loaded CloudX bid with supported third-party bids and returns the selected platform. React Native support is backed by the CloudX native SDKs and supports CloudX, Unity LevelPlay, PubMatic, and custom publisher-supplied bid inputs.
Why use Trusted Arbiter?
When your app loads ads from several platforms, it needs a way to choose which ad to show. Trusted Arbiter provides a shared comparison API for supported bids.
Less comparison logic to maintain
Submit the supported bids to Trusted Arbiter and use the returned platform to select the ad. Your app continues to manage partner SDK integration, ad loading, and display.
Use available bid values
Trusted Arbiter can compare actual bid values where available. Some demand uses estimated prices. See the pricing guidance below for each supported input.
Use loaded ad objects or ad info objects from each SDK to populate bid values:
import { CloudX, CloudXArbiterBid } from 'cloudx-react-native';
// cloudXAdInfo is the CloudXAdInfo object from a CloudX load callback.
// levelPlayAdInfo is the Unity LevelPlay ad info object.
// pubMaticPrice and pubMaticPartnerName come from the PubMatic/OpenWrap bid object.
const result = await CloudX.arbiter({
bids: [
CloudXArbiterBid.cloudX(cloudXAdInfo),
CloudXArbiterBid.levelPlay({
networkName: levelPlayAdInfo.adNetwork,
revenue: levelPlayAdInfo.revenue,
precision: levelPlayAdInfo.precision,
}),
CloudXArbiterBid.pubMatic({
price: pubMaticPrice,
partnerName: pubMaticPartnerName,
}),
],
});
console.log('Selected platform:', result.platform);On timeout, error, or an unavailable arbiter service, the SDK falls back to the highest comparable USD bid among the supplied supported bid inputs.
When to run the arbiter
Run the arbiter when your candidate ads finish loading — never on the show path. CloudX.arbiter() is a network round trip, and a user who taps a button that shows an ad must never wait on it.
Fullscreen formats (interstitial, rewarded, app open): prepare ahead. Load every candidate in parallel. Once they have all settled — loaded or failed — run the arbiter and store the result. At the placement, show the stored winner immediately, with no network call. Run the cycle again after the ad is shown or hidden, after it fails to display, or when a candidate expires.
import { CloudX, CloudXAdInfo, CloudXArbiterBid, CloudXInterstitialAd, CloudXArbiterResult } from 'cloudx-react-native';
let nextWinner: CloudXArbiterResult | null = null;
// Runs as soon as the candidates have loaded, ahead of the placement.
const prepareWinner = async (cloudXAdInfo: CloudXAdInfo, adMobAdUnitId: string) => {
nextWinner = await CloudX.arbiter({
bids: [CloudXArbiterBid.cloudX(cloudXAdInfo), CloudXArbiterBid.adMob({ adUnitId: adMobAdUnitId })],
});
};
// Runs at the placement. No network call here.
const showInterstitial = (cloudXAdUnitId: string) => {
switch (nextWinner?.platform) {
case 'CLOUDX':
CloudXInterstitialAd.showAd(cloudXAdUnitId);
break;
case 'ADMOB':
// show your AdMob interstitial
break;
default:
break; // no winner prepared; continue without an ad
}
nextWinner = null;
};If the placement arrives before a winner is stored, either continue without an ad or show the single candidate that did load. That is an acceptable degraded path, never the primary one.
View formats (banner, MREC): arbitrate, then render. Nothing user-initiated is waiting, so it is correct to attach or render the winner directly where the await CloudX.arbiter() call returns — the arbiter completing is the trigger to show. Only the winner’s view or assets may ever be attached. See Banner and MREC for the view-attachment rules.
AdMob and Google Ad Manager
CloudX compares a loaded CloudX ad with a loaded AdMob or Google Ad Manager ad. AdMob and Ad Manager are separate demand sources, so both may bid in the same arbitration. This applies to publisher-managed mediation setups, including accounts described commercially as AdMob Pro; there is no separate AdMob Pro SDK API.
Google demand does not normally reveal the price of a loaded ad before it is shown, so there is no pre-bid price for the arbiter to compare against CloudX’s bid. CloudX prices the bid automatically from your historical Google performance, so you do not supply a price and no pre-bid pricing API is required. The revenue reporting below feeds that history. See how AdMob/GAM estimated pricing works.
If your AdMob account exposes impression-level revenue data pre-bid, you can supply that exact price yourself instead of using the estimate — see Manual input with pre-bid ILRD below.
Report Google paid events back to CloudX (required)
Reporting Google’s impression-level revenue is a required part of the Trusted Arbiter AdMob and Ad Manager integration, not an optional analytics extra. After you show an AdMob or Ad Manager ad that won an arbitration, forward Google’s paid event into the CloudX SDK. Without those events CloudX never learns the realized price of Google demand, and the estimates it supplies to future arbitrations degrade.
Call CloudX.reportRevenueData() from your Google paid-event handler. Revenue is a currency-unit number, not micros — react-native-google-mobile-ads already reports event.value in currency units.
import { CloudX, CloudXRevenuePlatform, CloudXRevenuePrecision } from 'cloudx-react-native';
// event is the paid event from your Google ad (react-native-google-mobile-ads onPaid).
const reportGooglePaidEvent = (event, adFormat, adUnitId) =>
CloudX.reportRevenueData({
platform: CloudXRevenuePlatform.ADMOB, // use CloudXRevenuePlatform.GAM for Ad Manager
revenue: event.value,
adFormat,
currencyCode: event.currency,
precision: CloudXRevenuePrecision.ESTIMATED,
networkName: 'admob',
adUnitId,
});Report the ad unit id you passed to the arbiter bid so CloudX can attribute the realized price to the right ad unit. See Publisher-Reported Revenue Data for the full field reference and the precision mapping.
Create the bid from the ad unit id of the ad you loaded:
// networkName is optional; pass the winning ad source when you know it.
const adMobBid = CloudXArbiterBid.adMob({
adUnitId: adMobAdUnitId,
networkName: adMobNetworkName ?? 'admob',
});
// An Ad Manager ad unit id takes the form /NNNNNNN/placement/name.
const adManagerBid = CloudXArbiterBid.gam({
adUnitId: '/21775744923/example/interstitial',
});
// Runs once the candidates have loaded, ahead of the placement.
nextWinner = await CloudX.arbiter({
bids: [CloudXArbiterBid.cloudX(cloudXAdInfo), adMobBid, adManagerBid],
});
// Runs at the placement. No network call here.
const showAd = () => {
if (nextWinner?.platform === 'ADMOB') {
// show the AdMob ad
} else if (nextWinner?.platform === 'GAM') {
// show the Ad Manager ad
}
nextWinner = null;
};Store the result rather than showing from where the arbiter returns — see When to run the arbiter.
A winning Google bid reports its own platform — the string 'ADMOB' or 'GAM'. You no longer need to inspect the result’s platformName to tell these sources apart, as you would for a custom bid.
Pass a blank ad unit id and the bid still builds rather than crashing your app, but it carries no usable identity: it is never priced and the server rejects it.
Manual input with pre-bid ILRD
Some AdMob accounts expose impression-level revenue data pre-bid: the ad value for the loaded ad is available at load time, before the ad is shown. This is a legacy, account-gated capability, so check with your Google account team whether it is enabled for your account. An exact per-impression price that you know before show is the one case where supplying your own price beats CloudX’s estimate.
Pass the pre-bid ad value as manualRevenuePerImpressionUSD and it overrides the estimate:
const adMobBid = CloudXArbiterBid.adMob({
adUnitId: adMobAdUnitId,
manualRevenuePerImpressionUSD: preBidPricePerImpressionUSD,
});The unit you receive depends on the native SDK underneath: the Google Mobile Ads SDK reports ad values in micros on Android and in currency units on iOS, so convert to a per-impression USD amount before passing it in.
How the value is treated:
0.0is a real price. It means this bid is worth nothing — not that the price is missing.- Negative and non-finite values are not prices, so they are treated as absent and logged.
- A blank ad unit id drops the manual price entirely, because a bid with no identity cannot be validated.
manualRevenuePerImpressionUSD is revenue for a single impression, in USD — not CPM, and a non-USD amount must be converted to USD first. See the Android and iOS pages for the per-platform unit-conversion rules for AdMob ad values.
Supported Formats
The arbiter is format-agnostic: it takes any loaded CloudX ad, and the same field mapping applies regardless of format.
- Fullscreen — interstitial, rewarded, app open. Prepare the winner ahead of the placement; see When to run the arbiter.
- View — banner, MREC. Arbitrate, then render the winner; see Banner and MREC for the view-attachment rules.
Banner and MREC
Auto-refresh conflicts with arbitration: a refresh can swap the ad after the arbiter has already picked a winner. Disable auto-refresh in the CloudX dashboard and call stopAutoRefresh() on the banner or MREC ad, and disable auto-refresh on the other arbitrated networks as well.
CloudXBannerAd.stopAutoRefresh(adUnitId);
// CloudXMRECAd.stopAutoRefresh(adUnitId);Only show the winning bid’s ad with showAd(adUnitId); keep the rest hidden with hideAd(adUnitId) (or never shown).
Recommended refresh flow: after the winner’s impression, load a new fill from the winning network only; retain non-winning ads that already have a fill and re-request just the unfilled networks; rerun the arbiter once responses return. Refresh the displayed ad every 20-30 seconds — shorter intervals decrease CPM performance.
Custom Bid Inputs
Use CloudXArbiterBid.custom() when you want Trusted Arbiter to compare CloudX with a third-party platform that does not have a dedicated bid factory.
const customBid = CloudXArbiterBid.custom({
platformName: 'my_mediation_platform',
networkName: 'winning_demand_source',
revenuePerImpressionUSD: 0.00125,
precision: 'EXACT',
extras: { ad_unit: 'third-party-ad-unit-id' },
});
const result = await CloudX.arbiter({
bids: [CloudXArbiterBid.cloudX(cloudXAdInfo), customBid],
});
console.log('Selected platform:', result.platform);When a custom bid wins, result.platform is 'CUSTOM' and result.platformName contains the platformName supplied on the bid. Pass revenuePerImpressionUSD as revenue for one impression in USD, not CPM. Use 'EXACT', 'ESTIMATED', 'PUBLISHER_DEFINED', or 'UNDEFINED' for precision to describe that revenue value. The React Native bid object requires networkName; pass '' if your source does not provide a winning-network name. A custom bid missing a non-blank platformName, revenue, or precision is dropped with a warning and does not compete.