What one sample can and cannot prove
Schema inference from an example is a bounded problem, and the boundary is worth naming. A single document proves that a key can appear, that its value had a particular type once, and that a nested structure is possible. It proves nothing about whether the key always appears, whether a number is ever fractional, whether a string is ever empty, or whether an array can hold something the sample did not contain.
Everything in the second list is where generated schemas go wrong, and they go wrong in the direction that hurts: too strict. A schema that requires every key seen in one response will reject the response where an optional field was omitted, and it will do so in production rather than in review. So the generator writes what the sample supports and prints the rest as a list of open questions instead of quietly picking an answer.
The three honest failures
Null. A null value carries one bit of information — the key exists — and nothing about the type. Writing {"type":"null"} is literally correct and practically useless, so every null is flagged with the suggestion that it probably wants a type list such as ["string","null"]. The better fix is to find a sample where the field is populated.
The empty array. An empty array says the key holds a list. It says nothing about the element type, so no items is written. Guessing here is tempting and wrong: an items schema inferred from nothing will reject the first real element that arrives.
Mixed element types. An array holding a string, a number and a boolean has no single element schema. Four handlings are offered and none of them is free. anyOf is the most faithful but says nothing about which position holds which type. A type list is more readable and looser still. Omitting items is the most honest and the least useful. Taking the first element is the only option that will actively reject valid data, and it is labelled as such.
Arrays of objects get merged, deliberately
When every element of an array is an object, the elements are merged into one schema rather than listed as alternatives. The properties are the union of every key seen, and required holds only the keys present in every element. This is the one place where a sample genuinely does prove optionality: if two elements are the same kind of thing and one lacks a field, that field is optional, and the note next to it records how many elements had it.
That is also the practical argument for pasting a sample with several array elements rather than one. Two orders with slightly different item objects tell the generator more than a hundred identical ones.
Integers, formats and the other quiet guesses
JSON has one number type. The distinction between integer and number in a schema is a claim about the data, not about the document, and the only evidence available is whether the sampled value happened to have a fractional part. A price field holding 4 in the sample will be typed as an integer and will reject 4.50. Every such inference is counted and flagged rather than buried.
String formats are treated the same way but more cautiously: detected, listed, and written into the schema only if you ask. One string that parses as a date is weak evidence that the field is always a date, and format behaves differently between validators — in several it is an annotation that never fails validation unless assertion is switched on. Knowing that a field looks like a timestamp is useful; asserting it on this evidence is not.
Awkward keys, and why they do not break anything
Property names in a JSON document are arbitrary strings. A payload can contain a key named constructor, __proto__, toString or hasOwnProperty, and any of those will collide with an inherited member if the generator accumulates keys in an ordinary object. The classic symptom is a schema where a real field vanishes, or where a count comes back as a function rather than a number. Every lookup and accumulator here is created with a null prototype and probed with an explicit own-property check, so those keys are handled as data. The default sample includes a constructor key for exactly this reason — it should appear in the output like any other property.
Where to take the draft next
A generated schema is a starting point for three separate follow-on jobs: adding constraints the sample cannot imply (lengths, enumerations, ranges), deciding what additionalProperties should be, and writing descriptions so the schema documents as well as validates. None of those are inferable, and all three are what make a schema worth having. While shaping the document itself, the JSON formatter finds the syntax error, JSON diff shows what changed between two captures, JSON to TypeScript produces the compile-time version of the same shapes, and the JSONPath tester is how you check a path against a real payload.
Questions people ask
Why is a field marked required when I know it is optional?
On the default setting every key present in the sample is written into required, because that is the only reading a single document supports. It is the strictest interpretation and it is frequently too strict. Switch the required setting to none and add the genuinely mandatory fields back by hand, or paste a sample whose arrays contain elements with and without the field — where objects inside an array are merged, a key missing from any element is correctly left out of required and the reason is printed.
Can I feed it several sample documents at once?
Not directly, but there is a workaround that uses the merging behaviour deliberately: wrap your samples in an array and paste that. Objects inside an array are merged into one schema with required computed as the intersection, so three captured responses in a list produce a far more honest schema than any one of them alone. The result describes the array, so lift the items schema out of the output.
What happens to a key named constructor or __proto__?
It is treated as ordinary data and appears in the output like any other property. Every internal map is created with a null prototype and every membership test is an explicit own-property check, so there is no inherited member for such a key to collide with. This is a real failure mode in schema and diff tooling rather than a hypothetical one, which is why the default sample contains a constructor key.
Which draft should I choose?
Draft 2020-12 if the validator you are targeting supports it, draft-07 if you are not sure. The output here uses only keywords that mean the same thing in both — type, properties, required, items, anyOf, additionalProperties, format and examples — so the difference in practice is the declared $schema line. The drafts diverge on features this page does not generate, chiefly how tuple-style arrays and references are written.
Is my document uploaded to be analysed?
No. It is parsed with the browser JSON parser and walked in JavaScript in this tab. No request is made, nothing is stored, and closing the tab removes it. The usual input for a page like this is a real API response, so the answer matters more than it would for a formatting tool.