Command Palette

Search for a command to run...

JSONPath Tester: Query Any JSON Without Writing a Loop

JSONPath Tester: Query Any JSON Without Writing a Loop

T
Toolz Team
|Aug 23, 2026|14 min read

Part of the Data Tools collection

The first time I wrote a JSONPath expression that mattered, I got it wrong three times before it worked, and I only knew it was wrong because the API gateway I was configuring returned an empty policy instead of the field I wanted. There was no feedback loop. I would edit the expression, redeploy, and wait. Once I started keeping a JSONPath tester open in another tab, that same work took two minutes instead of an afternoon. This guide is about how I use the JSONPath Tester on toolz.dev, what the syntax actually does, and the small traps that make an expression return nothing when you were sure it should match.

TL;DR: JSONPath is a query language for JSON, the way XPath is for XML. A JSONPath tester evaluates an expression like $.store.book[*].author against a document and returns every matching value plus its path. The JSONPath Tester does this entirely in your browser, with support for wildcards, recursive descent, slices, unions, and filter expressions, so you can build and debug a query against real data before you paste it into code.

What is JSONPath?

JSONPath is a compact syntax for selecting parts of a JSON document. You write a short path that describes a route through the data, and evaluating it returns the value or values at that route. The idea comes from Stefan Goessner's 2007 proposal, which deliberately mirrored XPath so that anyone who had queried XML would feel at home. For years there was no formal specification, just that article and a family of implementations that mostly agreed, and in early 2024 the IETF published RFC 9535 to pin the grammar down.

You meet JSONPath more often than you might expect. It is the selector language in API testing tools like Postman and Karate, in Kubernetes kubectl output formatting, in AWS CloudWatch and Step Functions, in log processors, and in dozens of low-code platforms where a user needs to pull one field out of a webhook payload without writing code. Learning it once pays back across all of those.

The mental model is simple. A JSON document is a tree. Objects have named branches, arrays have numbered branches, and the leaves are your scalar values. A JSONPath expression is a set of directions for walking that tree, and the result is every leaf or subtree you land on. Where it gets powerful is that a single expression can land on many places at once.

What does a JSONPath tester actually do?

A tester takes two inputs, your JSON and an expression, and shows you every node the expression selects. That sounds obvious, but the value is in the feedback. When an expression returns nothing, or returns more than you expected, a tester turns a guessing game into a two second check, because you can see exactly which nodes matched and adjust one character at a time.

On toolz.dev the flow is short. Paste a JSON document, or load the sample bookstore that most JSONPath tutorials use, type an expression, and evaluate. The tool lists each matched value with a running count, and you can switch the output between three views. Values gives you just the results as a JSON array. Paths gives you the normalized location of every match, which is the quickest way to discover the expression you actually need. Entries gives you both together, so you can see the path and the value side by side.

The reason to test against real data rather than reason about it in your head is that JSON from the wild is messier than the examples. A field is sometimes an object and sometimes an array. A key you expected is missing on half the records. A number arrived as a string. Running the expression against the actual payload surfaces those surprises immediately instead of at deploy time.

How do I select items from an array?

Arrays are where most JSONPath work happens, and there are four ways to address them.

A single index selects one element. $.store.book[0] returns the first book, and JSONPath, like most languages, counts from zero. A negative index counts from the end, so $.store.book[-1] returns the last book without you needing to know how many there are. That negative form is genuinely useful when you want the most recent item in a log or the latest entry in a feed.

A wildcard selects every element. $.store.book[*] returns all four books, and $.store.book[*].author returns the author of each, giving you a clean array of authors. The wildcard also works on objects, where $.store.* returns every value of the store object regardless of key.

A union selects a specific set. $.store.book[0,2] returns the first and third books, and the same comma syntax works with names, so $['store']['bicycle'] and bracket-quoted keys let you address keys that contain spaces or punctuation that the dot form cannot.

A slice selects a range, borrowing Python's start:end:step form. $.store.book[:2] takes the first two, $.store.book[1:3] takes a middle range with the end index exclusive, $.store.book[::2] takes every second element, and $.store.book[::-1] reverses the array. Slices are the least known part of the syntax and the one that saves the most typing once you have it.

