HTML5 game publishing

Design for Unavailable Ads: Never Block the Player

Why unavailable is a normal answer, how every ad call needs two exits that both continue the game, place-by-place behaviour and the failure paths to test.

PlayKovo Team3 min read
Games currently available on PlayKovo. Open a title to see its current listing.

Most ad bugs are not bugs in the ad. They are bugs in what the game does around it: a button that stays disabled, a level that never loads because the callback never came, a player who gets charged for a continue they never received. The SDK guidelines include a short rule that prevents most of these: support unavailable ads without blocking a level, menu, continue action or save state. This post turns that rule into a design.

The rule in the guidelines

The SDK guidelines checklist has this item: "Support unavailable ads without blocking a level, menu, continue action, or save state." The mobile bridge documentation repeats it in code: after an interstitial, both outcomes call startNextLevel(), with the comment "Never block gameplay on an ad." And the web reference says to handle onError the same way you handle onClose.

Why would an ad be unavailable? The reference gives some reasons. PlayKovo applies a cooldown per game and answers unavailable if you ask too often. A browser, a local run or a game not enabled for mobile also returns unavailable. And the server decides actual availability for every placement. In short, "unavailable" is a normal answer, not an exception.

Every ad request has two exits

Think of each ad call as a fork:

  • Shown or completed: the player saw it, and the game continues (and for a rewarded ad, grants the reward in onReward).
  • Not shown: the game continues too, without a reward.

Both exits must lead to a working game. A quick test is to write the function that continues the game first, and pass it as both onClose and onError:

window.PlayKovoSDK.showInterstitial({
  placement: "level_complete",
  onClose: loadNextLevel,
  onError: loadNextLevel,
});

Place by place

WhereIf the ad is unavailable
Level completeShow results and the next-level button as usual
Game over / retryEnable retry. Do not hold the button until an ad finishes
Pause menuShow the menu immediately
Continue after dying (rewarded)Disable or hide the button; do not grant the continue; offer the normal restart
Bonus reward (rewarded)Hide the offer or say it is not available right now
Save pointSave first; never wait for an ad to save

The rewarded case needs more care

A rewarded ad is optional by design: the reference calls it an "optional reward flow". If the player cannot watch an ad, they should still be able to play on. That means the reward must never be the only way past a point. Treat rewards as a convenience (extra life, bonus coins), not a gate.

The reference shows a button pattern worth copying. Check capabilities when the screen renders, disable the button while a request is open, and re-enable it from onError:

continueButton.disabled = !window.PlayKovoSDK.getCapabilities().rewarded;
continueButton.addEventListener("click", async () => {
  continueButton.disabled = true;
  await window.PlayKovoSDK.showRewarded({
    placement: "continue_run",
    onReward: () => { playerHasContinue = true; },
    onClose: () => resumeRun(),
    onError: () => { continueButton.disabled = false; },
  });
});

Common ways a game blocks on an ad

  • Waiting for a callback that never arrives. If the only way to continue is onClose, and you do not handle onError, one failure freezes the game.
  • A modal "Loading ad..." with no way out. If you show your own message, make sure it ends.
  • An ad before saving. A crash during the ad would lose progress. Save first.
  • A disabled button without explanation. The player thinks the game is broken.
  • A required rewarded ad. If the level can only be passed after watching one, a player with no ad is stuck.

Test every failure

  1. Run the game locally. Without the live platform the SDK is in local preview, which is not an ad decision, so ads may be unavailable; play a whole session and make sure nothing hangs.
  2. Call an interstitial twice in a row to trigger the cooldown.
  3. Hit each placement with the network off.
  4. Close an ad early and check that no reward is given.

More detail on local runs is in testing the SDK on localhost. If a reviewer finds a path that blocks play, it counts against you; our post on ad behavior that gets a game rejected lists related problems.

We use optional cookies for site analytics and site advertising. You can change your choice later. Privacy policy.