Mintegral playable validator
Drop in the ZIP you would submit to Mintegral and run it inside a mock container, watching the handshake both ways. Does your creative announce itself with gameReady and then wait — or does it start playing underneath their loading screen, to nobody? Is gameStart a global their reviewer can actually find, or assigned onto window where the scan will miss it? Is the archive named the way they require? Every call lands on a timeline as it happens.
Drop a playable to run it
The .zip you would submit to Mintegral, or a single .html build. It runs inside a mock Mintegral container in a sandboxed frame on this device — nothing is uploaded.
How Mintegral's playable API works
A protocol that runs in both directions
Most ad frameworks are one-way: the creative announces things and the container listens. Mintegral's is the exception, and every difficulty with it follows from that one fact. Four functions belong to them and your creative calls them. Two functions belong to your creative and Mintegral calls them. Getting the direction of any one of the six backwards produces a playable that looks finished, runs perfectly when you open it yourself, and fails review — because the half you got wrong is the half that only happens inside their container.
The four your creative calls
gameReady() says every resource has loaded and the creative is holding. gameEnd() says the round finished, won or lost. gameRetry() says the player chose to go again. install() is the click-through, and it is the only route to the store you are permitted — a creative that navigates on its own is doing something their container blocks. These four are provided by Mintegral and already exist in the window by the time your code runs.
The two your creative provides
gameStart and gameClose are yours to define. Mintegral calls them. This is the sentence worth reading twice, because it is the one the exporter behind this tool got backwards on its first attempt, on the strength of an open-source SDK that wraps both directions under its own names. Calling gameStart does nothing at all — you are calling into empty space. Defining it is what makes it work, and their documentation is plain about what belongs inside: start your timers and your music there.
Your ad does not start when it is ready
It becomes ready, says so, and waits. Mintegral holds its own loading screen over your creative until gameReady arrives, then clears that screen and calls gameStart. A creative that begins playing the moment it has loaded runs its opening seconds underneath their UI — the animation nobody saw, the tutorial nobody read, the hook that was the entire point of the ad. It is a wasted impression, and their review checks for it. This is the single most common way a technically correct playable produces a bad ad.
But waiting does not mean showing nothing
The distinction that catches people going the other way. Holding until gameStart means holding the motion — the timeline, the audio, the animation loop, the countdown. It does not mean rendering a black rectangle. Draw your opening scene while you wait, so their screen lifts onto a picture rather than onto nothing, and a reviewer who taps immediately finds something to tap. A creative that gates its rendering as well as its playback has the opposite problem from the one this section warns about, and it looks just as broken: their loading screen clears and the ad appears to still be loading.
They read your file as well as running it
This is what makes Mintegral stricter than the rest, and it is not obvious from anything they publish up front. Their review reads the source for the two callbacks you define, and watches the other four fire while a person drives your playable by hand. Both halves have to pass. The only place their guidance says so directly is a note about Cocos Creator builds, whose start and end callbacks are — in their words — not recognised as static global methods, with the advice to add them to the generated HTML by hand. That note is the whole rule, stated once, about a single engine.
Which means where you define them decides whether they count
A property assigned onto window at runtime is not a static global method any scanner can find. Neither is a function declared inside a closure, and neither is one buried at the end of a megabyte of bundled runtime. All three work when called. None of them survive the scan. Declare both as plain top-level functions in the head, ahead of everything else — and that placement solves a second problem at the same time, described below.
They can call gameStart before your creative has loaded
The reason gameStart exists is that Mintegral starts the ad, and nothing makes them wait for you. A call landing on undefined throws inside their harness, and the difference that makes is not a late start — it is a container that never gets past its own loading screen. Declaring the function early is what prevents it. The pattern that works is a top-level declaration in the head that forwards to your real handler, remembering the call if the handler is not installed yet, so a start that arrives too early is honoured the moment you are ready for it rather than lost.
The six calls, and which way each one travels
Four belong to Mintegral and your creative calls them. Two belong to your creative and Mintegral calls them. Mixing up any one of the six produces a playable that works when you open it and fails review.
gameReady()Your creative calls thisonce, when every resource has loadedThe announcement that clears their loading screen. Nothing else lifts it. A creative that never calls this is never shown, however perfectly it loaded — their review panel reports it as Game Ready undetected, which is a confusing thing to read about an ad you have just watched work on your own machine. If your runtime is large, make sure the call cannot be skipped when loading takes longer than you expected.
gameStartMintegral calls thiswhen their loading screen clearsYour cue to begin: release the timeline, start the music, run the entry animations. Declare it as a top-level function in the head, not as a property assigned onto window, and declare it early enough that a call arriving before your creative has finished loading has something to land on.
install()Your creative calls thison every call-to-actionThe only permitted route to the store. Write it out literally rather than assembling the name from a string or routing it through a helper that calls things by name — their review reads the source, and a call built at runtime is a call their scanner cannot see. A creative that uses window.open or a plain anchor instead will silently do nothing inside their container.
gameEnd()Your creative calls thiswhen the round finishesWon or lost, both. Their reviewer detects each call as it happens while driving the playable by hand, so this has to fire on the real path through your ad — a call that exists only in the source reads as undetected, which is the same result as not writing it.
gameRetry()Your creative calls thisif the player can go againConditional, and the only one of the six that is. Their wording is that if the playable is designed to play again you should add it, and if not you needn't — so a single-round playable that omits this is correct rather than incomplete.
gameCloseMintegral calls thiswhen the ad is dismissedYour cue to stop. Their documented example of what belongs here is stopping the music, which is a good indication of what they are checking for — an ad whose soundtrack carries on after it has gone. Release timers and audio here. Declared the same way as gameStart, at the top level and early.
Seven ways a Mintegral playable fails review
All but the first run correctly in a browser opened directly, which is what makes them expensive to find any other way.
Every runtime item on their panel says Undetected
Including gameReady, for a creative that definitely called it. This is the signature of the source scan failing rather than the run failing. The usual cause is gameStart and gameClose being assigned onto window from inside a closure, at the end of a large bundle, after loading finished — all three of which are invisible to a scanner reading the file for top-level function declarations. The fix is to declare both in the head as plain functions that forward to your real handlers.
Their loading screen never lifts, over a black frame
gameReady was never called, and almost always because something threw before the line that would have called it. Their screen sits above your creative, so whatever broke underneath is invisible — including any error message your own code might have drawn. Worth building in a last-resort timer that announces anyway after ten or fifteen seconds: a creative that is genuinely broken is better seen broken than hidden behind a screen that never moves.
Their panel says Game End detected, Game Ready never observed
The scan found your gameEnd in the source and the run never saw gameReady fire. The version of this that is hardest to find is a creative that checked for their functions once, at the top of its own script, found nothing, and concluded there was no container. Their functions are injected into your window and nothing promises that has happened by the time an inline script at the end of the body runs. Treat absence as not yet rather than not there, and keep looking for a second or two before deciding you are running outside their container.
The ad plays but the viewer sees it half finished
Playback started on load instead of waiting for gameStart. The opening ran underneath their loading screen and the viewer arrived partway through. This is invisible in ordinary testing because the ad looks completely normal once the screen clears. The container above draws that screen for real so you can watch your creative behind it, and reports any sound it makes there — but whether a timeline is advancing is internal to the creative and no container can see it from outside, so this is the one check on this page you have to make yourself. Look at where your code starts its timers and animations: if that is a load handler rather than gameStart, you have this problem.
The ad renders one frame and then does nothing
The opposite mistake: waiting for gameStart forever. A creative that gates everything behind their call and has no fallback is at the mercy of a container that takes the announcement and goes quiet. A ceiling of a few seconds, after which the ad begins anyway, is the right shape here — a slow container starting a few seconds early is a worse ad, but an ad that never begins is not an ad. The checkbox on the tool above simulates this.
Rejected at upload, before anybody reviewed the creative
A packaging failure rather than a runtime one, and the fastest of these to fix. Mintegral takes a ZIP and nothing else, shaped so the archive, the folder inside it and the entry document share one name — my_ad.zip containing my_ad/my_ad.html. An entry at the archive's root is the usual mistake, because that is where every other network here puts it. The 5 MB cap is measured on the archive as uploaded, so artwork is what usually pushes a build over.
Tapping the call-to-action does nothing
The exit went through window.open, a plain link, or another network's SDK. Mintegral is explicit that a creative must never navigate on its own, so anything other than install() is swallowed. The frequent version of this is an MRAID build submitted to Mintegral — the two frameworks are unrelated, and a creative exiting through mraid.open will not click through here whatever else it does.
Mintegral is one of thirteen networks this editor exports to. If your creative targets Unity, AppLovin, ironSource or Chartboost, use the MRAID validator instead — and for size limits and packaging across all of them, read the network specs.
Open the spec checkerCommon questions
- Is my creative uploaded to a server?
- No. The file is read in your browser and rendered into a sandboxed frame on this device. Nothing is transmitted and nothing is stored — you can confirm it by watching your browser's network tab during a run, or by disconnecting after the page loads and running one anyway.
- What is the difference between gameStart and gameReady?
- Direction, and it is the single most important thing about this framework. gameReady is a function Mintegral provides and your creative calls, to say it has finished loading. gameStart is a function your creative provides and Mintegral calls, to say the loading screen has cleared and the ad should begin. They are not two halves of one thing and they travel opposite ways. A creative that calls gameStart is calling into empty space; a creative that waits to be told gameReady will wait for ever.
- Why does this tool check my source as well as running my ad?
- Because Mintegral's review does. Their reviewer watches the four calls fire while driving your playable by hand, and separately reads your file for the two callbacks you define. A creative can behave perfectly and still fail the read — that is the specific failure that produced this page. A tool that only ran your ad would give you a clean pass on a build that is about to be rejected.
- What can this tool not check?
- Whether your timeline is actually advancing before gameStart. It sounds like the easiest thing here to detect and it is the one genuinely impossible one: a container sees a renderer's animation loop running whether the ad is playing or paused, because every canvas engine schedules frames continuously from the moment it starts. A paused ad and a running one look identical from outside the creative. Sound is the exception — nothing but a started ad makes noise — so that is reported, and the rest is left to you rather than guessed at. Everything else on this page is checked directly: the six calls, the two source declarations, the archive shape and the size.
- How close is this to Mintegral's real review?
- Close enough to expose the mistakes that matter, and deliberately not presented as more than that. It implements the six-call protocol, holds a loading screen the way theirs does, and reads your source the way a scanner looking for top-level declarations would. What it cannot reproduce is their exact timing, their panel's wording, or a human reviewer's judgement about whether your ad is any good. Treat a pass here as a good sign and their own submission process as the authority.
- My creative works when I open it directly. Why does it fail here?
- That is the normal case, and it is what the tool is for. Opened directly there is no container, so a defensively written creative takes its fallback path — no loading screen to wait behind, no gameStart to miss, and window.open works, so the click-through appears fine. Every one of those is a different branch from the one that runs inside their container. The failures here are real; the success you saw was a different code path.
- Do I need gameRetry?
- Only if your playable can be played again. Mintegral's own wording makes it conditional — if the playable is designed to play again you add it, and if not you needn't. A single-round playable that omits it is correct, and this tool does not report its absence as a fault.
- Should I upload the ZIP or the HTML?
- The ZIP, because that is what Mintegral takes — their spec accepts no other form. Upload the archive exactly as you would submit it and the validator opens it, finds the entry document and runs that, while also checking the two things only an archive can be wrong about: whether it follows the name.zip > name/ > name.html rule, and whether it is under the 5 MB cap. A loose HTML file is accepted too, since that is what you have after unzipping one to look inside, but the packaging checks are skipped and reported as untested.
- Why does the archive, the folder and the file need the same name?
- Because Mintegral says so, and it is enforced at upload rather than at review — an archive shaped any other way is refused before a human sees the creative. So my_ad.zip must contain a folder called my_ad, which must contain my_ad.html. This is unlike every other network here, whose entry document sits at the archive's root. Letters, digits and underscores only in the name.
- Will the artwork show up if I upload a ZIP?
- For a Mintegral export from this editor, yes — the packager inlines every asset as a data URI, so the entry document carries its own artwork and stands alone inside the archive. An archive built elsewhere may reference images as separate files, which a sandboxed frame cannot resolve; the validator detects that and says so on screen, because a blank canvas otherwise reads as a fault in the ad. Even then the handshake, the calls and the source checks are all still accurate.
- Which other networks work this way?
- None of the ones this editor exports to, which is why Mintegral has a page of its own. Unity, AppLovin, ironSource and Chartboost use MRAID. Meta, Moloco and InMobi share a single FbPlayableAd.onCTAClick() call — the opposite extreme from this one, with no handshake at all — and have their own validator. TikTok and Pangle share another format, Vungle and Liftoff Monetize post messages to the parent frame under a format Liftoff call Adaptive Creative, and Google asks for one exit function and a meta tag. Mintegral is the only one that calls back into your creative, and a build made for any of the others will fail here on the exit check alone.
Your next playable is one afternoon away.
Open the editor, pick a format and start placing objects. Nothing to install, and nothing to pay.
