Validate a GTM dataLayer against a JSON Schema — free, in-browser
Paste a GTM/GA4 dataLayer and validate every event against a JSON Schema. Catches missing required keys, bad enums, and type mismatches — fully client-side.
last verified 2026-07-18
A broken dataLayer fails silently. GTM will happily read page.type: "landing" even though your
tracking plan says the only valid values are home, category, product, and a handful of others.
GA4 will accept value: "12.00" as a string and quietly break your revenue reporting. Nothing errors,
nothing warns — the damage only surfaces weeks later as a report that doesn’t reconcile. The
dataLayer Validator exists for exactly this gap: paste the contents of
a dataLayer, and every push is checked, per event, against a JSON Schema — the published
dataLayer Event Spec by default, or your own tracking-plan schema.
It runs 100% client-side. Nothing you paste leaves the browser, and the tool works offline, which matters when the payload you’re debugging contains user IDs or transaction data you’d rather not send to a third-party validator.
What it does
You paste a dataLayer in any of three shapes: a JSON array of push objects, a single event object,
or a JSON string of either. GTM/gtag array-form pushes like ["event", "purchase", {…}] are
unpacked automatically into normal event objects. The tool then validates each event independently
and renders a results table with one row per event: its index, its event name, a pass/fail status,
and — for failures — every error as a triplet of JSON path, failed keyword, and a plain-English
message. A summary line above the table counts total events, how many passed, and how many have
errors.
Out of the box it validates against a compact subset of the published
dataLayer Event Spec. That default schema requires an event key
on every push and enforces, among other things:
eventnames matching the snake_case pattern^[a-z][a-z0-9_]{1,49}$page.pathstarting with/, andpage.typedrawn from a ten-value enum (home,category,product,cart,checkout,confirmation,article,search,account,other)consentkeys limited to the four Consent Mode signals (ad_storage,analytics_storage,ad_user_data,ad_personalization), each strictly"granted"or"denied"— any extra key is flaggedecommerce.value,shipping, andtaxas non-negative numbers,currencymatching^[A-Z]{3}$- every item in
ecommerce.itemscarryingitem_idanditem_name, withquantityas an integer of at least 1
A separate Schema tab shows the active schema as editable JSON. You can tweak it or replace it wholesale with your own tracking-plan schema; it persists in your browser’s localStorage, so your custom schema survives reloads without ever touching a server.
How it works
The engine (datalayer.js) is a deliberately small JSON Schema validator — a hand-written subset of
draft 2020-12 with zero dependencies. It supports exactly these keywords, and documents that list in
the UI: type, required, properties, additionalProperties (boolean form), enum, const,
pattern, minimum, maximum, minLength, maxLength, items (single-schema form), and $ref
to local #/$defs or #/definitions pointers. Anything else — allOf/anyOf/oneOf/not,
if/then/else, remote $refs, tuple items, prefixItems, dependentRequired, multipleOf,
minItems/maxItems, format — is intentionally skipped rather than mis-evaluated, so a result is
never silently wrong about a keyword it doesn’t understand.
Before validation, each raw push goes through a normalization step. Plain objects pass through
untouched. Arrays whose first element is "event" and second is a string are merged into an event
object (["event", "purchase", {…}] becomes { event: "purchase", … }). Other command-style arrays
(config, set, consent, js) are preserved as inspectable _command entries — they carry no
event key, so the schema’s required rule flags them rather than the tool crashing on them.
Primitive pushes are wrapped the same defensive way.
The validator itself walks each event recursively alongside the schema. A few implementation details worth knowing:
- Type checks distinguish
integerfromnumberthe way JSON Schema does:1.5fails anintegerrule, which is how the tool catches fractionalquantityvalues. enumandconstuse structural deep equality, so they work on objects and arrays, not just scalars.$refresolution handles JSON Pointer escaping (~0,~1), and an unresolvable$refproduces its own explicit error instead of passing vacuously. A depth guard (200 levels) stops pathological self-referential schemas.- Every error is recorded as
{instancePath, keyword, message}— the same shape Ajv users will recognize — which is what lets the results table pin each failure to an exact JSON path like/ecommerce/items/0/item_id. patternuses JavaScript regular expressions; a pattern that fails to compile is skipped rather than treated as a failure.
The default schema is written using only supported keywords, so results against it are faithful. The
full published spec additionally layers if/then and not guards that this subset does not
evaluate — the tool says so in the UI rather than pretending otherwise.
How to use it
- Open the dataLayer Validator and stay on the Validate tab.
- Paste your dataLayer JSON into the textarea. From a live page, you can run
copy(JSON.stringify(window.dataLayer))in the browser console and paste the result. - Press Validate (or Ctrl/Cmd+Enter). You’ll get a parse confirmation (“Parsed N events”), a pass/fail summary, and the per-event error table.
- Not sure what output looks like? Sample — valid loads a clean
page_view+purchasepair; Sample — with errors loads a deliberately broken payload (missingevent, apage.pathwithout a leading slash, anAdd To Cartname that fails the snake_case pattern, a strayconsent.marketingkey, a stringvalue, lowercase currency, an item missingitem_id, and a fractionalquantity) so you can see how each failure is reported. - To validate against your own tracking plan, switch to the Schema tab, paste your JSON Schema, and press Use this schema. A live check under the textarea confirms the JSON parses before you apply it; Reset to default restores the published spec subset at any time.
Limitations
- It’s a subset validator. Schemas leaning on
allOf/anyOf, conditionals,format, or array cardinality keywords will have those rules skipped, not enforced. Passing here means “conforms to every rule checked,” which the tool states verbatim in its results — not full draft 2020-12 conformance. - It validates a static snapshot. It checks the JSON you paste, not the live page: it cannot see push ordering, timing, race conditions with tag firing, or whether the tags reading the dataLayer actually fire. The tool’s own framing is right: validation is step one, ground truth is step two.
additionalPropertiesis supported only in boolean form — a schema-valuedadditionalPropertiesis ignored.- Your schema lives in one browser. localStorage persistence means no sync across machines or teammates; if localStorage is unavailable, the tool warns that your schema won’t survive a reload.
FAQ
Does my dataLayer leave my browser? No. Parsing and validation run entirely client-side, the page works offline, and the only thing stored anywhere is your custom schema, in your own browser’s localStorage.
Why does a push show up as “(command: config)” or “(no event)”?
Command-style array pushes (config, set, consent) and pushes without an event key are kept
and validated rather than dropped. Since the default schema requires event, they’re flagged — which
is usually what you want a QA pass to surface.
My events pass here — why is GA4 still wrong? Schema conformance says the data is shaped correctly, not that it’s collected. Tag firing rules, consent state, trigger ordering, and transport can all still break collection. Use the Beacon Decoder to inspect what’s actually being sent, and see the GA4 guide for the collection pipeline.
Can I use my own tracking-plan schema?
Yes. The Schema tab accepts any JSON Schema built from the supported keyword subset (type,
required, properties, additionalProperties, enum, const, pattern, min/max bounds,
items, local $ref). Keywords outside the subset are skipped, and the UI lists exactly what’s
supported.
Where does the default schema come from? It’s a compact, faithful mirror of the published dataLayer Event Spec, rewritten to use only keywords the validator fully supports, so no result against the default is based on a partially evaluated rule.
Related
- dataLayer Validator — the tool itself; free, no account.
- dataLayer Event Spec — the standard the default schema mirrors.
- Events and schemas — why tracking plans and event schemas exist.
- Google Tag Manager — where the dataLayer fits in the tag stack.
- GA4 — the collection pipeline your validated events feed.
- GTM Container Explorer and Beacon Decoder — inspect the container reading your dataLayer and the beacons it produces.
- All free tools and the vendor directory.
- BeaconForge is pre-launch: it audits the beacons your pages actually send — the ground truth this validator can’t see — subscribe for first access.