Free tool · no sign-up

Meta Playable Ads validator

For Meta, Moloco and InMobi playables — one FbPlayableAd call, three sets of rules

Drop in the playable you would submit to Meta, Moloco or InMobi and watch the one call this format has. FbPlayableAd.onCTAClick() is the whole protocol — no ready event, no viewability gate, no lifecycle — which means almost everything that fails a review here is in the file rather than the run. The three networks share that call and disagree about nearly everything else, so every finding below says which of them it is about.

Drop a playable to run it

The single .html file you would submit to Meta, Moloco or InMobi — or a .zip for the two that take one. It runs in a mock FbPlayableAd container in a sandboxed frame on this device — nothing is uploaded.

Where the three networks disagree

They share the exit call and the 5 MB cap. Everything else is worth checking per network, and it is the reason the same file can be accepted by one and refused by another.

NetworkPackaging
MetaSingle HTML or ZIP with index.html at the root, max 100 filesPublishes its own Playable Ads Preview tool for a first-party check.Portrait, responsive
MolocoSingle HTML only — a ZIP is rejected outrightRejects a creative that merely contains mraid.js, commented out or not.Landscape
InMobiSingle HTML or ZIPAccepts a Meta-format build; delivered through a contact rather than self-serve.Landscape

A single HTML file with every asset data-URI compressed into it is the build that travels furthest — it is the only packaging all three accept.

How the format works

Three networks, one call, and no agreement on anything else

Meta, Moloco and InMobi all take a playable whose call-to-action calls FbPlayableAd.onCTAClick(). That is where the similarity ends. Moloco rejects a ZIP outright and wants a single HTML file; Meta accepts either and caps a ZIP at 100 files; InMobi takes a Meta-format build and is reached through a contact rather than a self-serve upload. Meta asks for portrait, the other two want landscape. The practical consequence is that one file is rarely correct for all three, and a rejection from one of them tells you very little about the other two — which is why the tool above makes you pick a network before it decides anything.

The protocol is one function, and that is genuinely all of it

There is no SDK to initialise, no handshake and no state machine. MRAID makes a creative wait for ready and then for viewableChange before it may start. Mintegral holds a loading screen up and calls into your creative when it is ready to begin. This format does neither: the container injects an object with a single method, your creative runs as soon as it can, and it calls that method when someone taps the call-to-action. Nothing tells you the ad became visible, because there is no event that says so. If you are porting a creative from MRAID, the single most common way it fails here is that it is still waiting for a signal that will never arrive.

So do not wait for anything before you start

The absence of a ready gate is a design instruction, not an omission to work around. Start as soon as your artwork is loaded. A creative that defers its first frame until some container event fires will sit on a blank screen for the entire impression, and the failure looks exactly like a broken build rather than a misread specification. The exporter behind this tool has no ready gate for this family for precisely this reason — the runtime's own default, which is to begin once the images are warm, is the correct behaviour here rather than a shortcut.

Write the call against the bare global, even where an alias is tidier

This is the rule that costs people a submission cycle, and it is not written down in any of the three specifications. Reviews in this family read the creative's text. A build that saves the object first — var fb = window.FbPlayableAd, then fb.onCTAClick() — behaves identically in every test you can run and reads, to anything scanning the file, as a playable whose call-to-action does nothing. Write FbPlayableAd.onCTAClick() out in full. The same applies to what your build tools do afterwards: a bundler that hoists the global into a local variable reintroduces the problem long after you stopped thinking about it.

Guard the global rather than aliasing it

The obvious objection to the paragraph above is that referencing a bare global is unsafe when the container might not be there — and that is a real concern, because a reviewer opening your file directly gets no FbPlayableAd at all. The answer is to check for it without capturing it: test window.FbPlayableAd, and inside that branch call FbPlayableAd.onCTAClick() against the bare name. The guard makes the reference safe and the literal call stays readable to a scanner. The tool above has a switch that removes the global entirely so you can see what a reviewer opening the file by hand would get — a creative that throws there is broken before it reaches an ad.

mraid.js must not be in the file at all

Meta's specification states that a playable must work without mraid.js or similar frameworks. Moloco goes further in practice: it rejects a creative that merely contains the reference, which means a commented-out script tag is still a rejection. That is a harsher rule than it sounds, because the usual way a playable acquires an mraid.js tag is that it was built for Unity or AppLovin first and the tag lives in a shared HTML template nobody thinks about. This is why the exporter here declares its head scripts per network instead of sharing one shell — inheriting MRAID's would fail this family's review on a file that otherwise runs perfectly.

