Our complete CloudX Unity SDK integration guide is available on our docs site, https://docs.cloudx.io/en/unity/integration.
Click here to download the latest .unitypackage Github release.
This repository is also a runnable Unity demo project. It shows a working CloudX integration for banner, MREC (the 300x250 medium rectangle), interstitial and rewarded ads, plus a First Look flow that gives CloudX the first chance and falls back to AdMob.
Requirements:
- Unity 6 LTS
6000.0.60f1(seeProjectSettings/ProjectVersion.txt) - iOS: Xcode
- Android: the Unity Android Build Support module
Open the project in Unity and press Play, or build to a device from File > Build Settings. Build to a device for anything beyond a smoke test: the CloudX ad callbacks are no-ops in the Editor, so ads neither load nor show there.
The app opens on a launch screen that picks a demo flow. Nothing SDK-related happens until you
choose, which is deliberate: the iOS tracking prompt and CloudXSdk.Initialize belong to the flow
you picked, not to app start.
OptionsScene ── General ──> GeneralScene (the full CloudX surface)
└─ First Look ──> FirstLookScene (CloudX first, AdMob fallback)
There is no back navigation; relaunch the app to pick the other flow.
| Scene | Script holding the SDK calls | What it demonstrates |
|---|---|---|
Assets/Scenes/OptionsScene.unity |
Assets/Scripts/OptionsScreen.cs |
Picking a flow. No SDK calls. |
Assets/Scenes/GeneralScene.unity |
Assets/Scripts/GeneralScreen.cs |
Every ad format, straight CloudX. |
Assets/Scenes/FirstLookScene.unity |
Assets/Scripts/FirstLook/ |
CloudX first, AdMob as the fallback. |
Assets/Scripts/AdScreenUi.cs is the layout shared by the two ad screens. It is demo-only: it wires
buttons and reflows on rotate, and contains no SDK calls. Ignore it when reading the integration.
OptionsScene is index 0 in the build settings, so it is what launches. Each button calls
SceneManager.LoadScene with a scene name, which only resolves for scenes listed in
File > Build Settings, so all three are listed there.
A third flow, Arbiter/TPA, is not implemented yet and its button stays hidden.
The straight CloudX integration, one button per format. GeneralScreen.cs is the file to read: it is
the SDK call sequence and nothing else.
The screenshot has both a banner (top) and an MREC (bottom) on screen, which is why two buttons read "Show Bottom Banner" and "Hide MREC" - the labels track what the next tap will do.
| Button | Behaviour |
|---|---|
| Show Interstitial | Shows the preloaded interstitial, then reloads on close. |
| Show Rewarded | Same for rewarded, and logs the reward the user earned. |
| Show/Show edge Banner | First tap shows the banner. Each later tap moves it to the opposite edge, so you can cycle it around the screen. |
| Show/Hide MREC | Toggles MREC visibility. |
The status line at the bottom reports initialization; the text beside each fullscreen button reports that format's load state.
The initialization sequence, in the order Start() runs it:
- Resolve iOS tracking first. The SDK never prompts, and treats an undetermined ATT status as opted out, so a load issued before ATT resolves goes out as do-not-track and never fills - even if the user later grants permission. On Android this step is a no-op.
- Set privacy and user data (
SetHasUserConsent,SetDoNotSell, user and app key/values). These belong beforeInitializeso they apply to the first auction. - Subscribe to the initialization callbacks, then call
CloudXSdk.Initialize. - Create and load ads only after
OnSdkInitialized. Buttons stay inert until then, so no tap can reach aLoadbefore the SDK is ready.
Both initialization callbacks originate in native code, so neither is guaranteed to arrive. The demo re-enables the UI after 15 seconds regardless, because a permanently untappable screen is a worse failure than letting a tester poke the not-ready paths.
First Look gives CloudX the first chance to fill a placement and falls back to AdMob only when CloudX cannot. The full pattern is documented at https://docs.cloudx.io/en/unity/integrations/first-look; this screen is a working copy of it, meant to be lifted into a publisher app.
It covers two formats: interstitial and banner. Those are the two shapes the rule has to handle - a fullscreen ad that is consumed by being shown, and an inline ad that stays on screen and therefore needs an explicit pass cycle. Rewarded follows the interstitial exactly and MREC follows the banner exactly, so the screen would only repeat itself; the General screen already shows the SDK calls for all four formats. This screen is about the controller, not about format coverage.
The rules the controllers implement:
- CloudX is asked first. AdMob is loaded lazily, only after CloudX reports a load failure.
- The two are never loaded in parallel, so the fallback costs nothing when CloudX fills.
Show()prefers a ready CloudX ad over a ready AdMob one, and returnsfalsewhen neither is ready. For the interstitial the caller just carries on with the game; the demo says so and reloads. For the banner aShow()with nothing ready is remembered, and the ad appears as soon as either source loads;Hide()cancels that.- If CloudX initialization fails outright, the controllers skip the CloudX leg and serve AdMob directly, rather than waiting for load callbacks that a failed init never delivers.
- A failed load or show is retried with a capped backoff (2 s, 4 s, 8 s ... up to 60 s), reset by the next successful load. A fixed short retry would turn sustained no-fill into a tight request loop against the fallback network.
The status text names which SDK won, so you can see the pattern working:
Left: CloudX filled. Right: the same button after CloudX no-filled, showing Google's test creative.
Everything the flow needs lives in Assets/Scripts/FirstLook, and none of it calls into the General
screen:
| File | Role |
|---|---|
FirstLookInterstitialController.cs |
The whole interstitial flow, self-contained. |
FirstLookBannerController.cs |
The whole banner flow, self-contained, including the pass cycle. |
FirstLookSource.cs |
The CloudX / AdMob enum every event reports. |
FirstLookConfig.cs |
AdMob ad unit ids, the banner pass cooldown, and the fallback test switch below. |
FirstLookScreen.cs |
Initializes both SDKs, wires the controllers to the buttons. |
To integrate one format, copy two files: that format's controller and FirstLookSource.cs. Each
controller is one file you can read top to bottom - state, the entry points, then each SDK's
callbacks - with no base class to chase. The two controllers repeat about fifty lines of ad-unit and
dispose bookkeeping between them; that is deliberate, so neither file drags a shared base along into
your project.
To see the fallback path yourself, set ForceCloudXNoFill = true in FirstLookConfig.cs and rebuild.
It points CloudX at an unknown ad unit, so every CloudX load fails and AdMob serves instead.
The banner toggles Show/Hide and the button label names the SDK that filled (e.g.
Hide Banner (CloudX)). It sits at the top in both orientations.
A banner is not consumed the way a fullscreen ad is, so it needs one thing the interstitial does not.
One pass is one ad opportunity: CloudX is asked first, AdMob only if CloudX fails, and the winner goes
on screen. Putting an ad on screen spends the pass - CloudX inline ads report only load and click,
and a load into a view that is already visible renders straight away, so that is the one moment the
code can treat as "this fill has been used". The screen then schedules the next pass
FirstLookConfig.PassCooldownSeconds later (30 s by default), and that pass starts at CloudX again.
Without the cycle the first fill would latch: after one CloudX no-fill the AdMob fallback would own the placement until the scene was destroyed, and CloudX would never get another first look.
Three details worth copying as they are:
- Reloading is in place, not a recreate -
LoadBanneron the existing view, allowed because refresh was stopped for that ad unit - so a visible ad is replaced only once the new one has filled, and the slot never blanks. - The cycle only turns while an ad is on screen. Hiding cancels the pending pass, so a hidden slot never keeps requesting in the background, and showing it again puts the same ad back up and restarts the cooldown from that tap. The screen still preloads once before the first tap, so an ad is ready when the user asks for it.
- An ad the AdMob console refreshed on its own does not count as a pass. Only a fill the controller asked for spends one, so an AdMob unit that still has Automatic refresh enabled cannot keep postponing CloudX's next first look - which it otherwise would, on every refresh. The demo's Google test units do refresh, so this path is live even here.
Auto-refresh itself stays off on the CloudX side: the pass cycle owns reloading, so an SDK refresh
timer would compete with it and could swap the ad out from under the First Look source decision.
CloudX banner auto-refresh is opt-out - showing a banner starts it unless the ad unit was first passed
to StopBannerAutoRefresh - so the controller calls that before create and never calls
StartBannerAutoRefresh. (GeneralScreen restarts refresh on focus; First Look deliberately does not.)
Disable automatic refresh on your AdMob banner ad unit.
This is the one step the code cannot do for you. The Google Mobile Ads Unity plugin has no refresh API: a
BannerViewloads once, and whether it refreshes afterwards is decided solely by the ad unit's Automatic refresh setting in the AdMob console, in the settings of each banner ad unit. If that setting is on, AdMob swaps the creative on its own schedule, outside the pass cycle. Set it to Disabled on every AdMob unit you use as a First Look fallback.The demo's Google test units are configured by Google, not by this project, so treat them only as a way to see the fallback render; the setting above is about the units you replace them with.
The First Look flow needs the Google Mobile Ads Unity plugin, which this project pulls in as a
package (Packages/manifest.json) along with the External Dependency Manager it requires. Unity
resolves both on open, so no manual import step is needed.
If you copy the First Look folder into your own project, add the same plugin there; the CloudX SDK itself does not depend on it.
The demo ships with CloudX demo dashboard IDs so it runs without an account. To point it at your own CloudX app:
- Replace the app key and ad unit IDs in
Assets/Scripts/DemoConfig.cs. - Set the bundle identifier registered for that app in Unity under
Project Settings > Player > Identification (
ProjectSettings/ProjectSettings.asset).
For iOS device builds also set your own Signing Team ID under Project Settings > Player > Signing. It ships empty on purpose.
Bid requests are authorized per app key and bundle identifier, so both have to match your dashboard app or the SDK gets no fill.
The AdMob ad units in FirstLookConfig.cs are Google's official test units and stay valid as they
are; replace them with your own AdMob units when you take this into production, and set
Automatic refresh to Disabled on the banner one (see the First Look section for why).
The project is configured for the Simulator SDK. To build for a physical iOS device, switch Target SDK to Device under Project Settings > Player > Other Settings before building.





