JSONPath Tester: Evaluate JSONPath Expressions Online

Type a JSONPath expression and watch every match highlight inside the document tree, with a cheatsheet, ready-made queries and copy or CSV export.

🌐 Español

JSON document

Try:

4 matches found.

Tree view

Object · 1 entry

Matches

$['store']['book'][0]['author']: "Nigel Rees"
$['store']['book'][1]['author']: "Evelyn Waugh"
$['store']['book'][2]['author']: "Herman Melville"
$['store']['book'][3]['author']: "J. R. R. Tolkien"
JSONPath syntax cheatsheet
$The root of the document.
.propertyA child property, e.g. $.store.bicycle. Bracket form also works: ['property'].
..propertyRecursive descent — that property at ANY depth in the document, not just directly under the current node.
*Wildcard — every property of an object, or every element of an array.
[n]The array element at 0-based index n. A single NEGATIVE index (e.g. [-1]) is not supported — use a slice like [-1:] instead.
[n,m]Multiple specific array indices at once, e.g. [0,2].
[start:end]An array slice (end exclusive). Negative bounds ARE supported here, e.g. [-1:] for "just the last element".
[?(expression)]A filter — keep only the elements for which the expression is truthy.
@Inside a filter expression, the current element being tested.

🔒 Private by design: everything runs locally in your browser and never uploaded to any server.

The bookstore document, and why it is the one loaded

The sample sitting in the document box when the page opens is the bookstore object from Goessner’s original JSONPath article: a store containing four books with a category, an author, a title, a price, and an ISBN on two of them, plus a red bicycle. Nearly every JSONPath implementation uses it in its own documentation, so an expression you found in a Stack Overflow answer or a library README can usually be pasted here and tried against the exact data its author had in mind. The starting expression, $.store.book[*].author, returns all four authors.

  1. Paste your own JSON into the JSON document box, or leave the sample in place while you learn the syntax.
  2. Type into the JSONPath expression box and watch the summary line, the highlighted Tree view and the Matches panel update as you type.
  3. Click any of the ready-made queries in the Try row to drop a working expression into the box, or open the JSONPath syntax cheatsheet at the foot of the page for the operator list.
  4. Press Copy match list, Download .txt or Download .csv to take the results with you. All three are disabled while there are no matches.
  5. Load sample puts the bookstore document and the starting expression back if you want to experiment from a known state.

Recursive descent finds more than you asked for

The .. operator is the one that most often surprises people, and the sample shows why in two queries. $..author returns four results, because only books have authors. $..price returns five: the four books, and then the bicycle’s price, which is nowhere near the part of the document you were thinking about. Recursive descent means every property with that name at any depth, and a document large enough to be worth querying is usually large enough to hide a second property with the same name somewhere unrelated.

That is precisely the class of bug the tree matters for. The Matches panel gives you the values; the tree beside it shows you where in the document each one lives, with every ancestor of every match already unfolded so nothing is hiding behind a collapsed arrow. Seeing the bicycle’s price light up next to the books is faster than reading a flat list of five numbers and wondering why there is one too many.

Filters, and the evaluator that runs them

A filter such as $..book[?(@.price<10)] keeps only the elements for which the expression is true, with @ standing for the element under test. Against the sample, that one returns two books. Presence checks work the same way: $..book[?(@.isbn)] keeps the two books that have an ISBN. Conditions combine, so $..book[?(@.price<10 && @.category=="fiction")] narrows to a single book, Moby Dick. A filter always attaches to something that selects the elements it tests, so the bracket on its own, with no path in front of it, matches nothing at all.

Running a filter means executing something the visitor typed, which historically meant some JSONPath libraries reached for the browser’s eval. This one does not. The default safe evaluator parses the filter into a syntax tree and interprets it with a restricted walker that knows about comparisons, boolean operators and member access and nothing else. There is also a tolerance built in for filters that read a property some elements do not have: rather than aborting the whole query, an element whose test cannot be evaluated is simply treated as not matching, which is why $..book[?(@.foo.bar)] returns zero matches instead of an error.

Three states, kept honestly separate

A query here ends in one of three places, and they are never disguised as one another. There is a genuine parse error, shown as a message with the tree and the results hidden. There is a syntactically acceptable expression that matches nothing, shown as an explicit statement that no matches were found rather than as an empty panel. And there is a result, shown as a count plus the matches themselves. Empty the expression box completely and the summary drops back to inviting you to type one.

