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.
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.
- 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.
- 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.
- 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
$refthat 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.
| Draft | Selected by | Notes |
|---|---|---|
| 2020-12 | https://json-schema.org/draft/2020-12/schema, or no $schema | $dynamicRef and $dynamicAnchor are not supported (ignored, with a warning). |
| 2019-09 | https://json-schema.org/draft/2019-09/schema | $recursiveRef / $recursiveAnchor are supported. |
| 7 | http://json-schema.org/draft-07/schema# | Keywords beside $ref are ignored. |
| 6 | http://json-schema.org/draft-06/schema# | Validated with draft 7 rules, with a warning (draft 7 only added if/then/else). |
| 4 | http://json-schema.org/draft-04/schema# | Boolean exclusiveMinimum/exclusiveMaximum; keywords beside $ref are ignored. |
| 3 | http://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),$anchornames, and schemas embedded in the same document with their own$id(a$refto that$id, absolute or relative, resolves to the embedded copy). A schema without an absolute$iduses the base URIhttps://schema.invalid/root.json, which never resolves to anything real. - Never fetched: a
$refto anything not in the document (for examplehttps://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$defswith 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.
typethat is not one ofarray,boolean,integer,null,number,object,string(with a suggestion forint,bool,float,str,dict,list, …), or an empty array.requiredthat is not an array of strings;required: trueis identified as draft 3 syntax.patternor apatternPropertieskey that is not a valid ECMA-262 regular expression with theu(Unicode) flag. Needless escapes such as\_are errors under that flag.enumthat 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/oneOfthat are not non-empty arrays;$refthat is not a string.- A
$refthat does not resolve (see above).
Errors. Each error has:
| Field | Meaning |
|---|---|
instanceLocation | JSON Pointer (RFC 6901) to the failing value; "" is the whole instance. Keys containing / or ~ are escaped as ~1 and ~0. |
keyword | The failing keyword, or false where the schema is false. |
keywordLocation | The path taken through the schema, as a JSON Pointer; a $ref segment marks a reference that was followed, e.g. /properties/id/$ref/minimum. |
schemaLocation | Where that keyword is written in the schema document, after following references, e.g. /$defs/positive/minimum. Null only when the path goes through $recursiveRef. |
message | What is wrong. |
leaf | false 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
falsesubschema reported the instance location as its schema location. - With all errors enabled, a property listed in
propertiesthat 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.0is anintegerin every draft.multipleOfavoids binary rounding artefacts: 0.07 is a multiple of 0.01. patternuses JavaScript regular expressions with theuflag 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,constandenumcompare 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.