JSONPath Tester

Test JSONPath expressions against real JSON data and see every matching value and its exact path, supporting wildcards, recursive descent, slices, and filter expressions. A free online tool from Staaarter, right in your browser.

Runs locallyUpdated 2026-07-18

Overview

Introduction

Once JSON gets deeply nested, pulling out exactly the values you need by hand becomes tedious. JSONPath gives you a compact query language for that, similar in spirit to XPath for XML, and this tool lets you write and test expressions against real data instantly.

It exists because writing a JSONPath expression against a document you can't see is mostly guesswork: you write $.store.book[?(@.price < 10)], run it somewhere in application code, and only find out it's wrong when the result is empty or crashes. Testing it here first turns that trial and error into an immediate feedback loop, with the actual matches and their resolved paths shown as you type.

What Is JSONPath Tester?

A JSONPath tester evaluates a JSONPath query expression against a JSON document and returns every value that matches, along with the exact resolved path to each match.

It supports the common subset of the language that shows up in real-world use: the dollar root ($), dot and bracket member access, wildcards (* and [*]), recursive descent (..key), array indices, comma lists, slices, and filter expressions with a single comparison, like [?(@.price < 10)].

Because filter expressions are evaluated by a small, purpose-built comparison engine rather than by running arbitrary JavaScript, evaluation is safe to perform directly on whatever you paste, and it happens entirely inside your browser: no document or expression is sent anywhere to compute a result.

How JSONPath Tester Works

The expression is parsed into a sequence of steps (member access, wildcards, array indices, slices, recursive descent, and filters), which are then applied one at a time against the parsed JSON, narrowing down from the root ($) to the final set of matches. Filter expressions like [?(@.price < 10)] are evaluated with a small, safe comparison engine rather than executing arbitrary code.

Because each step operates on the current match set from the previous step, an expression like $.store.book[?(@.price < 10)].title reads left to right: start at the root, descend to store.book, keep only array items whose price is under 10, then pull the title from what's left. The evaluator tracks the resolved path alongside each value the entire way, which is why the output can show you $.store.book[2].title rather than just the string it contains.

Wildcards and recursive descent look similar but aren't interchangeable: [*] and ..* both mean 'every value,' but only the bracket and double-dot forms are recognized; a bare dot-star ($.*) is parsed as an attempted, invalid member access instead. Recursive filters ($..[?(...)]) only test items inside arrays encountered while descending; they don't apply a filter condition to a bare object's own properties, since a filter step is defined to iterate over array elements.

When To Use JSONPath Tester

Use it to prototype an extraction query before hardcoding it into application code, to explore an unfamiliar API response and find where a specific value lives, or to debug why a JSONPath expression used in a config (like an OpenAPI extension or a log processor rule) isn't matching what you expect.

It's particularly useful when the JSON structure itself is the unknown: instead of manually expanding a large nested object in a debugger to find where a field lives, a recursive-descent query like $..price surfaces every matching value across the whole document at once, along with exactly where each one is.

Features

Advantages

  • Shows the exact resolved path for every match, not just the value.
  • Supports the most commonly used JSONPath features: wildcards, recursive descent, slices, and filters.
  • Safe filter evaluation without executing arbitrary JavaScript.
  • Instant feedback lets you iterate on an expression quickly.

Limitations

  • Filter expressions support a single comparison (property, operator, value) rather than compound boolean logic (&&, ||).
  • Script expressions and function extensions from advanced JSONPath implementations are not supported.
  • Property names in filters are limited to a single level (@.key), not deeper paths like @.a.b.

JSONPath vs. Manual Property Access

JSONPath vs. Manual Property Access
JSONPath (this tool)Manual code (obj.a.b[0])
Works without knowing the exact structureYes, with wildcards and recursive descentNo, requires exact property names
Supports filtering by a conditionYesOnly with extra written logic
Requires writing and running codeNoYes
Best forExploring and prototyping queriesProduction code once the path is known

Examples

Filter an array by price

Input

{"items":[{"name":"Pen","price":2},{"name":"Desk","price":150}]}

Output

$.items[?(@.price < 10)] → 1 match: { "name": "Pen", "price": 2 } at $.items[0]

The filter step tests each array item's price property against the condition; only Pen satisfies price < 10, so Desk is excluded and the single match keeps its resolved array index in the path.

Find every occurrence of a key with recursive descent

Input

{"store":{"book":[{"title":"Dune","price":12},{"title":"Foundation","price":8}],"bike":{"price":20}}}

Output

$..price → 3 matches: 12 at $.store.book[0].price, 8 at $.store.book[1].price, 20 at $.store.bike.price