The middle state is where the leniency of the parser shows. $.store.book[*].nope matches nothing because no such property exists, which is the answer you wanted. $.store.book[-1] also matches nothing, but for a much less obvious reason: a single negative index is not implemented, and the slice [-1:] is what you need instead. Meanwhile $.store.book[ returns the whole book array without complaint. All three land in the same “no error” bucket, so a zero or a suspicious result is always worth rereading rather than trusting. As a smaller curiosity, $..book.length returns 4 here, which is a property of the JavaScript array rather than anything the JSONPath specification promises, so do not carry that trick to another implementation.

Taking the answer somewhere else

Once an expression does what you want, the Matches panel is already in a shape you can use. Each line is the bracket-notation path followed by the matched value as compact JSON, which pastes straight into a ticket or a chat message. The CSV export is the same information with path and value columns for a spreadsheet, and the text export is the panel verbatim.

An expression is often only one step. If the document you are querying is too large to read in the box, open it in the JSON Tree Viewer first, which takes a .json file and collapses the parts you do not care about. Once you have found the field, change it in the JSON Editor rather than hand-editing raw text. If a query surprises you because the document is not shaped the way you assumed, the JSON Schema Validator will tell you whether it matches the contract at all, and JSON Diff will tell you whether it changed since the last time your query worked. For a document that arrived minified, run it through the JSON Formatter before pasting so the document box is easier to read. The tree is rebuilt from the parsed structure either way, so indentation changes nothing about it.

See it in action

Screenshot of the JSONPath Tester: Evaluate JSONPath Expressions Online tool with a sample JSON document loaded on the left and a JSONPath expression evaluated against it live on the right, with the matched nodes listed as results
JSONPath Tester: Evaluate JSONPath Expressions Online mid-process: a sample JSON document loaded on the left and a JSONPath expression evaluated against it live on the right, with the matched nodes listed as results.
Diagram: where the work happens on a SysFenix page that has no file input at all: the tool arrives as ordinary JavaScript inside the page, works the answer out on your own device and renders it in place, so the upload, queue and server-side record a typical online tool needs never happen
Where the work happens on a SysFenix page that has no file input at all: the tool arrives as ordinary JavaScript inside the page, works the answer out on your own device and renders it in place, so the upload, queue and server-side record a typical online tool needs never happen.

Frequently asked questions

Does an expression have to be submitted before it runs?

No. Both the document box and the expression box are read on every keystroke, so a half-typed expression is already being evaluated and the match count moves as you finish it. That is deliberate; watching the count jump from zero to four as you add one more segment tells you more about an expression than a single run at the end does.

Why does a bracket left open produce a result instead of a complaint?

Because the engine underneath is lenient with several kinds of malformed input rather than strict. Typing $.store.book[ against the sample document returns one match, the whole book array, since the unfinished bracket is effectively discarded. Only input the parser genuinely cannot make sense of raises an error, so treat a surprising result as a reason to reread your expression, not as proof it parsed the way you meant.

What does a genuine syntax error look like here?

A message above the results naming the problem and where in the expression it sits. Leaving a comparison unfinished, as in a filter reading @.price< with nothing after it, reports that an expression was expected after the less-than sign at a specific character offset. While that message is showing, the tree and the match list are hidden entirely, so there is never an old result left on screen pretending to belong to the broken expression.

Why does [-1] find nothing when it should mean the last element?

Because a single negative index is not implemented by the engine this page uses, and it fails by matching nothing rather than by complaining. The slice form does work, so ask for the last element as [-1:], which is one of the ready-made queries you can click. It is a real limitation of the implementation rather than of JSONPath itself, and worth remembering if you are copying an expression to somewhere that behaves differently.

In what format are matched paths reported?

In bracket notation with quoted keys, so an author inside the first book of the sample comes back as a dollar sign followed by the four steps ['store'], then ['book'], then [0], then ['author'], and then the matched value. The form is verbose but unambiguous, which matters for keys containing dots or spaces that dot notation cannot express. The same paths make up the two exports, as one line each in the text file and as a path column in the CSV.

Can a filter expression run arbitrary code from whatever I paste?

No. The library is used in its default safe mode, which parses a filter into a syntax tree and walks it with a small interpreter that understands comparisons, boolean operators and property access. Neither the browser's eval nor the Function constructor is involved, and the one place in this tool that calls the library passes a fixed set of options, so the opt-in native mode that would use them cannot be reached from the page at all.

Related tools