What does the double dot do?

The double dot is recursive descent, and it is the feature that makes JSONPath feel like a search rather than a path. $..author finds every author key anywhere in the document, no matter how deeply it is nested, and $..* returns every value at every level. When you do not know the exact shape of a document, or when the same field appears at several depths, recursive descent finds all of them in one expression.

Consider the sample bookstore. $..price returns five values, the four book prices and the bicycle price, because it descends into every object and collects every price it finds. A plain $.store.book[*].price would return only the four book prices, because it walks a fixed route. The difference between those two expressions is the difference between asking for prices in a known location and asking for prices anywhere.

Recursive descent is powerful enough to be dangerous, in the sense that it can match more than you meant. That is exactly why a tester matters here. Run $..name against an unfamiliar payload and you might discover it matches a user name, a product name, and a file name that you had no idea shared a key. Seeing the paths in the output tells you whether to narrow the expression before you rely on it.

How do filter expressions work?

A filter keeps only the elements for which a condition is true, and it is written [?(...)] with @ standing for the current element. $.store.book[?(@.price < 10)] returns the books cheaper than ten. Inside the filter you can compare a field against a literal with the operators ==, !=, <, <=, >, and >=, test for the mere presence of a field, and combine conditions with && and ||.

A few concrete examples make the shape clear:

  • $.store.book[?(@.category == "fiction")] selects the fiction titles.
  • $.store.book[?(@.price < 10 && @.category == "fiction")] narrows to cheap fiction.
  • $.store.book[?(@.isbn)] selects only the books that have an ISBN, using existence rather than comparison.
  • $.vals[?(@ > 2)] filters a plain array of numbers, where @ on its own refers to the element itself.

The single most common filter bug is a type mismatch. In JSON, "12" and 12 are different values, so a filter that compares a numeric field to a quoted number, or a string field to a bare number, silently matches nothing. When a filter surprises you, the first thing to check is whether the field and the literal are the same type. Testing the expression against the real data, where you can see the actual values, is how you catch that in seconds instead of after a failed deploy.

JSONPath versus JSON Pointer versus a JSON diff

These three tools all touch JSON structure, but they answer different questions, and picking the wrong one wastes time. Here is how they compare:

Approach Answers Matches Best for
JSONPath Which nodes satisfy this query? Zero, one, or many Extracting fields, filtering arrays, exploring unknown shapes
JSON Pointer (RFC 6901) What is at this exact location? Always exactly one Referencing a single fixed field, as in JSON Schema $ref
JSON diff What changed between two documents? A set of changes Comparing two versions of the same data

JSON Pointer, defined in RFC 6901, addresses one precise place with a slash-separated path like /store/book/0/title, and it never uses wildcards or filters. Reach for it when you need to name a single field unambiguously. Reach for JSONPath when a single expression should select a set of fields. And when your real question is what differs between two payloads rather than what a query selects, a JSON Diff is the right tool. Knowing which of the three you actually need is half the battle.

Why does my expression return no results?

An empty result almost always comes from one of a handful of causes, and a tester lets you rule them out quickly.

The first is a structural mismatch. You wrote $.data.items.name when items is an array, so you needed $.data.items[*].name with a wildcard. The dot form walks into an object, and an array is not an object with a name key, so the path dead-ends. Switching the output view to paths and stepping the expression one segment at a time shows you exactly where it stops matching.

The second is a spelling or casing error. JSON keys are case sensitive, so $.userId will not match a userID field, and a trailing space or a typo in a key name produces the same silent nothing. Because the tester shows you the document right next to the expression, these are fast to spot.

The third, as covered above, is a filter type mismatch, where a numeric comparison runs against a string value or the reverse. The fourth is assuming a key exists on every element when it exists on only some. Recursive descent and existence filters are the usual remedies. In every case, the fix comes from watching which nodes the expression touches, which is precisely what a tester is for.

