MRAID validator
Run a playable inside a mock MRAID 3.0 container and watch what it does. Does it wait for the container before starting? Does it handle being hidden? Does the call-to-action reach mraid.open, or quietly do nothing? Every container event and every MRAID call lands on a timeline as it happens.
Drop a playable to run it
A single .html build. It runs inside a mock MRAID 3.0 container in a sandboxed frame on this device — nothing is uploaded.
What MRAID is, and why a playable has to care
A common language between an ad and the app showing it
MRAID — Mobile Rich Media Ad Interface Definitions — is a small JavaScript interface an ad network injects around your creative. It is how an ad asks the questions it cannot answer alone: am I on screen yet, how much room do I have, has the user turned the sound off, and where do I send someone who taps. Without it, a creative sitting inside somebody else's app is blind to all of that.
Your creative never ships with it
This is the detail that confuses people first. You do not bundle mraid.js — the network injects its own implementation at serve time, and a copy in your upload is at best ignored and at worst grounds for rejection. Your creative assumes the object will be there and starts by asking whether it is ready. That assumption is exactly what a validator has to fake in order to test anything.
The container has states, and the order matters
A container starts in loading, moves to default once the ad can be shown, and reaches hidden when it goes away. Nothing about your creative is guaranteed until that first transition. A creative that calls an MRAID method during loading is calling into an object the container has not finished building, which is why the spec asks you to wait for a ready event — or to check the state yourself in case ready fired before your code was parsed.
Ready is not the same as visible
The mistake this tool was built to catch. A container being ready means the interface works; it says nothing about whether a human can see the ad. Networks commonly prepare a creative in the background and reveal it later, so an ad that starts playing at ready runs its opening seconds into an empty room. The viewableChange event is the one that says a person is actually looking, and Unity states outright that playback must wait for it.
The events this container fires
In the order they arrive, with the timings the mock container uses. A real network's delays differ; the sequence does not.
readyjust after loadThe interface is usable. Everything your creative does with MRAID should begin at or after this point. If your code loads late and misses it, mraid.getState() returning anything other than loading tells you the same thing. This container waits for the page's load event before firing, so a creative carrying megabytes of inlined artwork gets the same sequence as a small one.
stateChangewith ready, and on hideCarries the container's new state — loading, default or hidden. Most creatives ignore it, which is usually fine; the ones that should not are creatives holding a timer or an animation that ought to stop when the ad is put away.
viewableChange0.4s after readyTrue when the ad is actually on screen, false when it is not. The single most important event for a playable, because it is the difference between starting the experience for a viewer and starting it for nobody.
exposureChangewith viewableChangeThe MRAID 3.0 refinement of viewability — a percentage and the visible rectangle rather than a yes or no. Useful when part of the ad can be obscured by the host app's own interface. Safe to ignore if you already handle viewableChange.
sizeChangeon rotationThe ad's new dimensions after the device turns. A creative that lays itself out once on load and never listens for this is the creative that looks correct in portrait and broken in landscape — which is the failure the rotate control here is for.
audioVolumeChangeon muteThe device volume as a percentage, zero when muted. An ad that relies on sound to explain itself should notice this and fall back to something visual, because a large share of mobile viewing happens with the sound off.
Five ways a playable fails inside a container
Each of these runs correctly in a browser opened directly, which is what makes them expensive to find any other way.
The ad plays but the viewer sees it half finished
Playback started at load or at ready instead of waiting for viewableChange. The container had prepared the creative in the background, so the opening ran off screen. On the timeline this shows as gameplay activity before the viewableChange(true) line — and as a viewableChange fired with zero listeners attached.
Tapping the call-to-action does nothing
The exit went through window.open, a plain anchor, or another network's SDK. An MRAID container intercepts navigation, so anything other than mraid.open(url) is swallowed silently. This container reports the attempt rather than allowing it, so the wrong exit call appears as a line on the timeline instead of as nothing at all.
Rejected for including mraid.js
The creative bundled its own copy of the interface. The network injects the real one at serve time, and a bundled file either shadows it or trips an automated check. Reference it if your build needs the symbol to exist, but never ship the implementation.
Works in a browser, blank on a device
Almost always an error thrown during load. A browser opened directly has no MRAID object at all, so a creative written defensively falls back and looks fine; inside a real container it takes the other branch and hits something that throws. Any uncaught error appears on the timeline, and everything after it never ran.
Sound plays before anyone has touched the ad
Audio started on load. Mobile browsers block unprompted playback, so the sound usually does not arrive and the creative carries on as though it had — leaving the rest of the ad out of step. Several networks also reject it outright. This container marks any play() before the first interaction.
MRAID covers four of the networks this editor exports to. For size limits, packaging and the exit call on all thirteen, use the spec checker, or 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.
- How close is this to a real ad network container?
- Close enough to expose the mistakes that matter, and deliberately not presented as more than that. It implements the MRAID 3.0 state machine, the event sequence and the methods a playable actually calls, on delays resembling a real container. What it cannot reproduce is a specific network's timing, its SDK quirks, or the performance of a real device. Treat a pass here as a good sign and a network's own tester as the authority.
- Why does the timeline say a container event had 0 listeners?
- Because the container fired it and your creative was not subscribed. That line is the most useful one here: it distinguishes an event the ad handled from one it never heard. A viewableChange with no listeners means nothing in the creative reacts to becoming visible, which on Unity is a requirement rather than a preference.
- Which networks use MRAID?
- Among the networks this editor exports to: Unity Ads, AppLovin, ironSource and Chartboost. Meta, Moloco and InMobi use a different interface entirely — a single FbPlayableAd.onCTAClick() call with no ready gate and no viewability event, which has a validator of its own — while TikTok and Pangle share another, and Mintegral, Google and the Vungle / Liftoff Monetize pair each have their own, the last of those under the name Adaptive Creative. A creative built for one of those will run in this container and fail its exit check, because the call it makes is not the one MRAID defines. Worth knowing in the other direction too: an MRAID build retargeted at Meta or Moloco fails on the mraid.js tag alone, whether or not any code calls it.
- Can I test a ZIP here?
- Not in this validator. A single HTML file carries everything it needs, but an archive's entry document loads assets from sibling files that a srcdoc frame cannot resolve, so the ad would run half-loaded and look broken for reasons that are not its fault. Check archives with the spec checker instead, which inspects every file inside them.
Your next playable is one afternoon away.
Open the editor, pick a format and start placing objects. Nothing to install, and nothing to pay.
