JSONPath Tester
Developer Tools · Added
Write a JSONPath expression, see what it selects, and get the normalised path of every match — which is the part you paste into the code that has to fetch it for real. It implements the subset that behaves identically across implementations and RFC 9535, and refuses anything outside that with a message rather than quietly returning nothing.
3 matches
- Matches
- 3
- Nodes examined
- 9
- Result shape
- list
A recursive descent walks the whole document
| Path | Value |
|---|---|
| $['store']['book'][0]['title'] | Sayings of the Century |
| $['store']['book'][1]['title'] | Sword of Honour |
| $['store']['book'][2]['title'] | Moby Dick |
JSONPath was a blog post in 2007 and only became a specification — RFC 9535 — in 2024, so implementations still disagree at the edges. This supports the subset that behaves the same everywhere: child access, indexes including negative ones, slices, the wildcard, recursive descent, and single-comparison filters. Script expressions and functions are refused with a message rather than guessed at, because a query that works here and nowhere else would be worse than none. Everything runs in this tab; the document is never uploaded.
How to use the jsonpath tester
- 1Paste your JSON, or use the sample document.
- 2Write a path, or press one of the examples to see a feature.
- 3Read the matches — each row shows the value and the exact path to it.
- 4Copy the values as JSON, or the paths for your code.
Examples
Every value at any depth
- Input
- $..price
- Result
- Four matches, each with its own path: three book prices and the bicycle's
A filter
- Input
- $.store.book[?(@.price < 10)]
- Result
- The two books under ten, as whole objects with their array indexes
Something it will not guess at
- Input
- $.book[?(@.title.match(/^S/))]
- Result
- Refused, with the reason: script expressions are not portable between implementations
An empty result meaning “no matches” and one meaning “I did not understand” are different answers.
About the jsonpath tester
Why JSONPath has dialects at all
XPath had a specification before it had implementations. JSONPath had it the other way round: Stefan Gössner's 2007 article sketched a syntax, people implemented it in a dozen languages, and each resolved the ambiguities differently. Does a filter on a non-existent field match or skip? Does a negative index count from the end everywhere or only in arrays? Does $..* include the root? Different libraries answer differently, and all of them are defensible readings of the original.
RFC 9535 settled it in 2024, but the installed base did not vanish. So the practical advice for anything that has to run in more than one place is to stay inside the intersection — which is what this tool implements and why it declines to extend past it.
Recursive descent is expensive, and worth knowing when
$..price reads as a small query and is not. It walks every node in the document looking for the key, so its cost is the size of the whole document rather than the depth of the path. On a configuration file that is instant; on a large API response inside a loop it is the reason a script is slow.
The nodes-examined figure here is there for that reason. A path with an explicit prefix — $.store..price rather than $..price — narrows the search before the descent begins, and the difference in that number shows what it saved. Where the shape is known, spelling it out is faster and it also documents the assumption for whoever reads the code next.
When a query returns nothing
An empty result has two completely different causes, and a tool that renders both as a blank panel is unhelpful. Either the path was understood and matched nothing — a statement about your document — or it was not understood at all.
This separates them: a path it cannot parse produces an error naming the problem, and a path that parses and finds nothing says so explicitly. The usual causes of the second are a spelling difference, an array where an object was expected, or a filter comparing a string to a number. That last one is silent in most implementations: `[?(@.price > '10')]` compares a number to a string, and this refuses to order values of different types rather than inventing a result.
Frequently asked questions
Which JSONPath does this implement?
Why refuse script expressions instead of trying?
What is the difference between .. and *?
Why show the path of each match rather than just the value?
Is my JSON uploaded anywhere?
Related tools
JSON Formatter
Developer Tools
Pretty-print, minify and inspect JSON with precise error positions.
JSON Diff
Developer Tools
Compare two JSON documents by structure — key order and formatting ignored, type changes called out.
JSON Validator
Developer Tools
Check JSON validity and get a structural summary — depth, key count and type breakdown.
ASCII Table
Developer Tools
Searchable ASCII reference with decimal, hex, octal, binary and escapes.