Skip to content

Advertising

Advertising is how most games on Y8 earn. The SDK shows two kinds of break: interstitials, which you request at natural pauses in play, and rewarded ads, which the player chooses to watch in exchange for something. It can also show banners, which stay on screen during play in a space your game sets aside for them.


Pause in the callback, not before the call

This is the one thing to get right, because getting it wrong strands players in a paused game.

An ad break does not always show an ad. It may be skipped because none was available, or because the previous ad was too recent. When that happens the SDK does not fire the "ad started" and "ad finished" callbacks at all — there was no ad to start or finish.

So pause your game inside the before-ad callback and resume it inside the after-ad callback. If you instead pause before requesting the break, a skipped break leaves the game paused with nothing to un-pause it.

Tip

Mute your audio in the same place you pause, and restore it in the same place you resume.


Showing an interstitial

y8Sdk.showAd({
    type: "next",
    name: "level-complete",

    beforeAd: () => {
        pauseGame();
    },

    afterAd: () => {
        resumeGame();
    },

    adBreakDone: (info) => {
        console.log(info.breakStatus);
    },
}).catch((error) => {
    console.error(error);
});

Every field is optional. type defaults to "start" and name to "start-game".

name is a label for the break. On games whose ads run through AdSense for Platforms it is passed to Google with the break; Y8 does not report on it. Keep it stable.

JsResponse<AdBreakInfo> response =
    await Y8.Instance.ShowAdAsync(AdType.next, "level-complete");

if (response.IsSuccess)
{
    Debug.Log(response.Data.Status);
}

type defaults to AdType.start; name is optional. Y8 does not report on it.

Pause and resume by subscribing to the SDK's events rather than doing it around the call — they fire only when an ad actually appears, which is the behaviour described above:

private void OnEnable()
{
    Y8.Instance.OnAdPauseGame  += PauseGame;
    Y8.Instance.OnAdResumeGame += ResumeGame;
}

private void OnDisable()
{
    Y8.Instance.OnAdPauseGame  -= PauseGame;
    Y8.Instance.OnAdResumeGame -= ResumeGame;
}

private void PauseGame()  => Time.timeScale = 0f;
private void ResumeGame() => Time.timeScale = 1f;

Subscribe once, at startup — not per ad request.

Call showAds
    type: "next"
    name: "level-complete"

Calling showAds from an event sheet

The integration calls your PauseGame function when an ad is about to show and your ResumeGame function when the break ends. In the example project both only log a message — fill them in to pause and mute your game, and to resume it.

Pause and resume around the ad break

Y8.showAd(pauseGame, resumeGame);
Parameter Type Description
pauseGame Void->Void Called before the ad is displayed. Pause and mute here.
resumeGame Void->Void Called when the break ends, whether or not an ad was shown. Resume here.

pauseGame runs only when an ad is about to show. resumeGame runs at the end of every break, including one that was skipped, so it must be safe to call when the game was never paused.

The Haxe wrapper always requests the start placement; it has no way to choose another one.


Placements

The placement describes when the break happens. Pick the one that matches what the player is actually doing; the ad system uses it to decide what to serve.

Placement When to use
start The game has loaded, before play begins.
pause The player paused the game.
next Between levels, rounds or stages.
browse The player is in menus, not playing.
reward The player chose to watch an ad for a reward.

Never request preroll

preroll is a placement the Y8 platform runs itself, before your game's UI appears. Requesting it from the SDK is not supported.

The method is showAd, not adBreak

adBreak is the name Google's own ad API uses, and it is easy to reach for by mistake — but it does not exist on the Y8 SDK: y8Sdk.adBreak() throws a TypeError. An adBreak() helper copied from Google's documentation is worse, because it bypasses the SDK and on most Y8 games does nothing at all, with no ad and no error. If ads are not appearing, check the method name first.


Rewarded ads

A rewarded ad is player-initiated: they press a button offering something in exchange for watching. Grant the reward only when the ad was actually watched through to the end.

y8Sdk.showAd({
    type: "reward",
    name: "extra-life",

    beforeAd: () => pauseGame(),
    afterAd: () => resumeGame(),

    beforeReward: (showAdFn) => showAdFn(),

    adViewed: () => {
        grantExtraLife();
    },

    adDismissed: () => {
        // Watched only part of it — no reward.
    },

    adBreakDone: (info) => {
        console.log(info.breakStatus);
    },
}).catch((error) => {
    console.error(error);
});

beforeReward must call the function it is given

beforeReward runs when a rewarded ad is ready and receives a function that displays it. Nothing is shown unless you call that function.

It is the hook for asking "Watch an ad for an extra life?" — show your own prompt, then call showAdFn() if the player accepts. If you do not need to ask, pass it straight through as above.

It is not where you grant the reward. Grant in adViewed.

Callback When it runs
beforeReward(showAdFn) A rewarded ad is available. Call showAdFn() to play it.
adViewed The player watched it through. Grant the reward here.
adDismissed The player closed it early. Grant nothing.

beforeReward, adViewed and adDismissed are ignored for every placement other than reward.

