JSONPath Tester Online: Evaluate JSONPath Expressions, Filters and Wildcards
Paste JSON on the left and type a JSONPath expression; every match appears with its value and its exact normalised path, such as `$['user']['roles'][0]`. Click one of the example expressions to start. Full JSONPath works, including wildcards, recursive descent, array slices and filter expressions, and a plain dotted path such as `user.profile.email` is accepted as a shortcut for `$.user.profile.email`.
JSONPath syntax
JSONPath selects parts of a JSON document the way XPath selects parts of XML. Stefan Goessner proposed it in 2007, and in February 2024 the IETF standardised it as RFC 9535. An expression always starts at the root, $, and walks down through object members and array elements:
$ the whole document
$.store.book member access with dots
$['store']['book'] the same with brackets (needed for keys with spaces or dots)
$.store.book[0] first array element
$.store.book[-1:] last element (a slice)
$.store.book[0:2] elements 0 and 1 (end is exclusive)
$.store.book[*] every element
$.store.* every member of store
$..price every price at any depth (recursive descent)
$.store.book[?(@.price < 10)] filter: books cheaper than 10
Inside a filter, @ is the element being tested. Comparisons use ==, !=, <, <=, > and >=, conditions combine with && and ||, and [?(@.isbn)] keeps only elements that have an isbn member.
Querying arrays: examples on a sample document
Given a store with three books, { title, author, price }, where only the first and third have an isbn, and a red bicycle priced 19.95, the tester returns:
$.store.book[*].author ["Nigel", "Evelyn", "Herman"]
$..price [8.95, 12.99, 8.99, 19.95]
$.store.book[?(@.price < 10)].title ["Sayings", "Moby"]
$.store.book[?(@.isbn)].title ["Sayings", "Moby"]
$.store.book[?(@.author == "Evelyn")].price [12.99]
$..book[?(@.price > 9 && @.price < 20)].title ["Sword"]
$['store']['bicycle']['color'] ["red"]
A JSONPath query always produces a list of matches, even when it selects a single value, because the same expression may match zero, one or many nodes. That is why the tester shows an array with a path for every match: when a result is empty, check the path of a broader query, such as $.store.*, to see where the data actually is.
Engine differences to know
The tester uses jsonpath-plus, a widely used JavaScript implementation of Goessner's syntax. RFC 9535 is stricter and differs in a few details, and so do other libraries, which is the most common reason an expression that works in one tool returns nothing in another.
Negative indexes: RFC 9535 accepts [-1] for the last element, while Goessner-style engines, including this one, need the slice [-1:]. Filters: RFC 9535 writes filters without parentheses, [?@.price < 10]; Goessner-style engines expect [?(@.price < 10)]. Functions: RFC 9535 defines length(), count(), match(), search() and value(); older engines instead let filters use JavaScript expressions, which this tester evaluates in a safe sandbox without running arbitrary code. Test with the syntax of the library you will use in production.
JSONPath in tools you already use
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
SELECT JSON_EXTRACT(doc, '$.user.email') FROM events; -- MySQL
SELECT jsonb_path_query(doc, '$.items[*] ? (@.qty > 1)') FROM orders; -- PostgreSQL
Kubernetes uses JSONPath templates in curly braces and allows the leading $ to be omitted. MySQL's JSON functions accept a subset: member access, array indexes, * and ** wildcards, but no filters. PostgreSQL implements the SQL/JSON path language, which looks similar but puts filters after the path, ? (@ > 1), and has modes such as lax and strict. API testing tools such as Postman, REST Assured and Karate, and JSON assertions in many CI tools, use JSONPath or close variants.
jq is not JSONPath: .store.book[] | select(.price < 10) | .title does the same job with its own language. If you work mostly on the command line, learning jq is worth it; for configuration fields that expect a JSONPath string, test the expression here first.
Writing robust expressions
Prefer explicit paths over recursive descent in production code. $..id is convenient for exploring, but it also matches id fields in nested objects you did not mean, and a new nested object in the API response can silently change the result. Anchor filters on stable fields, quote keys that contain dots, dashes or spaces with bracket notation, and mind types in comparisons. In this engine == compares like JavaScript, so @.id == "42" also matches the number 42; use === for a strict match. RFC 9535 comparisons are always strict, so "42" never equals 42 there.
When a query returns nothing, build it up one step at a time: $.store, then $.store.book, then $.store.book[*], then the filter. The first step that returns an empty list is where the path and the data disagree.
Invalid JSON and privacy
If the JSON cannot be parsed, the tester shows the parser error instead of results; fix it in the JSON formatter, which points to the line and column. Documents, expressions and results stay in your browser, so API responses with tokens or customer data are safe to paste.
Frequently asked questions
What is JSONPath?
A query language for selecting values from JSON, similar to XPath for XML. Expressions start at $ and use dots, brackets, wildcards and filters. It was standardised as RFC 9535 in 2024.
How do I filter an array in JSONPath?
Use a filter expression with @ for the current element, for example $.store.book[?(@.price < 10)].title. Combine conditions with && and ||.
How do I get the last element of an array?
Use the slice $.items[-1:]. RFC 9535 also allows $.items[-1], but many engines, including the one used here, need the slice form.
What does $.. mean?
Recursive descent: $..price finds every price member at any depth of the document. It is useful for exploring but can match more than you intend.
Why does my JSONPath return an empty result?
The path does not match the structure, a key is misspelled or needs bracket notation, a comparison expects a different type than the data contains, or the engine expects different filter syntax. Build the path one step at a time to find where it stops matching.
Is JSONPath the same as jq?
No. jq has its own language with pipes and functions. They solve similar problems, but expressions are not interchangeable.