Test JSONPath expressions against any JSON document — filters, regex, recursive descent.
Updated
JSONPath expression
Try:
JSON input
Matches (0)
No matches for this path.
⌘EnterCopy values
⌘KReset path to $
Quick start
How to test a JSONPath expression
Paste JSON, type an expression, see resolved paths and matched values instantly.
Step 1
Paste JSON
Drop your document into the input pane, or click Load sample for the classic JSONPath bookstore example.
Step 2
Type an expression
Start with $ and walk into the tree. Use [*] for wildcards, .. for recursive descent, ?(...) for filters.
Step 3
Copy matches
Click Copy values (or ⌘/Ctrl + Enter) to grab the matched values as JSON. All evaluation runs locally.
In-depth guide
JSONPath tester — query nested JSON without eval()
Paste any JSON document and a JSONPath expression to see exactly which values it selects and where they live in the tree. The evaluator is a small hand-written parser — no eval(), no new Function() — so it's safe to feed untrusted expressions. Both inputs stay in your browser.
Syntax cheat sheet
Expression
Meaning
$
Root of the document
$.foo or $['foo']
Child by key
$.list[0]
Index (negatives count from end)
$.list[0,2,4]
Union — multiple indices or keys
$.list[1:5]
Slice (start, end, optional step)
$.list[*]
Every immediate child
$..author
Recursive descent — every author anywhere
$.list[?(@.price < 10)]
Filter expression
Filter expressions
Inside ?(...) you can compare keys to literals or to each other. @ is the current candidate; $ is the document root.
Operators: ==, !=, <, <=, >, >=, =~ (regex), &&, ||, !. A bare path like ?(@.isbn) is true when the key exists with a non-empty value.
How this differs from RFC 9535
RFC 9535 (February 2024) is the new canonical JSONPath spec. This tester implements the practical subset most users actually reach for. Differences to know:
No length() / count() / match() functions — use external post-processing.
The recursive-descent .. token includes the starting node itself, which matches most legacy implementations but is a known divergence from the strictest reading of the RFC.
Filter regex literals use the JS form /pattern/flags. A plain string on the right of =~ is compiled as a pattern with no flags.
Why this is safe with untrusted expressions
Many JSONPath libraries pass the body of ?(…) to eval() or new Function(). That makes them code-execution sinks: any string you accept from a user or external system runs with full JS privileges.
This implementation parses filter expressions by hand and only evaluates a fixed grammar of comparisons, regex matches and logical operators. Anything else is a syntax error. You can safely take a JSONPath expression from a URL query parameter, a form field or an API request without sanitising it.
Common pitfalls
Validate the output before committing it, especially when fixing almost-valid input.
Escaping, comments, trailing commas, and mixed encodings are the usual source of surprising results.
For production config, keep a copy of the original until the consuming system accepts the rewritten file.
Privacy and security
Browser-first by design. The tool page explains any exception before you use it.
Pasted code and data are processed locally in the page. EpitomeTool does not send your input to a formatting, validation, or conversion API.
Frequently asked questions
Is my JSON uploaded to a server?
No. Both the JSON parse and the JSONPath evaluation run entirely in your browser as JavaScript. Nothing is sent over the network.
Which JSONPath dialect does it implement?
The common Stefan Gössner dialect popularised in 2007 and partly standardised in RFC 9535. Supported syntax: `$` root, `.name` or `['name']` child, `[n]` index (negatives count from end), `[a,b,c]` union, `[start:end:step]` slice, `[*]` wildcard, `..` recursive descent, `?(...)` filter.
Which filter operators are supported?
Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`. Regex match: `=~` (right-hand side is a string or `/pattern/flags`). Logical: `&&`, `||`, `!`. Inside filters, `@` is the current candidate and `$` is the JSON root. Bare paths like `?(@.isbn)` are truthy when the key exists with a non-empty value.
Why does my filter return nothing?
Three common causes: (1) the path before `?(` must point at an array or object — the filter tests each child. (2) strings must be quoted: `?(@.category == 'fiction')`, not `== fiction`. (3) regex literals use `/pattern/flags` syntax: `?(@.isbn =~ /^0-/)`.
What's the difference between [*] and ..?
`[*]` matches the immediate children of one level. `..` recursively descends into every nested object and array. So `$.store.book[*]` gives the four book objects, but `$..book` finds the `book` key wherever it appears in the tree.
How are negative indices handled?
`[-1]` is the last element; `[-2]` the second-from-last. Slices accept negatives too: `[-3:]` is the last three elements, `[:-1]` is everything except the last.
Is filter scripting (?(...)) safe?
Yes — this implementation uses a hand-written parser, not `eval()` or `new Function()`. Only the supported operators above are honoured. Anything else is a syntax error rather than arbitrary code execution. (Many older JSONPath libraries do use `eval()` and should not be fed untrusted expressions.)
Does it match the RFC 9535 spec exactly?
Close, but not byte-identical. RFC 9535 (Feb 2024) tightened several edge cases (canonical output ordering, function syntax, name-shorthand grammar). This tool covers the productive subset most users actually need; for spec-conformance work, cross-check with a reference engine like jsonpath-rfc9535.
Keep exploring
More tools you'll like
Hand-picked utilities that pair well with the one you're on — all
free, client-side, and zero-signup.