JsResponse<AdBreakInfo> response =
    await Y8.Instance.ShowAdAsync(AdType.reward, "extra-life");

if (!response.IsSuccess)
{
    return;
}

switch (response.Data.Status)
{
    case AdBreakStatus.Viewed:
        GrantExtraLife();
        break;

    case AdBreakStatus.Dismissed:
        // Closed early — grant nothing.
        break;

    case AdBreakStatus.NoFill:
        // Nothing available right now; tell the player to try later.
        break;

    case AdBreakStatus.Error:
        break;
}

There is no separate "offer the ad" hook — show your own prompt before calling ShowAdAsync, and call it only if the player accepts.

RewardAd → On clicked
         → Call showRewardAds
            functionName: "addCoinsReward"

Requesting a rewarded ad Rewarded ad configuration

The named function runs only when the ad was watched through, so grant the reward there and nowhere else:

On function addCoinsReward
    → Grant the player their reward

Granting the reward

Two more functions in the y8Api event sheet report the other outcomes:

Function When it runs
rewardAdDismissed The player closed the ad early. Grant nothing.
NoRewardAds The break ended without showing an ad. A good place to tell the player to try again later.
Y8.showRewardAd(
    pauseGame,
    resumeGame,
    function():Void {
        coins += 100;
        trace("Reward granted");
    },
    function():Void {
        trace("No rewarded ad available");
    }
);
Parameter Type When it runs
pauseGame Void->Void Before the ad is displayed.
resumeGame Void->Void When the break ends, whether or not an ad was shown.
onReward Void->Void The ad was watched through. Grant the reward here.
onUnavailable Void->Void No rewarded ad was available (noAdPreloaded, frequencyCapped or other), or the request failed. Not called when the break ends as timeout, notReady, error or ignored — only resumeGame runs then.

onReward does not run when the player closes the ad early, so granting there is safe.


Knowing what happened

The ad-break-done callback runs for every break the SDK accepts, whether or not an ad was shown, and describes the outcome. It does not run when the call itself fails (see the .catch() above), or when an ad blocker stops the ad system from loading at all — then no callback runs, which is one more reason to resume in the after-ad callback rather than only here.

adBreakDone: (info) => {
    // info.breakStatus is always set — what actually happened.
    //
    // On games whose ads run through AdSense for Platforms, info also
    // carries breakType ("next"), breakName ("level-complete") and
    // breakFormat ("interstitial" or "reward").
    //
    // On every other game, and on a frequency-capped break, info is just:
    // { breakStatus: "viewed" }
}
breakStatus Meaning
viewed Shown and watched.
dismissed Shown, closed early.
noAdPreloaded Nothing available to show.
frequencyCapped Skipped — the previous ad was too recent.
notReady The ad system had not finished starting up.
timeout The request took too long.
error The request failed.
ignored A rewarded ad was offered, but showAdFn was not called before the next break was requested.
other Anything else.

Only viewed and dismissed mean an ad appeared. Treat every other value the same way — carry on with the game.

JsResponse<AdBreakInfo> response = await Y8.Instance.ShowAdAsync(AdType.next);
AdBreakStatus status = response.Data.Status;
AdBreakStatus breakStatus Meaning
Viewed viewed Shown and watched.
Dismissed dismissed Shown, closed early.
NoFill noAdPreloaded, frequencyCapped, other No ad appeared. Also returned when no Game ID is set, or while another ad break is still in progress.
Error timeout, notReady, ignored, error, anything else No ad appeared; the break failed or timed out.

Only Viewed and Dismissed mean an ad was shown. NoFill and Error mean the same thing for your game — no ad was shown, carry on.

The integration reports the outcome through the functions described above: the reward function runs only on a completed rewarded ad, rewardAdDismissed when it was closed early, NoRewardAds when none was shown, and ResumeGame once the break is over either way.

The wrapper reports the outcome through the callbacks described above: onReward for a completed rewarded ad, onUnavailable when none was available or the request failed, and resumeGame once the break is over either way — including breaks that end as timeout, notReady, error or ignored, where neither of the other two runs.


Frequency capping

Interstitials are paced. By default Y8 allows one roughly every 180 seconds, configurable per game. Rewarded ads are never capped, though watching one does restart the interval for interstitials.

Call the SDK at every natural break anyway. You do not need to do the counting — when a request lands inside the interval, the SDK skips it and reports the outcome as capped without showing anything.

A capped break behaves exactly like one where no ad was available: the before-ad and after-ad callbacks do not run, so a game that pauses inside them is never paused in the first place. Handle it the same way you handle an empty break — which, if you followed the advice at the top of this page, means doing nothing at all.


Games served from your own site

Some builds don't contain the game itself: the uploaded index.html loads it in an iframe from the developer's own site, often so a multiplayer client stays in step with its servers. The SDK then runs on your domain rather than on Y8's.

Interstitial and rewarded ads still work, from SDK version 2.14. The SDK notices it is running outside Y8 and asks the Y8 game page to show each break instead. Your code does not change: the same calls, the same callbacks, in the same order. The ad covers your game's area, as it does for a game whose files are on Y8. Y8's own fullscreen button keeps the player in fullscreen through the ad; if your game makes its own frame fullscreen instead, the player is taken out of that fullscreen for the ad, since it would hide the ad.