Nothing may touch the network at runtime

Meta's wording is that no external network calls are permitted, with XMLHttpRequest named as the example; Moloco repeats the prohibition. Everything the creative needs must be inside the file before it ships, which is what data-URI compression of the assets is for. The consequence people miss is analytics: there is no allowance for a tracking beacon here, and a scanner reading your source will find the call whether or not it ever fires. Remote configuration, a late-loaded font, an A/B flag fetched at start — all of it has to go, and the creative has to work with what it was packaged with.

No JavaScript redirects, because the network owns the destination

Meta's specification says playable HTML5 assets should not contain any JavaScript redirect. This trips up builds that were previewed on the web first, where sending the browser somewhere is the natural way to test a click-through. In an ad it is not how anyone reaches the store: onCTAClick() takes no arguments at all, the network holds the destination itself, and anything your creative supplies is discarded. If you have been trying to work out where to put your store URL, the answer is that you do not — which is why the export dialog in this editor greys the URL fields out when every selected target is one of these three.

The entire API

Not an excerpt. One method on one injected object is the whole of what this format gives a creative, and there is nothing to wait for before using it.

FbPlayableAd.onCTAClick()
Creative → networkwhen someone taps your call-to-action

The whole interface. It takes no arguments — the network holds the destination and discards anything you pass — and it should fire once, on a real tap. Write it against the bare global so a scan can read it, guard it with a check that window.FbPlayableAd exists, and do not call it on load: an exit before any interaction reads as an auto-redirect and is one of the quicker ways to fail a review.

Six ways this fails review

Written as symptoms rather than as rules, because the rule is not what you have in front of you — a rejection notice is.

  1. 1

    Rejected for containing mraid.js, in a creative that never uses MRAID

    The tag is in the file even though no code calls it — almost always because the playable was built for Unity, AppLovin or ironSource first and the script tag lives in a shared template. Moloco rejects a creative that contains the reference at all, so commenting it out does not help and neither does leaving it in place unused. Delete the tag. If you are exporting from a tool, check that it emits a different HTML shell per network rather than one shell for everything.

  2. 2

    Rejected for a missing call-to-action, in a creative whose CTA works

    The most confusing rejection in this family, because it is a true statement about your file and a false one about your ad. The call was saved into a variable first, or reached through a wrapper, or hoisted into a local by a bundler — so onCTAClick fires perfectly at runtime and the literal FbPlayableAd.onCTAClick() is nowhere in the text being read. Write it out against the bare global, and check what your minifier produces before you resubmit.

  3. 3

    The ad shows a blank screen for the whole impression

    A creative ported from MRAID that is still waiting for a signal this format does not send. There is no ready event and no viewableChange here — nothing will ever tell your creative it became visible, so a first frame gated on one never arrives. Start as soon as your artwork has loaded. This is the failure most likely to look like a broken build when it is actually a misread protocol.

  4. 4

    Moloco rejected the exact file Meta accepted

    Almost certainly the packaging. Moloco takes a single HTML file with every asset data-URI compressed into it and rejects a ZIP outright, while Meta accepts either. The same archive is therefore a correct Meta submission and an instant Moloco rejection. Export the single-file build for Moloco. Orientation is the other half of this: Meta asks for portrait and responsive, Moloco and InMobi want landscape.

  5. 5

    Rejected for a network call your creative does not appear to make

    Something in the file references XMLHttpRequest or fetch, and it does not need to run to be found — a scan reads the source. Analytics beacons are the usual culprit, followed by a remote font, a late-loaded config file, or a library that includes an HTTP client you never call. No external network calls are permitted in this format, so everything has to be inlined before you ship and the unused code has to come out along with it.

  6. 6

    Tapping the call-to-action opens a new tab, or nothing at all

    The exit went through window.open, an anchor, or an assignment to location rather than through onCTAClick(). This is the signature of a build made for the open web or for another network and retargeted. It is the failure that survives local testing most reliably, because navigating works perfectly when you open the file yourself and does nothing inside a real placement — which is exactly the difference the container above reproduces.

Nothing leaves your device

Your creative is read in the browser and rendered into a sandboxed frame on this machine. There is no upload step and no server involved — the file, and whatever it is advertising, stay with you.

Meta's own preview tool

