First Look
Give CloudX the first chance to fill an ad placement, then fall back to your existing mediation setup
First Look gives CloudX the first chance to fill a placement while preserving your existing mediation setup as the fallback path. Start with one placement, verify load and show behavior, then expand to more placements.
This example uses an AdMob interstitial fallback through the Google Mobile Ads Unity Plugin. The same pattern applies to other fallback mediators: load CloudX first, load the fallback only if CloudX does not load, and keep the game flow moving when neither source is ready.
using System;
using CloudX;
using GoogleMobileAds.Api;
public sealed class FirstLookInterstitialController : IDisposable
{
public enum Source
{
CloudX,
AdMob,
}
public event Action<Source> AdLoaded;
public event Action<Source, string> AdLoadFailed;
public event Action<Source> AdShown;
public event Action<Source, string> AdShowFailed;
public event Action<Source> AdClosed;
public event Action<Source> AdClicked;
private readonly string cloudXAdUnitId;
private readonly string adMobAdUnitId;
private InterstitialAd adMobInterstitial;
private bool isLoadingCloudX;
private bool isLoadingAdMob;
private bool isDisposed;
public FirstLookInterstitialController(
string cloudXAdUnitId,
string adMobAdUnitId)
{
this.cloudXAdUnitId = cloudXAdUnitId;
this.adMobAdUnitId = adMobAdUnitId;
CloudXAdsCallbacks.Interstitial.OnAdLoadSuccess += OnCloudXLoaded;
CloudXAdsCallbacks.Interstitial.OnAdLoadFailed += OnCloudXLoadFailed;
CloudXAdsCallbacks.Interstitial.OnAdShowSuccess += OnCloudXShown;
CloudXAdsCallbacks.Interstitial.OnAdShowFailed += OnCloudXShowFailed;
CloudXAdsCallbacks.Interstitial.OnAdHidden += OnCloudXClosed;
CloudXAdsCallbacks.Interstitial.OnAdClicked += OnCloudXClicked;
}
public void Load()
{
if (isDisposed ||
isLoadingCloudX ||
isLoadingAdMob ||
CloudXSdk.IsInterstitialReady(cloudXAdUnitId) ||
(adMobInterstitial != null && adMobInterstitial.CanShowAd()))
{
return;
}
isLoadingCloudX = true;
CloudXSdk.LoadInterstitial(cloudXAdUnitId);
}
public bool Show()
{
if (isDisposed)
{
return false;
}
if (CloudXSdk.IsInterstitialReady(cloudXAdUnitId))
{
CloudXSdk.ShowInterstitial(cloudXAdUnitId);
return true;
}
return ShowAdMobFallback();
}
public void Dispose()
{
if (isDisposed)
{
return;
}
isDisposed = true;
CloudXAdsCallbacks.Interstitial.OnAdLoadSuccess -= OnCloudXLoaded;
CloudXAdsCallbacks.Interstitial.OnAdLoadFailed -= OnCloudXLoadFailed;
CloudXAdsCallbacks.Interstitial.OnAdShowSuccess -= OnCloudXShown;
CloudXAdsCallbacks.Interstitial.OnAdShowFailed -= OnCloudXShowFailed;
CloudXAdsCallbacks.Interstitial.OnAdHidden -= OnCloudXClosed;
CloudXAdsCallbacks.Interstitial.OnAdClicked -= OnCloudXClicked;
CloudXSdk.DestroyInterstitial(cloudXAdUnitId);
DestroyAdMobInterstitial();
}
private void OnCloudXLoaded(CloudXAd ad)
{
if (ad.AdUnitId != cloudXAdUnitId)
{
return;
}
isLoadingCloudX = false;
AdLoaded?.Invoke(Source.CloudX);
}
private void OnCloudXLoadFailed(string adUnitId, CloudXError _)
{
if (adUnitId != cloudXAdUnitId)
{
return;
}
isLoadingCloudX = false;
LoadAdMobFallback();
}
private void OnCloudXShown(CloudXAd ad)
{
if (ad.AdUnitId == cloudXAdUnitId)
{
AdShown?.Invoke(Source.CloudX);
}
}
private void OnCloudXShowFailed(CloudXAd ad, CloudXError error)
{
if (ad.AdUnitId != cloudXAdUnitId)
{
return;
}
if (!ShowAdMobFallback())
{
AdShowFailed?.Invoke(Source.CloudX, error.Message);
}
}
private void OnCloudXClosed(CloudXAd ad)
{
if (ad.AdUnitId == cloudXAdUnitId)
{
AdClosed?.Invoke(Source.CloudX);
}
}
private void OnCloudXClicked(CloudXAd ad)
{
if (ad.AdUnitId == cloudXAdUnitId)
{
AdClicked?.Invoke(Source.CloudX);
}
}
private void LoadAdMobFallback()
{
if (isDisposed ||
isLoadingAdMob ||
(adMobInterstitial != null && adMobInterstitial.CanShowAd()))
{
return;
}
isLoadingAdMob = true;
DestroyAdMobInterstitial();
InterstitialAd.Load(
adMobAdUnitId,
new AdRequest(),
(ad, error) =>
{
isLoadingAdMob = false;
if (isDisposed)
{
ad?.Destroy();
return;
}
if (error != null || ad == null)
{
AdLoadFailed?.Invoke(
Source.AdMob,
error?.GetMessage() ?? "AdMob returned no ad");
return;
}
adMobInterstitial = ad;
RegisterAdMobEvents(ad);
AdLoaded?.Invoke(Source.AdMob);
});
}
private bool ShowAdMobFallback()
{
if (adMobInterstitial == null || !adMobInterstitial.CanShowAd())
{
return false;
}
adMobInterstitial.Show();
return true;
}
private void RegisterAdMobEvents(InterstitialAd ad)
{
ad.OnAdFullScreenContentOpened += () =>
AdShown?.Invoke(Source.AdMob);
ad.OnAdFullScreenContentClosed += () =>
{
DestroyAdMobInterstitial();
AdClosed?.Invoke(Source.AdMob);
};
ad.OnAdFullScreenContentFailed += error =>
{
DestroyAdMobInterstitial();
AdShowFailed?.Invoke(Source.AdMob, error.GetMessage());
};
ad.OnAdClicked += () =>
AdClicked?.Invoke(Source.AdMob);
}
private void DestroyAdMobInterstitial()
{
adMobInterstitial?.Destroy();
adMobInterstitial = null;
}
}Call Show() at the placement moment. If it returns false, neither CloudX nor the fallback had a ready ad, so continue the game flow without showing an ad.
if (!firstLookInterstitial.Show())
{
ContinueToNextScene();
}After a show, close, or terminal failure, call Load() again when your game is ready to prepare the next placement opportunity. Call Dispose() from the owning MonoBehaviour when it is destroyed.