JSONPath tester — run an expression and see every match with its path

Paste JSON, type a JSONPath expression such as $.store.book[?(@.price < 10)].title, and see every matching value together with the exact path where it was found.

Live demo · real result from this tool
Supports $ . [] * .. slices [0:2] unions [0,1] and filters ?(@.price < 10 && @.category == 'fiction'), =~ /regex/.
Result2 matches

Matched values

[  "Sayings of the Century",  "Moby Dick"]

Matches with paths

PathValue
$.store.book[0].title"Sayings of the Century"
$.store.book[2].title"Moby Dick"

Processed on your device — nothing is uploaded.

How to use the JSONPath tester

  1. Paste your document into JSON. The sample is the classic bookstore example.
  2. Type an expression in JSONPath expression. It must start with $.
  3. Read the count under Result, then the Matched values as a JSON array.
  4. Use the Matches with paths table to see exactly where each value lives.

What it does and when to use it

JSONPath picks values out of a JSON document, the way XPath does for XML. It is used in API test tools, Kubernetes kubectl -o jsonpath, AWS Step Functions, log processors and many SDKs. Getting an expression right inside those tools is slow, because you often only see the final result. Here you see every match and its path as you type, so you can check a filter against real data before pasting it into a test or config.

If you only need to filter an array by field conditions, without JSONPath syntax, try JSON query. To list every path in a document so you know what to select, use the JSON key extractor. For a quick structural view first, the JSON formatter helps.

Syntax reference

Expression Selects
$.a.b or $['a']['b'] a child by name
$.list[0], $.list[-1] an item by index, negative from the end
$.list[0,2] several indexes (a union)
$.list[1:3], $.list[::-1] a slice, start to end (end excluded), optional step
$.a.*, $.list[*] every child
$..price price at any depth
[?(@.x > 5)], [?@.x] items passing a filter, or items that have x
[?(@.name =~ /^a/i)] regex match (tool extension)
[?(@.tags.length > 2)] length of an array, string or object (tool extension)

How it works

The selectors follow RFC 9535, minus its function extensions. The expression is compiled into a list of steps, and each step is applied to the current set of matches, starting from the root. A .. step visits every level below. Filters run once per array item or object member, with @ set to that item; $ inside a filter refers to the whole document. Matches keep document order. Everything runs in your browser.

Worked examples

With this data:

{"orders":[{"id":1,"total":25,"status":"paid"},
           {"id":2,"total":140,"status":"paid","coupon":"VIP"},
           {"id":3,"total":60,"status":"refunded"}]}
$.orders[?(@.status == 'paid' && @.total > 50)].id   →  $.orders[1].id | 2
$.orders[?@.coupon].id                               →  $.orders[1].id | 2
$.orders[-1:].status                                 →  $.orders[2].status | "refunded"
$.orders[*].total                                    →  3 matches: 25, 140, 60

An expression without the leading $, such as orders, returns A JSONPath starts with $ (at character 1).

Limits and tips

  • When a filter compares missing fields, two missing sides are equal, as RFC 9535 says, so @.x == @.y matches items that have neither; a missing field never equals a real value.
  • Very large documents with .. on many levels can take a moment, since every node is visited.

Frequently asked questions

Does this follow RFC 9535?
It follows the RFC 9535 selectors (names, wildcards, indexes, slices, unions, descendants and filters with == != < <= > >= && || !), and like the RFC it accepts filters with or without parentheses. It does not support the RFC function extensions match(), search(), length(), count() and value(). Instead it offers =~ /regex/ and .length, the older Goessner and Jayway style, so check expressions before moving them to a strict RFC library.
Why do I get no matches?
Keys are case-sensitive, so $.store.Book finds nothing when the key is book. Also check that you used [ ] for array positions, and that strings in filters are quoted. Comparing a number with a string, such as @.price < '10', is always false.
Can I do arithmetic in a filter?
No. A filter compares a value with a literal, another @ path or a $ path, but it cannot calculate. $.store.book[?(@.price < $.limit)] works if limit is in the document; @.price < $.limit / 2 is an error.
Which regular expression syntax does =~ use?
JavaScript RegExp, written between slashes with optional flags, such as /^j/i. It searches anywhere in the string, so anchor it with ^ and $ for a full match. Other JSONPath engines may use a different regex flavour, and RFC 9535 uses I-Regexp through match() and search().
In what form are the result paths shown?
As JavaScript-style accessors, like $.store.book[2].title, with keys that are not valid identifiers in brackets and quotes. RFC 9535 normalized paths use brackets for every step, like $['store']['book'][2]['title'], so convert if you compare with another tool.

Written by the ToolsRift team · Last updated

Pages are drafted with AI assistance and checked by automated tests. How we write and check pages.

Was this tool useful?

Report a problem

Start typing to search every tool.

↑ ↓ to moveEnter to openEsc to close