Skip to content
AgileLogics

JSON Path Tester

Runs a JSONPath expression against a JSON document and shows every matching value.

Working on a whole file? Open it in the JSON editor →

How it works

Paste JSON into the input panel, enter a JSONPath expression in the second panel (e.g. $.store.book[*].title), and click Test.

Running a JSONPath query

JSONPath is a small query language for JSON, in the same spirit as XPath for XML. A path starts at $ (the whole document) and steps down through keys and array positions, with wildcards, recursive search and filters for picking items by value. This tester runs one expression against the JSON you paste and returns every matching value as a JSON array.

There are two main flavours. The original syntax comes from Stefan Goessner's 2007 article. In 2024 the IETF standardised a stricter version as RFC 9535. This tool uses the jsonpath-plus library (version 11), which follows the original syntax and adds some extensions.

Sample data and verified results

{"orders": [
  {"id": 101, "customer": "Lee", "total": 42.5, "items": [{"sku": "PEN", "qty": 3}, {"sku": "INK", "qty": 1}]},
  {"id": 102, "customer": "Ruiz", "total": 310, "status": "refunded", "items": [{"sku": "DESK", "qty": 1}]},
  {"id": 103, "customer": "Okafor", "total": 18.99, "items": []}
]}
Expression Result What it does
$.orders[*].id [101, 102, 103] Every order's id
$..sku ["PEN", "INK", "DESK"] Recursive descent: sku at any depth
$.orders[0:2].id [101, 102] Slice: indexes 0 and 1
$.orders[-1:] the Okafor order Last element via a slice
$['orders'][0]['customer'] ["Lee"] Bracket notation, handy for keys with spaces
$.orders[?(@.total > 40)].customer ["Lee", "Ruiz"] Filter on a value
$.orders[?(@.status)].id [102] Filter on a key existing
$.orders[?(@.total > 40 && @.id > 101)].id [102] Combined conditions
$.orders[?(@.items.length == 0)].id [103] Array length inside a filter
$.orders[*].items[*].qty [3, 1, 1] Nested wildcards
$.orders[*]~ [0, 1, 2] Extension: return keys/indexes instead of values

Steps

  1. Paste the JSON document into the first box. If it doesn't parse, you'll see "Enter valid JSON in the first field."; the JSON validator shows where it breaks.
  2. Type the expression into the second box, starting with $.
  3. Click Test. Matches appear as a two-space indented JSON array.
  4. "No matches found for that JSONPath expression." means the path is syntactically fine but selects nothing. Shorten it step by step until something matches, then add the next step back.

Differences from RFC 9535

If you're writing paths for a system that follows the RFC (some newer libraries and databases do), test the edge cases there too. These differences were confirmed with this tool:

Expression RFC 9535 Here
$.orders[-1] Last order No match; use [-1:]
$.orders[?@.total > 40] Filter without parentheses No match; write ?(...)
$.orders[?(length(@.items) == 0)] Function extension Error: length is not defined
$.orders[?(search(@.customer, "^O"))] Regex function Error: search is not defined
$.orders.length No match (not a member) [3], read as an array property
orders[0].id (no $) Invalid Accepted, [101]

The =~ regex operator found in some other implementations isn't supported either; it gives an "Invalid left-hand side in assignment" error.

Things to watch

Malformed paths are rejected before the query runs. The underlying library is lenient and would read an unfinished expression like $.orders[ as $.orders, so the tester checks the structure first: brackets and parentheses must pair up, quoted names must be closed, [] can't be empty, and the path can't end in . or contain .... $.orders[ gives "Invalid JSONPath expression: the "[" at character 9 is never closed with "]"." This check is structural only, so a well-formed path with a misspelled key still just finds no matches.

Results are values, not locations. You get the matched values, not their paths. To see where in the document a value sits, browse the data in the JSON/XML tree viewer.

Large numbers. The document is read with JSON.parse, so integers beyond 2^53 - 1 lose precision in the output, the same as anywhere else in JavaScript.

Putting results to work

A common use is pulling a clean array of records out of a nested API response before handing it to another tool. $.orders[*] turns the sample above into a flat list of order objects that the JSON to Excel converter can turn into a spreadsheet. If your data is XML, the XPath evaluator does the same job with XPath 1.0.

Last updated

Frequently asked questions

Which JSONPath syntax does it use?
The jsonpath-plus library, which follows Stefan Goessner's original JSONPath syntax plus a few extensions. That's what most JavaScript tools and many online examples use. It is not a strict implementation of RFC 9535, so a few RFC-style expressions behave differently (see the comparison table).
Why does $.items[-1] return nothing?
In this implementation a single negative index doesn't count from the end. Use a slice instead: $.items[-1:] returns the last element (inside an array, like every result).
Why must filters have parentheses?
Goessner-style filters are written ?(...), as in $.orders[?(@.total > 40)]. The RFC 9535 form without parentheses, [?@.total > 40], returns no matches here.
Why is my result always wrapped in square brackets?
JSONPath can match any number of values, so the tool always returns a JSON array of matches, even when there's only one.
Is my JSON sent anywhere?
No. The query runs in your browser with the jsonpath-plus library, and nothing is uploaded.