Text & Data

JSON Schema Validator

Validate JSON against a JSON Schema (draft 2020-12, 2019-09, 7 or 4) and see every error with JSON Pointers to the value and the schema keyword. Remote $refs are never fetched. Runs in your browser.

JSON Schema validator options

Draft

"From $schema" uses the draft the schema declares, and 2020-12 when it declares none.

Keyboard shortcuts

Esc
Close a menu or overlay, then leave full screen
↓ on a menu
Open it; ↑ ↓ move through its items
← → in the menu bar
Move between menus

Where your data goes

Using this page Using the API, MCP or A2A
Where it runs In your browser. The schema and the instance are parsed and validated by JavaScript on this page; nothing is sent anywhere, and remote $refs are never fetched. In a Cloudflare Pages Function at the Cloudflare data centre nearest the caller.
What leaves your device Nothing you enter. After the page and its scripts load, no request carries your input. The browser enforces this: the page's Content-Security-Policy sets connect-src 'none' and form-action 'none', which block fetch, XHR, WebSocket, EventSource, beacons and form posts.

The server receives the schema and the instance, processes it in memory inside the request, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. The server makes no network requests. For confidential documents use the page, which does the same work in your browser and sends nothing.

Stored Nothing leaves the page. No cookies, analytics or third-party scripts; the browser keeps only your View → Inline config choice. Your inputs and results: never. What is stored is your client record (client ID, a SHA-256 hash of your secret, expiry, and the profile you registered with) and one metadata row per call: operation, time, transport, status, error code, duration, request and response sizes, and country.
Logged Nothing (no requests are made). Only the per-call metadata above, attributed to your client ID. Never parameters, bodies, results, or credentials. Cloudflare, as the host, also processes request metadata (IP address, full URL including the query string, headers) under its own policies, so put inputs in POST bodies.
Access Open to anyone. Requires a client ID and secret (how to get one). HTTPS only; TLS terminates at Cloudflare.

Details and how to verify this yourself: Security & privacy.

User guide

The tool sits in a window that works like a desktop app: menus on the top row and the full-screen icon at its right (Esc leaves full screen). The set-up options described below are in Settings → Options…, an overlay, and the Settings menu also lists the common choices directly. To keep the options in view instead, choose View → Inline config; the page remembers that choice. Help → Keyboard shortcuts… lists the keys.

  1. Paste the schema on the left and the JSON to validate (the instance) on the right. Validation runs as you type. Sample loads an example with several errors.
  2. Read the verdict:
    • Valid means the instance satisfies every keyword of the schema.
    • Invalid lists each problem: where it is in the instance (a JSON Pointer such as /items/2/price), the keyword that failed, a message, and where that keyword is written in the schema.
  3. If the schema or the instance is not valid JSON, the error shows the line and column, and Go to error selects it. If the schema is valid JSON but cannot be used (a misspelt type, a broken regular expression, a $ref that points nowhere), each problem is listed with its location in the schema.

Which draft? From $schema uses the draft the schema declares in $schema, and 2020-12 if it declares none. Choose a draft explicitly to override it. The drafts differ in a few places that matter: in draft 7 and earlier, keywords next to a $ref are ignored; in draft 4, exclusiveMinimum and exclusiveMaximum are booleans.

Summary errors. When a nested value fails, the validator also reports the keywords that led there (properties, items, $ref, anyOf…), such as Property “id” does not match schema. These are hidden by default; tick Show summary errors to see the full chain. They are useful with anyOf and oneOf, where the summary is the actual failure and the errors under it explain why each alternative did not match.

Warnings point out things that do not stop validation but probably do not do what you meant: unknown keywords (often typos such as requried, or OpenAPI’s nullable), formats this validator does not check, keywords from a different draft, and duplicate keys in either document.

Specification

Validator. @cfworker/json-schema 4.1, which interprets the schema rather than compiling it to JavaScript, so it runs in a browser with a strict Content Security Policy and in Cloudflare Workers, where generating code at runtime is forbidden. It is tested against the official JSON-Schema-Test-Suite.

Drafts.

DraftSelected byNotes
2020-12https://json-schema.org/draft/2020-12/schema, or no $schema$dynamicRef and $dynamicAnchor are not supported (ignored, with a warning).
2019-09https://json-schema.org/draft/2019-09/schema$recursiveRef / $recursiveAnchor are supported.
7http://json-schema.org/draft-07/schema#Keywords beside $ref are ignored.
6http://json-schema.org/draft-06/schema#Validated with draft 7 rules, with a warning (draft 7 only added if/then/else).
4http://json-schema.org/draft-04/schema#Boolean exclusiveMinimum/exclusiveMaximum; keywords beside $ref are ignored.
3http://json-schema.org/draft-03/schema#Not supported: rejected.