Recursive descent finds price at every level of the document regardless of depth or whether it sits inside an array element or a plain nested object, returning all three occurrences with their full resolved paths.

Select every array item with a bracket wildcard

Input

{"items":[{"n":1},{"n":2}]}

Output

$.items[*] → 2 matches: { "n": 1 } at $.items[0], { "n": 2 } at $.items[1]

[*] as a bracket step returns every element of the items array, each tagged with its own index-based path, which is the correct way to select 'everything at this level' (a dot-form .* would fail here).

Slice a range of array elements

Input

{"items":["a","b","c","d","e"]}

Output

$.items[1:3] → 2 matches: "b" at $.items[1], "c" at $.items[2]

The slice end index is exclusive, matching JavaScript's Array.prototype.slice() semantics, so [1:3] returns indices 1 and 2 only, not the item at index 3.

An expression that matches nothing

Input

{"items":[{"name":"Pen","price":2}]}

Output

$.items[?(@.color == 'red')] → 0 matches

A syntactically valid filter referencing a property no item has (or no item satisfies) returns a successful result with zero matches, not an error. That's distinct from an invalid expression, which fails outright instead of returning an empty result.

Dot-wildcard is not valid syntax

Input

{"a":1,"b":2}

Output

$.* → Error: Expected property name after '.'

A literal dot followed by * is parsed as an attempted (and invalid) member access, not a wildcard, in this evaluator. Use $[*] to select every value at the root, or $..* to select every value anywhere in the document, instead.

Best Practices & Notes

Best Practices

  • Build complex expressions incrementally: start with $.store and add steps one at a time to see how the match set narrows.
  • Use recursive descent (..) sparingly on very large documents, since it searches every level of the tree.
  • Quote string values in filters (@.status == 'active') to avoid them being parsed as identifiers.
  • Use [*] or ..* for wildcards, not a bare .*; the dot form isn't parsed as a wildcard by this evaluator and errors instead of matching everything.
  • Once you've identified where a value lives, replace $.. with a specific dotted path in production code. A targeted path is faster and won't accidentally pick up an unrelated same-named key elsewhere in the document.
  • Remember that a recursive filter like $..[?(...)] only inspects arrays it finds during descent, not bare object properties with the same field; query for the object directly if you need to test a condition on a single nested object.

Developer Notes

The evaluator returns both value and path for every match so results can be copied directly into code that reads a specific location, such as lodash's get() or a JSON Patch path. Filter expressions are evaluated with a small, purpose-built comparison engine, not JavaScript's eval() or Function(), so a filter can only perform one of the six supported comparisons against a literal (number, boolean, null, or quoted string). There's no way for a filter expression to run arbitrary code, which is what makes it safe to evaluate directly in the browser against whatever you paste. Negative array indices ([-1]) are resolved against the array's length at match time, but the path shown in the result preserves the original negative index you wrote (e.g. $.items[-1]) rather than rewriting it to the resolved positive index, so the displayed path always echoes your expression's own indexing.

JSONPath Tester Use Cases

  • Extracting a specific nested value from a large API response
  • Prototyping a JSONPath expression before using it in a log processing rule or API gateway config
  • Exploring an unfamiliar JSON structure interactively
  • Debugging why an existing JSONPath query isn't matching expected data
  • Confirming the exact resolved path to pass to a downstream function like lodash's get() or a JSON Patch operation, instead of guessing at index numbers by hand
  • Auditing a large config or payload for every occurrence of a particular field name before a refactor, using recursive descent to find every location it appears

Common Mistakes

  • Forgetting to quote string values inside filter expressions.
  • Expecting compound filters with && or || to work, when only a single comparison per filter is supported.
  • Confusing recursive descent (..) with a typo of single-dot access, leading to unexpectedly broad matches.
  • Writing $.* expecting a wildcard, when only [*] and ..* are recognized as wildcard syntax here.
  • Assuming a recursive filter ($..[?(...)]) will match a bare object with the filtered property, when it only tests items inside arrays encountered during the descent.
  • Treating an empty match list as an error; a valid expression that matches nothing returns a successful result with zero matches, not a failure.

Tips

  • If an expression returns too many matches, add a more specific filter or index instead of relying on wildcards.
  • Copy the resolved path from a match and reuse it as a plain member-access expression once you've found what you need.
  • When porting a JSONPath expression from another library, check dot-wildcards (.*) and compound filters (&&/||) first, since those are the two most common features other implementations support that this evaluator doesn't.
  • Start from $ and add one step at a time rather than pasting a long expression at once, so you can see exactly which step first produces an empty or unexpected match set.

References

Frequently Asked Questions