JSON Schema Validator

Check a JSON document against a JSON Schema with Ajv, on draft-07 or 2020-12, and get a numbered error list with a path for each one.

🌐 Español

🔒 Private by design: your text is processed locally in your browser and never uploaded to any server.

Box one holds the document, box two holds the schema

The two text areas on this page come from the layout the site’s text comparison tools use, which is why they are labeled “Original text” and “Changed text” instead of something JSON specific. Learn the mapping once and it stops mattering, and it is worth learning: because Ajv runs here with strict mode off, an ordinary data object pasted into the schema box compiles into a schema that imposes no constraints at all, so reversing the two boxes returns a cheerful VALID rather than a complaint. The first box is always the JSON being inspected. The second box is always the schema. In “Generate a schema from an example” mode the second box is not read at all, so anything you leave in it is quietly ignored rather than validated against.

  1. Paste the JSON document you want to check into the box labeled Original text.
  2. Paste the JSON Schema into the box labeled Changed text.
  3. Leave Mode on “Validate JSON against a schema”, then set JSON Schema draft to “Draft-07 (most common)” or “2020-12 (latest)” so it matches the schema you just pasted.
  4. Click the action button, which carries this tool’s own name, and read the report that replaces both boxes.
  5. Take the result away with Copy to clipboard, or press Compare another to start again. That second button empties both boxes, so checking a second document against the same schema means pasting the schema in again.

Anatomy of a failing report

Take a document with a negative age, an unexpected extra key and a missing city, checked against a schema that requires name, age and city, sets a minimum of zero on age and refuses additional properties. The report comes back numbered:

=== ERRORS ===
1. (root): must have required property 'city'
2. (root): must NOT have additional properties (property: "extra")
3. /age: must be >= 0

Everything before the colon is a JSON Pointer into your document. A pointer of /age means the top-level age member; a deeper failure would read /items/2/price. When the failure belongs to the document as a whole rather than to any one field, as with a missing required key, the pointer is empty and the report prints (root) instead so the line still reads sensibly.

The second line is worth a closer look. Ajv’s own message for a rejected extra key is just “must NOT have additional properties”, which tells you a rule was broken but not which key broke it. The name is available in the error object’s parameters, so this tool appends it in brackets. That one addition is usually the difference between fixing a payload immediately and diffing it against the schema by eye.

Every line you see is produced by the tool itself rather than by an exception. A malformed document, a schema that is not valid JSON, and a schema that parses but is not a legal JSON Schema each land in their own labeled branch of the report, so you get a specific sentence in the result box rather than a generic failure banner.

Draft-07 and 2020-12 are not interchangeable

Both drafts are in genuine daily use, which is the only reason a selector exists. Draft-07 is what most published schemas, most tutorials and OpenAPI 3.0 target. 2020-12 is what OpenAPI 3.1 and newer generators emit. The two are not a version bump you can ignore, and one keyword shows why. Validate the document [1, "x"] against a schema whose prefixItems says the first element must be a string. Under Draft-07 the result is VALID, because prefixItems did not exist yet and an unknown keyword is skipped. Under 2020-12 the same pair reports one error, /0: must be string. Nothing about the schema or the document changed; only the rule set did.

The practical habit this suggests is simple. If a schema you inherited never seems to reject anything, run it once under each draft before concluding the data is clean.

Format keywords are accepted, then ignored

A schema here can say "format": "email" and it will compile without complaint, but the value is only ever checked as a string. Format support in Ajv lives in a separate companion package that this tool does not bundle, so the keyword is recognized as unknown, noted in the browser console, and skipped. That is a deliberate trade for a smaller download, and it is the single most common way a validator can look stricter than it is. Where a real constraint matters, write it as a pattern with a regular expression, or as minLength, enum or minimum, all of which are enforced.

Turning one example payload into a starting schema