$schema URIs match with http or https and with or without a trailing #. An unrecognised $schema is validated as 2020-12, with a warning. Apart from the differences in the table, every keyword is applied whichever draft is selected: prefixItems or dependentRequired in a draft 7 schema still take effect, with a warning that they belong to a later draft. In draft 2020-12 the array form of items is applied as a tuple (the older meaning), with a warning to use prefixItems.

Formats are asserted (an invalid value is an error) for: date, time, date-time, duration, uri, uri-reference, uri-template, url, email, hostname, ipv4, ipv6, regex, uuid, json-pointer, json-pointer-uri-fragment, relative-json-pointer. Any other format (for example idn-email, iri, or a custom one) is not checked and produces a warning.

References.

  • Resolved: JSON Pointer fragments (#/$defs/name), $anchor names, and schemas embedded in the same document with their own $id (a $ref to that $id, absolute or relative, resolves to the embedded copy). A schema without an absolute $id uses the base URI https://schema.invalid/root.json, which never resolves to anything real.
  • Never fetched: a $ref to anything not in the document (for example https://example.com/address.json, or a meta-schema URL) is an error that names the reference and its location. Neither the page nor the server makes network requests. To use an external schema, copy it under $defs with its $id.
  • Cycles: recursive schemas are fine as long as each step goes deeper into the instance. A cycle that does not (such as {"$ref": "#"}) is reported instead of hanging.

Checks before validating. These make the schema unusable and are reported as problems with their schema location; nothing is validated until they are fixed.

  • A schema (or subschema) that is not an object or a boolean.
  • type that is not one of array, boolean, integer, null, number, object, string (with a suggestion for int, bool, float, str, dict, list, …), or an empty array.
  • required that is not an array of strings; required: true is identified as draft 3 syntax.
  • pattern or a patternProperties key that is not a valid ECMA-262 regular expression with the u (Unicode) flag. Needless escapes such as \_ are errors under that flag.
  • enum that is not an array; minimum, maximum, multipleOf (greater than 0) that are not numbers; length and count keywords that are not non-negative integers; allOf/anyOf/oneOf that are not non-empty arrays; $ref that is not a string.
  • A $ref that does not resolve (see above).

Errors. Each error has:

FieldMeaning
instanceLocationJSON Pointer (RFC 6901) to the failing value; "" is the whole instance. Keys containing / or ~ are escaped as ~1 and ~0.
keywordThe failing keyword, or false where the schema is false.
keywordLocationThe path taken through the schema, as a JSON Pointer; a $ref segment marks a reference that was followed, e.g. /properties/id/$ref/minimum.
schemaLocationWhere that keyword is written in the schema document, after following references, e.g. /$defs/positive/minimum. Null only when the path goes through $recursiveRef.
messageWhat is wrong.
leaffalse for a summary error that is immediately followed by the more specific errors that caused it.

Errors are in evaluation order. With All errors off (API: all_errors=false), the result is the first specific error and the summary errors leading to it; valid is the same either way. At most 1,000 errors are returned; errorCount is the total.

Corrections to the library’s output. The raw library output has three quirks, which are corrected here:

  • An error from a false subschema reported the instance location as its schema location.
  • With all errors enabled, a property listed in properties that failed its own schema was also reported, wrongly, as an “additional” property.
  • Required and declared properties were looked up including inherited JavaScript names, so "required": ["toString"] passed on {}. Both documents are now plain data with no inherited names.

Semantics worth knowing.

  • Numbers are compared as IEEE 754 doubles. 1.0 is an integer in every draft. multipleOf avoids binary rounding artefacts: 0.07 is a multiple of 0.01.
  • pattern uses JavaScript regular expressions with the u flag and is not anchored: add ^…$ to match the whole string. A pattern with catastrophic backtracking can use up the request’s CPU time; on the page it can make the tab unresponsive.
  • uniqueItems, const and enum compare objects and arrays structurally.
  • Duplicate keys in either document are reported as warnings; the last value is used.

Limits. The instance may be nested at most 100 levels deep (the validator recurses several stack frames per level). API: schema at most 100,000 characters and instance at most 200,000 characters.

API. POST /api/json/schema/validate with schema and instance as JSON text, draft (auto, 2020-12, 2019-09, 7, 4) and all_errors. An invalid instance is a 200 response with valid: false. A schema or instance that is not valid JSON, or a schema that cannot be used, is a 422 error whose message gives the location.

API & MCP

The same logic is available over HTTP and as MCP tools. Unlike this page, these run on the server: see where your data goes.