> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cloudx.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 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](https://developers.google.com/admob/unity/quick-start). 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.

<Info>
  Initialize CloudX and Google Mobile Ads before creating the controller. Keep your existing pacing, retry, and placement timing rules around this controller.
</Info>

```csharp FirstLookInterstitialController.cs theme={null}
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.

```csharp theme={null}
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.

<Tip>
  This sample keeps the fallback lazy: AdMob loads only after CloudX fails to load. Do not parallel-load both sources unless CloudX recommends a different rollout strategy for your game.
</Tip>