Switch Mode to “Generate a schema from an example”, drop a real response into the first box, and you get back a complete schema with a $schema URI matching whichever draft is selected. It is a first draft, not a finished contract, and it makes three guesses you should expect to edit. Numbers always become "type": "number", so an integer id is not constrained to integers. Every key in the example is listed as required, because a single sample is the only evidence available. For an array of similarly shaped records the generator merges the items, keeping every key it saw but marking as required only the keys present in all of them, so one record missing a field will not force that field on the rest.

If the example itself is what you need first, generate a realistic payload with the Fake Data Generator, or tidy a real one with the JSON Formatter before pasting. When a document fails and you cannot see where, the JSONPath Tester lets you query for the exact field the pointer named, and the JSON Diff tool answers the related question of what changed between the payload that passed and the one that did not. Schemas written in YAML need a trip through YAML to JSON first, since only JSON is accepted here. Our developer tools guide puts this page in context alongside the rest of the encoding and formatting set.

See it in action

Screenshot of the JSON Schema Validator tool with the sample input “{"slug":"compress-pdf","uploads":false}”, Mode set to Validate JSON against a schema, JSON Schema draft set to Draft-07 (most common)
JSON Schema Validator mid-process: the sample input “{"slug":"compress-pdf","uploads":false}”, Mode set to Validate JSON against a schema, JSON Schema draft set to Draft-07 (most common).
Screenshot of the JSON Schema Validator result screen showing the generated output “=== VALIDATION RESULT === Draft: JSON Schema dra…”
The finished result: the generated output “=== VALIDATION RESULT === Draft: JSON Schema dra…”. The download link is a local blob URL — the file never leaves your device.

Frequently asked questions

Which of the two boxes takes the schema, and which takes the document?

The box labeled "Original text" always holds the JSON you are inspecting, and the box labeled "Changed text" holds the JSON Schema. Those labels come from the two-box text layout this tool borrows rather than from the tool itself, which is why they sound generic. Getting them the wrong way round is worth guarding against, because it does not raise an error; an ordinary data object compiles as a schema that constrains nothing, so a swapped pair happily reports VALID.

I filled in only one box and the button still worked. Why?

The action button becomes clickable as soon as either box has content, since the two-box layout has no way to know that this particular tool needs both. The report then tells you exactly which one is missing, with the wording "No JSON Schema was provided" or "No JSON document was provided" plus the name of the box to paste it into. Nothing is validated until both are present.

My schema passes on Draft-07 but fails on 2020-12. Is that a bug?

No, and it is the clearest reason the draft selector exists. Keywords introduced in 2020-12, prefixItems being the obvious one, are simply unknown words to the draft-07 rule set, so they are ignored and the document sails through. Selecting 2020-12 loads a validator that understands them, and the same document can then fail with a real error. If a schema looks suspiciously permissive, checking it under both drafts is a fast sanity test.

Are format keywords such as email, uri or date-time enforced?

They are accepted but never checked. The optional Ajv add-on that implements format checking is not bundled here, so a schema declaring a string as an email is validated only as a string; Ajv notes the unknown format in the browser console and carries on. Anything you truly need enforced should be expressed as a pattern with a regular expression instead, which is checked properly.

Why does the report list several errors at once instead of stopping at the first?

The validator is built with Ajv's allErrors setting turned on, so one pass collects every violation rather than bailing out early. Each numbered line starts with a JSON Pointer showing where the problem is, with the text (root) standing in for the whole document, then Ajv's own description of what went wrong. Errors about a rejected extra property also name the offending property, which Ajv's default message leaves out.

What assumptions does the schema generator make about my example?

Three worth knowing. Every numeric value is inferred as number, never integer, so an id of 7 produces a loose type. Every key present in a single example object becomes required, and for an array of objects the generator keeps the union of all keys but only marks as required those appearing in every item. An array whose items have different shapes gets an empty items constraint rather than a union, and additionalProperties is deliberately left unset so an extra field never breaks the generated schema.

Related tools