If you build across the stack the way I do, moving between a Laravel API, a React front end, and the occasional shell script, JSONPath shows up in all three, and a browser-based tester that never uploads your data is the tool I keep closest. I wrote about how utilities like this fit into a wider kit in the web developer toolkit, and the case for keeping this kind of work client-side is in the data privacy in online tools guide.

How does this fit with the rest of my JSON workflow?

A JSONPath tester is rarely the only tool open. When the JSON I am querying arrived minified or with inconsistent indentation, I run it through the JSON Formatter first so I can read the structure while I write the expression. The formatter and the tester together are how I go from an unreadable API response to a working query.

Once I know which fields I care about, the next step is often to reshape them. If I need to feed the selected values into a spreadsheet or an environment file, the JSON Flattener turns the nested structure into dot-notation keys, and its path syntax is close enough to JSONPath that the two reinforce each other. If I am building a type for the data in TypeScript, the JSON to TypeScript converter generates the interface, and if I need to validate the shape rather than just read it, the JSON Schema Generator produces a schema I can add constraints to. JSONPath is the exploration step; these tools are what I do with what I find.

The privacy point is worth repeating because JSONPath work so often happens against sensitive data. API responses carry tokens, user records, and internal IDs, and pasting them into a server-side tool means trusting someone else's logs. Because the toolz.dev tester parses and evaluates entirely in your browser, none of that leaves your machine, and the tool keeps working with the network disconnected. That is the difference between a tool you can use on a staging payload and one you can use on the real thing.

Frequently asked questions

What is JSONPath used for?

JSONPath is used to select and extract parts of a JSON document with a single expression. It is the query language in API testing tools, Kubernetes output formatting, cloud services like AWS Step Functions, and many low-code platforms, wherever someone needs to pull a field or filter an array out of a JSON payload without writing procedural code.

How do I select every element of an array in JSONPath?

Use the wildcard, so $.items[*] returns every element of the items array and $.items[*].id returns the id of each. You can also select one element by index with $.items[0], the last element with the negative index $.items[-1], a set with a union like $.items[0,2], or a range with a slice like $.items[1:3].

What does the double dot mean in JSONPath?

The double dot is recursive descent, which searches at any depth. $..author finds every author key anywhere in the document no matter how deeply nested, and $..* returns every value at every level. It is the fastest way to pull a field out of a document whose exact structure you do not know in advance.

How do filter expressions work in JSONPath?

A filter [?(...)] keeps only the elements for which a condition is true, with @ referring to the current element. For example $.book[?(@.price < 10)] returns books cheaper than ten, and you can combine conditions with && and ||, such as [?(@.price < 10 && @.category == "fiction")]. You can also test for a field's existence with [?(@.isbn)].

Why does my JSONPath expression return nothing?

The two most common causes are a structural mismatch and a type mismatch. Check that each key exists and is spelled with the exact casing, and that you used a wildcard where the data is an array rather than an object. In filters, remember that "12" and 12 are different values, so compare a string field to a quoted value and a numeric field to a bare number.

What is the difference between JSONPath and JSON Pointer?

A JSON Pointer addresses one exact location, like /store/book/0/title, and always returns a single value. JSONPath is a query language where a single expression can match many nodes at once through wildcards, recursive descent, and filters. Use a pointer to reference one fixed field, and JSONPath to select a set of fields or filter a collection.

Can I see the path of each match, not just the value?

Yes. Switch the output mode to paths to get the normalized location of every match, or entries to get the path and the value together. Seeing the real paths is the quickest way to refine an expression until it selects exactly the nodes you intended, which is especially helpful with recursive descent.

Is my JSON uploaded when I use the tester?

No. The document is parsed and the expression is evaluated in your browser with JavaScript, so nothing is transmitted, logged, or stored. You can confirm it by watching the network tab while you run a query, or by disconnecting from the internet, because the tester keeps working offline once the page has loaded.


Try it on your own data with the free JSONPath Tester. It evaluates wildcards, recursive descent, slices, unions, and filter expressions entirely in your browser, with nothing uploaded.

Comments

0 comments

0/2000 characters

No comments yet. Be the first to share your thoughts!