Trusted Arbiter compares a loaded CloudX bid with supported third-party bids and returns the selected platform. Available from Unity SDK 4.1.0 (backed by Android SDK 4.1.1 and iOS SDK 3.4.1), it supports CloudX, Unity LevelPlay, and PubMatic bid inputs.
Call CloudXSdk.Arbiter() after CloudXSdk.Initialize() has completed (after the CloudXInitializationCallbacks.OnSdkInitializedEvent event). Until the arbiter service is available, the SDK falls back to selecting the highest comparable USD bid from the supplied inputs.
Basic API
Create bid candidates from loaded ads, then pass them to CloudXSdk.Arbiter().
using System.Collections.Generic;
using CloudX;
using UnityEngine;
// cloudXAd is the CloudXAd from a CloudX OnAdLoadSuccess callback.
// Its AdValues map carries the trusted-payload keys the server uses to validate the bid.
// levelPlayNetwork / levelPlayRevenue / levelPlayPrecision come from the Unity LevelPlay ad info.
// pubMaticPrice and pubMaticPartner come from the PubMatic/OpenWrap bid object.
var bids = new List<CloudXArbiterBid>
{
new CloudXArbiterBid.CloudX(cloudXAd),
new CloudXArbiterBid.LevelPlay(
NetworkName: levelPlayNetwork,
Revenue: levelPlayRevenue,
Precision: levelPlayPrecision),
new CloudXArbiterBid.PubMatic(
Price: pubMaticPrice,
PartnerName: pubMaticPartner),
};
CloudXSdk.Arbiter(bids, result =>
{
Debug.Log($"Selected platform: {result.Platform}");
});
CloudXArbiterBid.CloudX accepts the CloudXAd object from a CloudX load callback. CloudXArbiterBid.LevelPlay accepts Unity LevelPlay ad info values. CloudXArbiterBid.PubMatic accepts a PubMatic OpenWrap bid price and optional partner name. The Extras map is optional on both the LevelPlay and PubMatic bids, and PartnerName is optional on PubMatic. The completion callback runs on the Unity main thread, so you can show an ad or update UI directly from it.
result.Platform is CloudXArbiterPlatform.CloudX, LevelPlay, or PubMatic for the selected platform, or CloudXArbiterPlatform.None when no winner could be selected (for example, no bids were supplied). The result also exposes result.Id (the auction identifier), result.BidId (the winning bid identifier, null when the platform is None), and result.Extras (additional metadata from the winning network).
Step-by-step: arbitrate CloudX and LevelPlay
This walkthrough shows exactly which Unity LevelPlay callback to read and which values to pass into CloudXSdk.Arbiter(). It uses an interstitial, but the same field mapping applies to any format.
Load both candidates
Create the LevelPlay interstitial and start a load on each platform. Subscribe to the load callbacks before loading.var levelPlayAd = new LevelPlayInterstitialAd("YOUR_LEVELPLAY_AD_UNIT_ID");
levelPlayAd.OnAdLoaded += OnLevelPlayLoaded;
levelPlayAd.OnAdLoadFailed += OnLevelPlayLoadFailed;
levelPlayAd.LoadAd();
CloudXAdsCallbacks.Interstitial.OnAdLoadSuccess += OnCloudXLoaded;
CloudXSdk.LoadInterstitial("YOUR_CLOUDX_AD_UNIT_ID");
Capture each platform's loaded ad
LevelPlay delivers a LevelPlayAdInfo in its OnAdLoaded callback; CloudX delivers a CloudXAd in OnAdLoadSuccess. Hold onto both — you read the arbiter inputs from them in the next step.private CloudXAd _cloudXAd;
private LevelPlayAdInfo _levelPlayInfo;
private void OnCloudXLoaded(CloudXAd ad) => _cloudXAd = ad;
private void OnLevelPlayLoaded(LevelPlayAdInfo info) => _levelPlayInfo = info;
Map the values into bids
Read the LevelPlay fields off LevelPlayAdInfo and pass them to CloudXArbiterBid.LevelPlay. The CloudX bid takes the CloudXAd directly.LevelPlayAdInfo field | Type | CloudXArbiterBid.LevelPlay parameter |
|---|
adNetwork | string | NetworkName |
revenue | double? | Revenue (coalesce with ?? 0) |
precision | string | Precision |
var bids = new List<CloudXArbiterBid>
{
new CloudXArbiterBid.CloudX(_cloudXAd),
new CloudXArbiterBid.LevelPlay(
NetworkName: _levelPlayInfo.adNetwork, // LevelPlayAdInfo.adNetwork
Revenue: _levelPlayInfo.revenue ?? 0, // LevelPlayAdInfo.revenue is double?
Precision: _levelPlayInfo.precision), // LevelPlayAdInfo.precision
};
Run the arbiter
Pass the bids to CloudXSdk.Arbiter() with a completion callback. The callback runs on the Unity main thread.CloudXSdk.Arbiter(bids, OnArbiterCompleted);
Show the winner
Switch on result.Platform and show the winning platform’s ad. CloudXArbiterPlatform.None means no winner was selected — continue without showing an ad.private void OnArbiterCompleted(CloudXArbiterResult result)
{
switch (result.Platform)
{
case CloudXArbiterPlatform.CloudX:
CloudXSdk.ShowInterstitial("YOUR_CLOUDX_AD_UNIT_ID", "level_complete");
break;
case CloudXArbiterPlatform.LevelPlay:
levelPlayAd.ShowAd("level_complete");
break;
default:
break; // CloudXArbiterPlatform.None — no winner; continue without an ad
}
}
LevelPlayAdInfo exposes camelCase fields (adNetwork, revenue, precision) in the LevelPlay Unity SDK 8.x. revenue is a double?, so coalesce it (?? 0) when passing it to the non-nullable Revenue parameter.
The ArbiterInterstitialController below packages these same steps into a reusable component that prepares a winner ahead of the placement.
Interstitial example
This interstitial example arbitrates between two platforms: CloudX and Unity LevelPlay. Prepare a winner before the placement is reached:
- Load CloudX and LevelPlay in parallel.
- Wait until both platforms have loaded or failed.
- Submit only loaded candidates to Trusted Arbiter.
- Cache the selected platform.
- At the placement, show the cached winner immediately.
If both platforms fail, start another load cycle. If the placement is reached before a winner is prepared, continue the app flow without showing an ad.
ArbiterInterstitialController.cs
using System.Collections.Generic;
using CloudX;
using UnityEngine;
/// <summary>
/// Prepares a Trusted Arbiter winner ahead of time so an interstitial can be shown
/// instantly when a placement is reached.
///
/// Loads the CloudX and LevelPlay interstitials in parallel, waits until both have
/// finished loading or failing, submits the loaded candidates to CloudXSdk.Arbiter,
/// and caches the selected CloudXArbiterPlatform in _nextWinner.
/// </summary>
public class ArbiterInterstitialController : MonoBehaviour
{
private const string CloudXAdUnitId = "interstitial_main";
// Set by the host once the LevelPlay Unity SDK reports a loaded interstitial.
public string LevelPlayNetwork;
public double LevelPlayRevenue;
public string LevelPlayPrecision;
// Invoked once the arbiter has selected a platform for the next show.
public System.Action<CloudXArbiterPlatform> OnWinnerPrepared;
private CloudXAd _cloudXAd;
private bool _cloudXLoadDone;
private bool _levelPlayLoaded;
private bool _levelPlayLoadDone;
private CloudXArbiterPlatform? _nextWinner;
private void OnEnable()
{
CloudXAdsCallbacks.Interstitial.OnAdLoadSuccess += OnCloudXLoaded;
CloudXAdsCallbacks.Interstitial.OnAdLoadFailed += OnCloudXLoadFailed;
CloudXAdsCallbacks.Interstitial.OnAdHidden += OnCloudXHidden;
CloudXAdsCallbacks.Interstitial.OnAdShowFailed += OnCloudXShowFailed;
}
private void OnDisable()
{
CloudXAdsCallbacks.Interstitial.OnAdLoadSuccess -= OnCloudXLoaded;
CloudXAdsCallbacks.Interstitial.OnAdLoadFailed -= OnCloudXLoadFailed;
CloudXAdsCallbacks.Interstitial.OnAdHidden -= OnCloudXHidden;
CloudXAdsCallbacks.Interstitial.OnAdShowFailed -= OnCloudXShowFailed;
}
/// <summary>Starts a load for each platform that does not currently hold a cached ad.</summary>
public void LoadMissingAds()
{
if (_cloudXAd == null) CloudXSdk.LoadInterstitial(CloudXAdUnitId);
if (!_levelPlayLoaded) LoadLevelPlayInterstitial();
}
/// <summary>
/// Shows the prepared winner, returning true only when a show call was made.
///
/// Returns false when no winner is ready or the cached ad is no longer available, in which
/// case a fresh load cycle is started.
/// </summary>
public bool ShowAtPlacement(string placement)
{
switch (_nextWinner)
{
case CloudXArbiterPlatform.CloudX:
return ShowCloudX(placement);
case CloudXArbiterPlatform.LevelPlay:
return ShowLevelPlay(placement);
default:
return false;
}
}
/// <summary>
/// Runs the arbiter once both platforms have settled, then caches the winning platform.
///
/// Returns early until both loads complete. If neither platform loaded, it restarts the
/// load cycle; otherwise it submits the loaded candidates to CloudXSdk.Arbiter.
/// </summary>
private void MaybePrepareWinner()
{
if (!_cloudXLoadDone || !_levelPlayLoadDone) return;
if (_cloudXAd == null && !_levelPlayLoaded)
{
_cloudXLoadDone = false;
_levelPlayLoadDone = false;
LoadMissingAds();
return;
}
var bids = new List<CloudXArbiterBid>();
if (_cloudXAd != null)
{
bids.Add(new CloudXArbiterBid.CloudX(_cloudXAd));
}
if (_levelPlayLoaded)
{
bids.Add(new CloudXArbiterBid.LevelPlay(
NetworkName: LevelPlayNetwork,
Revenue: LevelPlayRevenue,
Precision: LevelPlayPrecision));
}
CloudXSdk.Arbiter(bids, result =>
{
_nextWinner = result.Platform;
OnWinnerPrepared?.Invoke(result.Platform);
});
}
private bool ShowCloudX(string placement)
{
if (CloudXSdk.IsInterstitialReady(CloudXAdUnitId))
{
CloudXSdk.ShowInterstitial(CloudXAdUnitId, placement);
return true;
}
ClearCloudXAndLoadMissingAds();
return false;
}
private bool ShowLevelPlay(string placement)
{
if (IsLevelPlayInterstitialReady())
{
ShowLevelPlayInterstitial(placement);
return true;
}
ClearLevelPlayAndLoadMissingAds();
return false;
}
private void OnCloudXLoaded(CloudXAd ad)
{
_cloudXAd = ad;
_cloudXLoadDone = true;
MaybePrepareWinner();
}
private void OnCloudXLoadFailed(string adUnitId, CloudXError error)
{
_cloudXAd = null;
_cloudXLoadDone = true;
MaybePrepareWinner();
}
private void OnCloudXHidden(CloudXAd ad) => ClearCloudXAndLoadMissingAds();
private void OnCloudXShowFailed(CloudXAd ad, CloudXError error) => ClearCloudXAndLoadMissingAds();
private void ClearCloudXAndLoadMissingAds()
{
_cloudXAd = null;
_cloudXLoadDone = false;
_nextWinner = null;
LoadMissingAds();
}
private void ClearLevelPlayAndLoadMissingAds()
{
_levelPlayLoaded = false;
_levelPlayLoadDone = false;
_nextWinner = null;
LoadMissingAds();
}
/*
* The following members wrap the LevelPlay Unity SDK. Replace the bodies with calls into
* the LevelPlay SDK you integrate, and route its load callbacks into the fields above:
* on load success, set _levelPlayLoaded = true and the LevelPlay* values, then set
* _levelPlayLoadDone = true and call MaybePrepareWinner(); on load failure, set
* _levelPlayLoaded = false, _levelPlayLoadDone = true, and call MaybePrepareWinner().
* On ad close or show failure, call ClearLevelPlayAndLoadMissingAds() to drop the
* consumed ad and start a fresh cycle.
*/
private void LoadLevelPlayInterstitial() { /* LevelPlay.LoadInterstitial(...) */ }
private bool IsLevelPlayInterstitialReady() => _levelPlayLoaded;
private void ShowLevelPlayInterstitial(string placement) { /* LevelPlay.ShowInterstitial(...) */ }
}
ShowAtPlacement() returns true only when an ad show call was made. Keep the cached LevelPlay candidate values up to date while the LevelPlay ad remains loaded.
For PubMatic OpenWrap, create a third-party bid with new CloudXArbiterBid.PubMatic(price, partnerName). If the arbiter service is unavailable, the SDK falls back to the highest comparable USD bid among the supplied supported bid inputs.