Advanced: Faster Ad Loading (Preload)
By default, initializeAndOpenPlayer() does all of its work after the click: it runs the ad auction, requests the video, and buffers the creative, then reveals the player. On slower networks that can take a few seconds, and the user is staring at a spinner the whole time.
The preloadAd() API splits that work in two. You do the slow part — the auction and video request — ahead of the click, on a high-intent signal. The click itself only reveals an ad that is already loaded, which brings click-to-reveal down from ~1.5–3.5s to roughly 100–300ms. This is the same pattern used by Poki, CrazyGames, and Google H5 Games Ads.
How it works
<script type="text/javascript">
const options = {
apiKey: "xxxx-xxxx-xxxx-xxxx", // Replace with your actual API key
injectionElementId: "some-id", // The ID of the div from Step 2
adStatusCallbackFn: (status) => {
if (status.type === "complete") {
// Grant the reward here (see Step 4)
}
},
adErrorCallbackFn: (error) => {
console.log("Error: ", error.getError().data);
},
};
let adHandle = null;
// 1. Preload early — on a high-intent signal, NOT on page load.
async function loadAd() {
try {
adHandle = await preloadAd(options); // runs the auction + video request now
} catch (e) {
adHandle = null; // no-fill or network error — fall back on click
}
}
// 2. On click, just reveal the already-loaded ad.
document.getElementById("watch-ad").addEventListener("click", async () => {
if (adHandle) {
await adHandle.show(); // ~100–300ms
adHandle = null; // each handle is single-use
loadAd(); // preload the next one for the next click
} else {
initializeAndOpenPlayer(options); // fallback: the standard (slower) path
}
});
</script>
preloadAd(options) takes the same options object as initializeAndOpenPlayer() and returns a handle { show }. Call show() from inside your click handler to reveal the ad.
Three rules for using it well
-
Preload on a high-intent signal, not on page load. Good triggers: a reward modal mounting, a level-complete screen, an "out of coins" overlay, a "watch ad to double your reward" prompt appearing. Preloading on page load wastes ad requests on visitors who never click.
-
Always keep an on-click fallback. Roughly 10–30% of preloads will no-fill or fail. If the handle is missing or the promise rejected, fall through to
initializeAndOpenPlayer()for one best-effort try — never callshow()on a failed preload. -
Re-preload after each show. Each handle is single-use. Right after
show()resolves (or in your reward callback), callpreloadAd()again to have the next ad ready for the next click.
Pattern: an always-visible "Watch Ad" button
If your "Watch Ad" button is on screen for most of the session, there's no single intent moment — the button itself is the intent. Keep an ad loaded while the button is visible:
let adHandle = null;
let lastRefresh = 0;
async function refreshAd() {
try {
adHandle = await preloadAd(options);
lastRefresh = Date.now();
} catch (e) {
adHandle = null; // fall back to the on-click path
}
}
refreshAd(); // when the button first renders
setInterval(refreshAd, 4 * 60 * 1000); // keep it fresh (bids expire ~5 min)
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible" && Date.now() - lastRefresh > 60000) {
refreshAd(); // refresh on return, but not while backgrounded
}
});
watchBtn.addEventListener("click", () => {
if (adHandle) { adHandle.show(); adHandle = null; refreshAd(); }
else initializeAndOpenPlayer(options); // fallback
});
Things to keep in mind
- Bids expire (~5 minutes). If the gap between
preloadAd()andshow()is longer than the bid's lifetime, the video URL can fail. Refresh on a timer (as above) or re-callpreloadAd()on the next intent signal. - Preload uses an ad request. Each
preloadAd()call runs a real auction. Triggering it on genuine intent (rather than on every page load) keeps that efficient. For low-traffic games, a lighter option is to preload onhover/touchstartof the button — it fires ~50–200ms before the click for a partial speed-up without the polling. - It can fail silently. In Incognito or with third-party cookies blocked, the auction may fail without throwing. The on-click fallback (rule 2) is what keeps the experience working in those cases.
- Don't break the click gesture.
show()must be called from inside your click/tap handler (as in the examples). The preload does the network work in the background; the reveal stays bound to the user's tap, which keeps it working on iOS/Safari.
When you don't need this
If your ad is triggered by a deliberate, one-off action where a short wait is acceptable (e.g. an end-of-run "continue?" screen), the standard initializeAndOpenPlayer() from Step 3 is simpler and perfectly fine. Reach for preloadAd() when the speed of the reveal matters — frequent rewarded prompts, fast-paced loops, or an always-visible watch button.