Banners need the game files in the build

Banners are drawn inside your game, so in a game served from your own site they are requested from your domain, where Y8 is not authorised to sell ads. They will not earn. If you use banners, upload the game itself rather than a page that loads it from your site.


Banners

A banner is a display ad that stays on screen while the player plays: in a sidebar, a strip under the board, a lobby panel. It is not a break. Nothing pauses, and the ad appears inside an element your game reserves for it.

In-game banner ads require Y8 approval for each game

We generally consider them for games with long, continuous sessions and few natural breaks for video ads, such as some io and multiplayer games. Approved banners must be served through the Y8 SDK, remain clearly separate from game controls, and work safely on every supported screen size. Y8 may limit, disable, or withdraw banner approval if placement harms gameplay, causes accidental clicks, or affects ad quality. Adding banner code does not guarantee that banners will be shown.

While your game is in draft or in review, banners show test ads whether it is approved or not, so you can build and check your placement first. Once the game is released, banners appear only if Y8 has approved them; otherwise requestBanner rejects with bannersUnavailable. The SDK also logs a warning in the browser console until the game is approved. Contact Y8 support to have banners approved before you release the game.

Size Name
728×90 Leaderboard
300×250 Medium
320×50 Mobile
468×60 Main
320×100 Large Mobile

The element you reserve must be at least the size of the banner and fully on screen when you ask for one: not hidden, and not positioned or scrolled out of view. Put nothing else inside it. The ad is placed there and centred horizontally.

Requires SDK 2.13.0 or later

<div id="banner-bottom" style="width: 728px; height: 90px;"></div>
y8Sdk.requestBanner({ id: "banner-bottom", width: 728, height: 90 })
    .then(() => {
        // A banner is showing.
    })
    .catch((error) => {
        console.log(error.code);
    });

// Remove it when you need the space for something else.
y8Sdk.clearBanner("banner-bottom");

// Or remove every banner at once, for example when a match starts.
y8Sdk.clearAllBanners();

requestBanner resolves once an ad is showing. When it cannot show one it rejects with an error whose code says why:

code Meaning
bannersUnavailable Banners are not available or not approved for this game, or init() was called without an ad configuration.
missingId No id was given, or no element has that id.
invalidSize Not one of the sizes above, or the element is smaller than the banner.
notVisible The element is hidden or not fully on screen, or the tab is in the background.
videoAdPlaying An interstitial or rewarded ad is on screen.
bannerCooldown A banner of this size was requested too recently.
maxRefreshReached This size has used up its banners for the session.
unfilled No ad was available this time. Not reported on every game (see the tip below).
other Anything else, including ads failing to start up. message has the details.

A request declined before it is sent — every code except unfilled and other — leaves the banner already in that element where it is. Once a new banner is requested, it replaces the old one even if it then comes back unfilled.

Banner ads are not available in the Unity integration yet.

Banner ads are not available in the Construct 3 integration yet.

Banner ads are not available in the Haxe integration yet.

How often banners change

Banners are paced per size. By default each size allows one new banner every 180 seconds, configurable per game and never less than 30 seconds, and a limited number per session. Every banner of that size counts, whether you asked for it or it refreshed by itself, and removing a banner does not reset the count.

Depending on how the game is set up, a banner either refreshes by itself while it stays on screen, or changes only when you request a new one. Write the game so that either works: request a new banner at natural breaks, such as between matches or back in the lobby. A request that comes too soon is simply declined, and the banner already showing stays where it is.

No banner is requested or refreshed while an interstitial or rewarded ad is on screen, and banners never count towards the interstitial pacing described above.

Design for an empty space

Sometimes no banner is available. Keep the reserved space in your layout either way, so nothing jumps when an ad does or does not appear.

If your game earns through your own AdSense account (AdSense for Platforms), its banners come from AdSense, which can't tell the SDK when an ad stays empty. On those games requestBanner resolves once the ad has loaded, and unfilled never comes, so an empty banner space has to look right without the game being told.


Testing

While your game is in draft or in review, interstitials and banners are served Y8's own house ads automatically — or Google's test ads, on games whose ads run through AdSense for Platforms. There is nothing to switch on, and no configuration to remember to remove — real ads begin serving once the game is approved and released. Banners need one more step: after release they appear only once Y8 has approved banners for the game (see Banners).

In a draft or in-review build, a break that shows no ad also opens a panel over your game saying so, and why — no ad available, frequency capped, and so on. Close it and carry on. It is there so an empty break is visible while you test; live games never show it.

Before submitting, check that:

  • Gameplay pauses and audio mutes when an ad appears.
  • Gameplay resumes afterwards.
  • A break that shows no ad leaves the game running normally. Breaks are capped after the first ad that actually shows, so requesting two breaks in quick succession is an easy way to see this path. A first break that showed nothing does not start the cap.
  • Rewards are granted only after an ad is watched through, never when it is closed early.
  • If you show banners: each one appears inside its reserved space, and the layout still looks right when that space stays empty.