Meta publishes a Playable Ads Preview that checks an asset against its specifications and validates that the call-to-action is wired correctly. It is the first-party check — this page is for catching mistakes before you get there, and for the two networks it does not cover.

Meta Playable Ads Preview

Meta, Moloco and InMobi are three of the thirteen networks this editor exports to. If your creative targets Unity, AppLovin, ironSource or Chartboost, use the MRAID validator instead; for Mintegral there is the Mintegral validator, for Vungle and Liftoff Monetize the Adaptive Creative validator, and for size limits and packaging across all of them, read the network specs.

Open the spec checker

Common 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.
Why is this called the Meta Playable Ads validator rather than the FbPlayableAd validator?
Because nobody searches for FbPlayableAd until after they have been rejected. None of these three networks gives the format a branded name — Meta's own page is titled "Specifications for playable ads assets", Moloco files it under playable and interactive end card creatives, and InMobi under general creative specifications — so the network name is the clearest label available. FbPlayableAd is the name of the JavaScript global, it appears throughout this page, and it is what the tool checks for.
Can I submit the same file to Meta, Moloco and InMobi?
Sometimes, and it depends mostly on packaging. A single HTML file with every asset data-URI compressed into it is acceptable to all three, so that build travels furthest. A ZIP is fine for Meta and InMobi and rejected outright by Moloco. Orientation is the remaining difference: Meta asks for a portrait design that is responsive across resolutions, while Moloco and InMobi want landscape. Pick a network in the tool above and it will show you only what that one would refuse.
What is the file size limit?
5 MB for all three, measured on the file as you upload it. Meta states it as a maximum file size of 5 MB for playable HTML5 files. Artwork is almost always what pushes a build over, and it is worth remembering that data-URI encoding adds roughly a third to an asset's size — so the inlined single-file build is meaningfully larger than the loose assets that went into it. Re-export images at the dimensions they are actually drawn at before you start compressing quality.
Why does onCTAClick() take no arguments? Where does my store URL go?
It does not go anywhere in the creative. The network holds the destination and attaches it at serve time, so the call takes no parameters and anything you pass is discarded. This surprises people porting from formats where the creative supplies the URL, and it is the reason the export dialog in this editor greys out the URL fields when every selected network is one of these three — there is nowhere for that value to go.
Do I need to wait for the ad to become visible before starting?
No, and you cannot. There is no viewability event in this format — nothing will tell your creative it became visible, so there is no signal to wait for. Start as soon as your artwork is loaded. If you are porting a creative that waits for MRAID's ready or viewableChange, that wait is the reason it shows a blank screen here, and removing it is usually the whole fix.
My creative does not use MRAID, so why does mraid.js matter?
Because the rule is about the file rather than the behaviour. Meta requires that a playable work without mraid.js or similar frameworks, and Moloco rejects a creative that contains the reference at all — so an unused script tag, or even a commented-out one, is enough. The usual way this happens is a shared HTML template carried over from an MRAID build. Deleting the tag is the fix, and it is worth checking whether your export tool emits a different shell per network.
Will this tool tell me my creative is approved?
No, and it is deliberately not presented that way. It runs your creative against a mock container, checks the source the way a review scan reads it, and inspects the packaging for the rules these three networks publish. What it cannot do is reproduce a human reviewer's judgement about whether your ad is any good, or catch a policy issue in your artwork or claims. Treat a clean run here as a good sign and the network's own review as the authority. Meta also publishes a Playable Ads Preview tool of its own, linked above, which is the closest thing to a first-party check.
My creative works when I open it directly. Why would it fail review?
Opening the file directly gives you no container, which means the two most common failures are invisible. An exit routed through window.open or a location assignment works perfectly on your machine and does nothing inside a real placement, where a creative is not permitted to navigate on its own. And the source rules — mraid.js, XMLHttpRequest, a redirect, an aliased exit call — are not behavioural at all: a build that breaks every one of them can run flawlessly in front of you and still be rejected on a read of the file.
Which other networks work this way?
Only these three, among the thirteen this editor exports to. Unity, AppLovin, ironSource and Chartboost use MRAID, which has a state machine and viewability events this format has none of. Vungle and Liftoff Monetize use Adaptive Creative, whose interface is a posted message to the parent frame. Mintegral has a two-way protocol with six functions, TikTok and Pangle use another format again, and Google asks for an exit function and a meta tag. A build made for any of them will fail here on the exit call 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.