JSONPath tester
Test JSONPath expressions against sample JSON with live match counts and per-node copy.
Paste a JSON document on the left, type a JSONPath expression above it, and the matches appear on the right as an expandable tree — each one labelled with the concrete path it was found at, such as $.store.book[2].author, not just the expression you wrote. The match counter updates on every keystroke, so an expression that returns nothing tells you immediately rather than after a round trip. Invalid JSON is reported with the parser's own message and the character offset, which is usually enough to find a trailing comma without leaving the page. Three sample documents are built in: a bookstore for path and wildcard practice, a user list for filter expressions, and a small nested object for recursive descent.
Key facts about JSONPath tester
| Syntax supported | $ root, dot child, bracket child with single or double quotes, wildcard as .* or [*], recursive descent .., array index, negative index, slice [start:end], and filter [?(...)] |
|---|---|
| Filter expressions | @.field comparisons evaluated as JavaScript, so ==, !=, <, >, && and || all work — for example [?(@.age>30 && @.active==true)] |
| Filter depth | One level: @.role is substituted, @.address.city is not. Filters apply to arrays only |
| Not supported | Union selectors such as [0,2], slice step [::2], script expressions like [(@.length-1)], and function extensions such as .length() or count() |
| Match paths | Every result is shown with its resolved path, and each node inside the result has its own copy-path button |
| Match modes | All matches, or first match only — the counter always reports the full total |
| Result tree | Objects and arrays collapse and expand, with key and item counts shown while collapsed; strings over 150 characters are clipped to one line until you click them |
| Type colouring | Strings, numbers, booleans and null are coloured separately so a numeric value quoted as a string is visible at a glance |
| Sample documents | 3 — bookstore ($.store.book[*].author), users ($.users[?(@.role=="admin")].name) and a nested object ($..value) |
| Input | Typed or pasted text, or the Paste button which reads the clipboard directly. There is no file picker and no drag-and-drop |
| Size limit | None imposed by the page — the practical ceiling is how much JSON your browser will parse and render in one tab |
| Error handling | A JSON syntax error and a bad path are reported separately, so you always know which half of the screen is wrong |
What happens to your file
The JSON stays in the tab. Parsing is the browser's own JSON.parse, and the path evaluation is a tokeniser and a recursive walker written into the page bundle — there is no JSONPath service, no library downloaded at runtime and no request of any kind while you type. That matters here more than on most pages, because the document you are testing against is usually a real API response with real customer data in it. Nothing is written to local storage either, so a refresh clears both panels. Filter expressions are evaluated with a JavaScript Function built from your own input, which is why you should only paste filters you wrote or understand.
About this tool
- 1
Load a document
Paste your JSON into the left panel, use the Paste button to pull it from the clipboard, or start from one of the three samples while you work out the syntax.
- 2
Check it parses
If the JSON is malformed, the red box under the editor shows the browser's own parser message and position. Fix that first — no path can match a document that did not parse.
- 3
Write the expression
Start at $ and build downward: $.users to reach the array, $.users[*] for every element, $.users[*].email for one field of every element. The counter beside the field tells you how many nodes matched.
- 4
Narrow it with a filter
Add a predicate to select instead of enumerate: $.users[?(@.active==true)].name. Filters work on arrays and compare one field at a time.
- 5
Read the resolved paths
Each match is headed by the path it was actually found at. This is the fastest way to confirm that a recursive $..price is reaching the nodes you intended and not a similarly named field three levels down.
- 6
Take the result with you
Copy a single value, copy all matches as one JSON array, or copy an individual node's path to paste into your own code.
| Parser | Native JSON.parse for the document; a hand-written tokeniser for the path |
|---|---|
| Standard | The widely used Goessner-style JSONPath, not the stricter RFC 9535 grammar — behaviour on edge cases may differ from a server-side library |
| Slice support | [start:end] only; step is ignored and negative bounds are unreliable |
| Filter evaluation | JavaScript expression semantics, so string comparison is exact and type coercion follows JavaScript rules |
| Output | Expandable tree per match, copy value per match, copy all matches as JSON, copy path per node |
| Clipboard | Read (Paste button) and write (copy buttons) via the Clipboard API — Safari may prompt on read |
| Network | None after page load; works offline |
| Browsers | Any current browser; no WebAssembly, no worker, no file access |
- Build the expression one segment at a time and watch the match count. The segment where the count drops to zero is the segment that is wrong — usually a key that is nested one level deeper than you remembered.
- Recursive descent is a blunt instrument: $..id matches every id anywhere in the document, including ones inside unrelated objects. Check the resolved paths on the results before you trust it in code.
- String comparisons in filters are exact and case-sensitive. [?(@.role=="Admin")] will not match a value of admin.
- Filters only reach one level. To select on a nested field, walk down to the array that contains it first rather than writing @.user.role inside the predicate.
- Switch to First match when you only care whether anything matched at all; the counter still shows the true total, so you lose no information.
- A negative index works for the last element: $.users[-1] is a shorter and safer way to say the end of the array than counting.
- Use the copy-path button on a node you found by browsing the tree — it gives you a working expression for that exact node without writing one.
- Different JSONPath implementations disagree on unions, steps and filter semantics. Once an expression works here, run it once against the library your service actually uses before shipping it.
- Live match count while you type
- Resolved path for every match
- Filter, wildcard and recursive-descent support
- Collapsible result tree with type colouring
- Copy value, copy all, copy path
- Clipboard paste for the document
- Three worked sample documents
- Work out the expression for a field in an API response before wiring it into a test assertion or an integration step.
- Check what a JSONPath in an existing configuration file actually selects when the payload shape has changed.
- Pull one field out of every element of a long array and copy the whole set as a JSON list.
- Explore an unfamiliar response by browsing the tree and copying the path of anything interesting.
- Debug an automation rule that silently matches nothing by testing its path against a real captured payload.
- Teach JSONPath syntax with the bookstore sample, where each operator has a visible effect on the match list.
Related tools
View allWorks well with this6
More in Data & Dev12
Updated