What window.gameEnd() is

Mintegral's playable spec defines a click-through API — window.install(), with mraid.open(url) as a fallback — and, separately, a gameEndApi: window.gameEnd(). That second function is confirmed in Mintegral's own integration requirements: the creative is expected to call it once, at the point where the playable's interactive session is actually finished (typically when the end card or final state appears), independent of whether the user has clicked through yet.

Why Mintegral specifically cares about this, and a network like Google or Meta doesn't ask for an equivalent call, isn't spelled out in the documentation we have — that part is inference, not confirmed spec. The reasonable read is that Mintegral's SDK wants a distinct signal for "the interactive portion concluded" separate from "the user clicked," likely to feed completion-rate or engagement analytics on their side rather than just conversion tracking. Mintegral's own review process treats it as load-bearing either way: their QA explicitly tests that both the game-end callback and the app-store click callback fire, as separate checks, on every submission.

What happens if it's missing

The click-through still works. A tester or reviewer clicking the CTA sees the install/app-store flow resolve exactly as expected, which is exactly why this gap survives casual QA — nothing visibly breaks in a normal play-through. What's missing is the signal Mintegral's SDK uses to register that the playable's engagement session completed. Because Mintegral's review explicitly checks for that callback firing, a build that's functionally fine can still get flagged or rejected on a technicality that has nothing to do with how it plays.

Common mistakes

  • Never calling it at all. The most common gap — the CTA is wired correctly, and window.gameEnd() is simply never invoked anywhere in the build.
  • Calling it too early. Firing gameEnd() as soon as the playable loads, or at some fixed timer, rather than when the actual end state is reached, defeats the point of the signal — it's supposed to mark real completion, not "the file finished loading."
  • Calling it only on one branch. If the playable has multiple possible end states (a "replay" loop versus a final end card, for instance) and gameEnd() only fires on one of them, a user who takes the other path never triggers it. Since review needs it to fire reliably, a conditional call that some sessions never reach is functionally the same as not calling it at all.
  • Calling it multiple times. Less common, but wiring gameEnd() into a loop or into something like a resize or visibility handler can fire it repeatedly, which is unnecessary and can complicate whatever Mintegral does with the signal on their end.

How PlayableKit wires this — and what to check if hand-editing

When PlayableKit packages a build for Mintegral, it injects an adapter script into the exported HTML that exposes a single bridge function on window.playableAdNetwork.gameEnd(). That bridge, when invoked, calls window.gameEnd() for the Mintegral target (and separately calls the Unity/Luna lifecycle hook, Luna.Unity.LifeCycle.GameEnded(), if the export exposes one). The intent is that the underlying Unity/Luna build's own end-of-session logic — the same point where it would normally show an end card — is what triggers this bridge, so the callback fires at the playable's actual conclusion rather than on a fixed timer PlayableKit invents on its own.

If you're hand-editing a Mintegral package instead of using PlayableKit's automated output, the things worth checking are: window.gameEnd() is defined and reachable at all; it's called from the real end-state code path, not from a load event or a timer; every branch that counts as "the playable ended" reaches that call, not just the happy path; and it only fires once per session. PlayableKit's Mintegral checks in its validator look for exactly these signals — a CTA call, a game-ready call, a game-start call, and a game-end call all present in the HTML — which is a reasonable manual checklist even without running the tool.

Worth knowing: the gameEnd() gap is separate from — and easy to confuse with — Mintegral's other distinctive requirement, matching the archive name, top-level folder, and HTML filename. See window.install() vs mraid.open() for Mintegral for the click-through side of the same integration.

Before submitting a Mintegral build — hand-packaged or not — run it through PlayableKit's free playable ad validator, which checks for the CTA call, the game-ready/start signals, and the gameEnd() callback as part of its Mintegral-specific report.