Skip to content

Free JSONPath Tester — Evaluate Queries Online

Test JSONPath expressions against any JSON, 100% private in your browser — no upload, no signup, no eval. RFC 9535 standard engine plus Classic Goessner mode, with Values, Paths and Both result views.

No Tracking Runs in Browser Free
All evaluation runs locally in your browser. Your JSON and expression never leave this device. No eval, no upload.
Engine
 
JSONPath cheat sheet
$Root element
@Current element (in filters)
.nameChild member
..nameRecursive descent
[*]All elements / members
[0]Array index
[0:2]Array slice [start:end:step]
[a,b]Union of names / indices
[?(@.k>1)]Filter expression
length()RFC 9535 function: length / count / match / search / value
Reviewed for RFC 9535 grammar fidelity, normalized-path correctness, dual-engine semantic parity on common paths and documented divergence in the edge cases, no-eval safety (closing CVE-2024-21534 and CVE-2025-1302), and accessibility (ARIA roles, radiogroup engine toggle, screen-reader result announcements, LTR JSON handling under RTL layouts). — Go Tools Data Tooling Team · Jun 13, 2026

What Is a JSONPath Tester?

A JSONPath tester is a tool that lets you write a JSONPath expression, paste a JSON document, and see exactly which nodes the expression selects — both the matched values and their precise locations — without writing code or running a script. For developers it shortens the loop from minutes to milliseconds: tweak the path, watch the result change, and ship the query with confidence.

JSONPath is a query language for JSON, the JSON analogue of XPath for XML. An expression is built from a small alphabet of selectors. $ is the root of the document. A dot or a bracket steps into a child: $.store or $['store']. The double dot .. is recursive descent — it searches every level of the tree. The wildcard * selects all elements or members. Brackets carry array indices ([0]), slices ([start:end:step]), unions ([a,b]), and filter expressions ([?(@.price < 10)], where @ is the element being tested). With those pieces you can pull a single field out of a deeply nested API response, assert on values in tests, drive data transforms in systems like Kubernetes, AWS Step Functions, and Azure Logic Apps, or extract structured data from irregular JSON — all without imperative traversal code. JSONPath is also famously inconsistent between implementations, which is exactly the problem a good tester surfaces before it reaches production.

This tester ships two engines. The default is an RFC 9535 engine: RFC 9535 is the IETF's February 2024 formal specification of JSONPath, the first time the language was precisely standardized after fifteen years of divergent implementations. It defines an exact grammar, the concept of normalized paths for results, and five standard functions — length(), count(), match(), search(), value(). Our RFC 9535 engine is a zero-dependency implementation that uses no eval, so it parses and interprets expressions with its own grammar instead of compiling them to JavaScript. The second engine is Classic (Goessner), the de facto 2007 dialect that most older online tools and libraries implement; switch to it to reproduce results from a tool like jsonpath.com or to run an expression you copied from legacy code. The two dialects agree on common paths but diverge in the edge cases — filter whitespace and quoting, union ordering, how missing members compare, and which functions exist — so being able to flip between them in one place is the fastest way to diagnose why an expression behaves differently than you expected.

What the tester surfaces beyond raw values: the result of a JSONPath query is a nodelist, and this tool can show it three ways. The Values view renders the matched nodes as a JSON array, exactly what you would consume in code. The Paths view renders each match's normalized path — a canonical, bracket-quoted location such as $['store']['book'][0]['title'] that uniquely identifies where in the document the value lives, no matter how the expression was written. Two expressions that select the same node produce the same normalized path, which makes the Paths view invaluable for debugging. The Both view shows values and paths side by side. A stats line reports how many nodes matched.

Security is a first-class concern here. Many online JSONPath evaluators run on a server, or embed a library that evaluates filter predicates with JavaScript eval — the design that produced remote-code-execution vulnerabilities tracked as CVE-2024-21534 and CVE-2025-1302 in widely used JSONPath packages. This tool uses no eval at all. The RFC 9535 engine has no eval path, and the Classic engine is built on a patched, pinned release of jsonpath-plus with eval explicitly disabled. That closes the RCE class of bugs and lets the tool run under a strict Content-Security-Policy that forbids unsafe-eval. Every evaluation is local: your JSON and your expression never leave the page, are never logged, and are never stored on disk — only your engine and view preferences persist to localStorage. That makes the tool safe for proprietary API payloads, redacted logs, internal config, and any data with a schema you would not paste into a server-backed service.

If JSON wrangling is your task, pair this with the other JSON tools on the site: format and pretty-print your input with the JSON Formatter, compare two documents with the JSON Diff, check a payload against a schema with the JSON Schema Validator, or turn a sample response into typed interfaces with JSON to TypeScript.

// The expression you build in this tester maps straight onto the
// RFC 9535 reference library used under the hood.
import { query, paths } from 'jsonpath-rfc9535';

const document = {
  store: {
    book: [
      { title: 'Sayings of the Century', author: 'Nigel Rees', price: 8.95 },
      { title: 'Sword of Honour', author: 'Evelyn Waugh', price: 12.99 },
      { title: 'Moby Dick', author: 'Herman Melville', price: 8.99 },
      { title: 'The Lord of the Rings', author: 'J. R. R. Tolkien', price: 22.99 }
    ]
  }
};

// Values: query(document, path) returns the matched values directly.
const titles = query(document, '$.store.book[*].title');
// → ['Sayings of the Century', 'Sword of Honour', 'Moby Dick', 'The Lord of the Rings']

// Filter: books cheaper than 10.
const cheap = query(document, '$.store.book[?(@.price < 10)].title');
// → ['Sayings of the Century', 'Moby Dick']

// Normalized paths: paths(document, path) returns where each match lives.
const authorPaths = paths(document, '$..author');
// → ["$['store']['book'][0]['author']", "$['store']['book'][1]['author']", ...]

// RFC 9535 functions like length() are used INSIDE filters, not as a segment.
const longTitles = query(document, '$.store.book[?length(@.title) > 15]');
// → the two books whose title is longer than 15 characters

Key Features

RFC 9535 Standard Engine (No Eval)

The default engine implements RFC 9535, the IETF's 2024 formal JSONPath specification — exact grammar, normalized paths, and the five standard functions. It is zero-dependency and uses no eval, so it parses and interprets expressions with its own grammar instead of compiling them to JavaScript. It runs under a strict Content-Security-Policy.

Classic (Goessner) Compatibility Mode

One toggle switches to a Goessner-compatible engine (built on jsonpath-plus, constructed with eval disabled) so expressions copied from older tools like jsonpath.com behave the way you saw them there. Flip between RFC 9535 and Classic to compare results and diagnose why a path matches differently across dialects.

Three Result Views: Values, Paths, Both

Values renders matched nodes as a JSON array, exactly what you consume in code. Paths renders each match's normalized path like $['store']['book'][0]['title']. Both shows them side by side so you can map every value to its precise location. The active view persists across sessions.

Normalized Paths for Every Match

Each result carries its canonical, bracket-quoted normalized path — the RFC 9535 way of uniquely identifying a node's location regardless of how the expression was written. Two expressions that hit the same node produce the same normalized path, which makes debugging ambiguous queries straightforward.

Full Selector Support

Root $, current element @, child .name, recursive descent ..name, wildcard [*], array index [0], slice [start:end:step], union [a,b], and filter [?()] expressions with comparison and logical operators. A built-in cheat sheet documents every selector so you never have to leave the page to look one up.

RFC 9535 Function Extensions

Call length(), count(), match(), search(), and value() inside expressions — count the elements of an array, test a string against an I-Regexp pattern, or filter on the size of a nested list. These standard functions are available in the default engine; the tool tells you to switch engines if you invoke them in Classic mode.

Format, Upload & Examples

Format JSON pretty-prints your input so the structure is readable before you query. Upload reads a .json or .txt file entirely in the browser — it is never sent anywhere. The Examples dropdown loads known-good starter expressions against sample data so you see the engine working before you adapt a path.

Permalink Sharing (No Upload)

Copy link encodes the JSON, expression, engine, and view into the URL hash. Browsers never transmit URL fragments in requests, so a shared link reproduces your full state on the recipient's machine without touching go-tools.org servers. Self-contained and audit-friendly for collaborative debugging.

100% Private, Browser-Only

Your JSON and your expression never leave your device. No network requests, no logging, no analytics on what you type — verify in DevTools → Network. Only the engine and view preferences persist to localStorage. Safe for proprietary payloads, redacted logs, and any data you wouldn't paste into jsonpath.com.

Worked Examples

Select every book title from a bookstore document

$.store.book[*].title
["Sayings of the Century", "Sword of Honour", "Moby Dick", "The Lord of the Rings"]

Paste the classic Goessner bookstore JSON, type the expression, and the Values view returns a JSON array of all four titles. Switch to Paths to see each result as a normalized path like $['store']['book'][0]['title']. The wildcard [*] iterates every element of the book array; .title projects one member from each.

Filter books cheaper than 10 with a filter expression

$.store.book[?(@.price < 10)].title
["Sayings of the Century", "Moby Dick"]

The filter selector [?()] keeps only array elements where the predicate is true; @ is the current element. Against the bookstore data (prices 8.95, 12.99, 8.99, 22.99) two books qualify. Both engines accept this shape, but note Classic (Goessner) writes the same filter as [?(@.price<10)] — switch engines if you copied an expression from an older tool.

Walk the whole tree with recursive descent

$..author
["Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"]

The .. operator descends into every level of the document and collects each author member wherever it appears, regardless of nesting depth. Recursive descent is the fastest way to pull one field out of a deeply nested or irregular structure without spelling out the full path.

Slice an array with [start:end:step]

$.store.book[0:2].title
["Sayings of the Century", "Sword of Honour"]

Array slices follow the same half-open [start:end] convention as Python and JavaScript: index 0 up to but not including index 2 returns the first two books. Add a third field for a step — $.store.book[::2] takes every other element. The end bound is exclusive, a common off-by-one trap the Paths view makes obvious.

Filter by title length with the RFC 9535 length() function

$.store.book[?length(@.title) > 15]
[{"title": "Sayings of the Century", "author": "Nigel Rees", "price": 8.95}, {"title": "The Lord of the Rings", "author": "J. R. R. Tolkien", "price": 22.99}]

length() is one of the five RFC 9535 standard functions, and it is only valid inside a filter expression [?...] — never as a standalone path segment like $.store.book.length(), which the RFC 9535 grammar rejects (that segment form is a jsonpath-plus extension, not standard JSONPath). Here the filter keeps each book whose title has more than 15 characters; against the bookstore data, the titles longer than 15 characters are selected (for example "Sayings of the Century" and "The Lord of the Rings"), while shorter ones like "Moby Dick" and "Sword of Honour" are excluded. count(), match(), search(), and value() are likewise used inside filters. These functions are an RFC 9535 feature — switch to the standard engine (the default) to use them; Classic (Goessner) mode does not implement them.

Select a union of two named members

$.store.book[0]['title','author']
["Sayings of the Century", "Nigel Rees"]

A union selector [a,b] gathers several children in one expression. Here it pulls both the title and the author of the first book. Unions also work with array indices — [0,2] grabs the first and third elements. The Both view pairs each value with its normalized path so you can see exactly which member produced which result.

How to Use the JSONPath Tester

  1. 1

    Paste or upload your JSON

    Drop JSON into the input box, paste it, or click Upload to load a .json / .txt file from disk. Format JSON re-indents the document. Invalid JSON is flagged inline with a parser message before you query.

  2. 2

    Choose an engine

    RFC 9535 (the 2024 IETF standard, no eval) is the default. Switch to Classic (Goessner) when you are running an expression copied from an older tool such as jsonpath.com so the results match what you saw there.

  3. 3

    Type your JSONPath expression

    The leading $ is shown for you. Start with a child path like .store.book[*].title, an index like [0], a recursive descent like ..author, or a filter like [?(@.price < 10)]. Results update live as you type.

  4. 4

    Switch the result view

    Values shows a JSON array of matched values. Paths shows each match's normalized path like $['store']['book'][0]['title']. Both shows them side by side so you can map every value to its exact location in the document.

  5. 5

    Copy the result or share a permalink

    Copy result drops the output on your clipboard. Copy link encodes the JSON, expression, engine, and view into a URL hash (no upload) so a colleague can reproduce the exact query locally on their own machine.

Common JSONPath Mistakes

Forgot the leading $ root

Every JSONPath expression begins at the root, written as $. Omitting it (or writing the path as if $ were implicit) makes most engines reject the expression. The tester shows the $ for you, so start your input with the next selector — a dot, a bracket, or a recursive descent.

✗ Wrong
store.book[*].title  →  invalid (no root)
✓ Correct
$.store.book[*].title  →  selects every title

Off-by-one slice — expected the end index included

Slices are half-open: [start:end] runs up to but not including end. [0:2] returns two elements (indices 0 and 1), not three. To include the last element by index, use [start:] or push the end bound one past it.

✗ Wrong
$.store.book[0:2]  →  first TWO books, not three
✓ Correct
$.store.book[0:3]  →  first three books (indices 0,1,2)

Used a Classic expression in the RFC 9535 engine (or vice versa)

An expression copied from jsonpath.com or jsonpath-plus may parse or match differently under RFC 9535 because of filter, union, and function differences. If results look wrong, flip the engine toggle to match the dialect the expression was written for.

✗ Wrong
Classic filter run under RFC 9535  →  parse error or unexpected nodes
✓ Correct
Switch engine to Classic (Goessner)  →  reproduces the original result

Called an RFC 9535 function as a standalone segment

length(), count(), match(), search(), and value() are RFC 9535 function extensions that are only valid inside a filter [?...]. A standalone segment call like $.store.book.length() is rejected by the RFC 9535 grammar (it is a jsonpath-plus extension, not standard). Call the function inside a filter, and use the default RFC 9535 engine — the Classic (Goessner) engine does not implement these functions.

✗ Wrong
$.store.book.length()  →  parse error (not a valid RFC 9535 segment)
✓ Correct
$.store.book[?length(@.title) > 15]  →  books with a title over 15 chars

Forgot @ inside a filter expression

Inside a filter [?()], the current element is @, not $. Writing $.price refers back to the document root rather than the element under test, so the filter selects nothing or everything. Use @ to address members of the element being filtered.

✗ Wrong
$.store.book[?($.price < 10)]  →  wrong scope
✓ Correct
$.store.book[?(@.price < 10)]  →  books under 10

Quoted a member name with the wrong syntax

Bracket notation needs quotes around string keys: $['store'] or $.store both work, but $[store] (unquoted in brackets) is an index/identifier error. Use quotes inside brackets for any key with spaces, dots, or special characters: $['first name'].

✗ Wrong
$[store][book]  →  invalid bracket selectors
✓ Correct
$['store']['book']  →  same as $.store.book

Expected recursive descent to stop at the first level

$..author does not stop at the top — it collects every author member at every depth. If you only want direct children, spell out the path. Recursive descent over a large document can return far more nodes than intended.

✗ Wrong
$..price  →  every price anywhere in the tree
✓ Correct
$.store.book[*].price  →  only book prices

Who Uses This Tool

Extract Fields from an API Response
Pull request IDs, nested resource attributes, or a list of names out of a JSON payload without writing traversal code. Build the path here against a sample response, confirm it returns exactly the nodes you want in the Values view, then paste the validated expression into your application or test.
Write Assertions for Integration Tests
Many test frameworks and contract-testing tools (REST Assured, Karate, Postman) use JSONPath to assert on response bodies. Draft the assertion path here, verify it selects the right node against a real response, and copy it into your test — catching a wrong path before the suite goes red.
Configure Data Transforms in Pipelines
Kubernetes, AWS Step Functions, Azure Logic Apps, and many ETL tools accept JSONPath to address fields in event payloads. Prototype the exact path against a representative event here, confirm it resolves, and drop it into your pipeline config with confidence that it points where you intend.
Reproduce a jsonpath.com Result Privately
Have an expression from a server-backed evaluator but cannot paste your data into a third-party site? Switch to Classic (Goessner) mode, load your JSON, and reproduce the same result locally — no payload ever leaves your browser, so proprietary data stays on your machine.
Migrate Legacy Expressions to RFC 9535
Moving to a system that advertises RFC 9535 compliance? Run a legacy expression in Classic mode, then flip to the RFC 9535 engine to see whether it still parses and matches the same nodes. The dual-engine comparison pinpoints filter, union, and function differences you would otherwise hit in production.
Debug Why a Path Returns the Wrong Nodes
A path that selects too much or too little is hard to reason about from the values alone. Switch to the Paths view to see the normalized location of every match — the exact array index, the exact member chain — and the off-by-one slice or stray recursive descent becomes obvious immediately.
Teach or Review JSONPath
Open a working expression against sample data and walk through it selector by selector, switching between Values and Paths so the learner sees both what is selected and where it lives. The cheat sheet and worked examples give a structured reference for code review or onboarding.

Engine & Algorithm Notes

RFC 9535 Engine (jsonpath-rfc9535, Zero-Dependency)
The default engine implements the IETF RFC 9535 grammar directly: it tokenizes and parses the expression into an abstract syntax tree and interprets it against the document. There is no eval and no Function constructor anywhere in the path, so it is immune to the eval-injection class of bugs and runs under a strict Content-Security-Policy.
Classic Engine (jsonpath-plus, eval Disabled)
The Classic (Goessner) engine is jsonpath-plus, pinned to a patched release (>= 10.4.0) and constructed with the eval option explicitly set to false. That keeps Goessner-dialect compatibility while closing the remote-code-execution vectors tracked as CVE-2024-21534 and CVE-2025-1302, which affected the library's default eval-based filter path.
Normalized Path Generation
Every match is reported with its RFC 9535 normalized path — a canonical form using single-quoted bracket notation ($['store']['book'][0]['title']) with array indices as bare integers. Normalized paths are stable and unique per node, so equivalent expressions yield identical paths, which the Paths and Both views rely on for unambiguous result identification.
Lazy-Loaded Engine Chunks
Both engines are loaded as separate JavaScript chunks only when first selected, so the initial page stays light and the engine you do not use is never downloaded. Switching engines re-evaluates the current expression against the current document immediately, with no page reload.
Local File Reading and JSON Formatting
The Upload button uses the browser FileReader API to read a .json or .txt file into the input entirely client-side — the file is never transmitted. Format JSON parses and re-serializes the input with two-space indentation, surfacing parse errors inline so malformed JSON is caught before evaluation.
Permalinks via URL Hash (Never Transmitted)
Share state is encoded in the location.hash fragment, carrying the JSON, the expression, the active engine, and the result view. Browsers never include the fragment in HTTP requests, so go-tools.org servers receive zero data when a permalink is opened; hydration happens entirely on the recipient's device.

JSONPath Best Practices

Pick the Engine That Matches Your Target
If your downstream system advertises RFC 9535 compliance, write and validate against the RFC 9535 engine. If you are reproducing or maintaining an expression from an older tool or library, use Classic (Goessner). Validating against the wrong dialect is the most common reason a path that worked in the tester fails in production.
Verify with the Paths View, Not Just Values
The Values view tells you what matched; the Paths view tells you where. When a query returns the right-looking values it may still be selecting them from the wrong location — a stray recursive descent or an over-broad wildcard. Check the normalized paths to confirm the expression hits exactly the nodes you intend.
Mind the Exclusive End of a Slice
[0:2] selects indices 0 and 1, not 0 through 2 — the end bound is exclusive, just like Python and JavaScript. Off-by-one slice errors are the most frequent JSONPath bug. Use the Paths view to read the exact index of every selected element and confirm the boundary before you ship.
Prefer an Explicit Path Over Recursive Descent When You Can
$..price is convenient but matches every price anywhere in the document, including ones you did not intend. When you know the structure, spell out the path ($.store.book[*].price) so the query stays precise and predictable as the data grows. Reserve .. for genuinely irregular or unknown shapes.
Keep Whitespace and Quoting Consistent in Filters
RFC 9535 follows its grammar exactly for filter expressions, while the classic dialect is looser. Write filters cleanly — quote string literals with single quotes ('fiction'), keep operators spaced, and avoid relying on lenient parsing — so the same expression evaluates the same way regardless of which engine or library eventually runs it.

Frequently Asked Questions

Is my JSON or JSONPath expression sent to your server?
No. Every evaluation runs in JavaScript inside your browser. Your JSON document and your JSONPath expression are not uploaded, not logged, not stored on disk, and not sent to any third party. Only your UI preferences — the active engine (RFC 9535 or Classic) and the result view (Values / Paths / Both) — are saved to localStorage so the page remembers them next visit; the JSON and the expression themselves are never persisted. You can verify by opening DevTools → Network: typing in either box fires zero requests. That makes this tool safe for proprietary API payloads, redacted log samples, internal config, and anything else you would not paste into a server-backed evaluator like jsonpath.com.
What is JSONPath and what is it used for?
JSONPath is a query language for JSON, the same way XPath is a query language for XML. You write a path expression — for example $.store.book[*].author — and the evaluator returns every value in the document that the path selects. It is used to pull specific fields out of API responses, to assert on values in integration tests, to configure data transforms in tools like Jenkins, Kubernetes, AWS Step Functions, and Azure Logic Apps, and to extract data from large or irregular JSON without writing imperative traversal code. An expression is built from an axis of selectors: $ (the root), . or [] (child access), .. (recursive descent), * (wildcard), [start:end:step] (array slice), [a,b] (union), and [?()] (filter). This tester evaluates the expression live and shows both the matched values and their normalized paths.
What is the difference between RFC 9535 and the classic Goessner syntax?
Classic JSONPath is the de facto syntax Stefan Goessner published in 2007. It became widely implemented but was never formally standardized, so subtle behaviors — how filters are written, how unions and the root function work, how absent values compare — diverged across libraries. RFC 9535, published by the IETF in February 2024, is the first formal specification of JSONPath. It nails down a precise grammar, defines normalized paths for results, and adds standard functions (length, count, match, search, value). The two are close but not identical: RFC 9535 is stricter about whitespace and quoting in filters, defines comparison semantics for missing members, and rejects some loose constructs the classic dialect tolerated. This tool defaults to the RFC 9535 engine (a zero-dependency, no-eval implementation) and lets you switch to a Classic (Goessner) engine for backward compatibility.
Why does the same expression return different results in the two engines, and how do I use an expression copied from jsonpath.com?
Because RFC 9535 and the classic Goessner dialect have genuinely different rules in the edge cases — filter whitespace and quoting, union ordering, how missing members compare, and which functions exist. An expression written for one engine can match differently (or fail to parse) in the other. If you copied an expression from an older tool such as jsonpath.com, jsonpath-plus, or a Jayway-based service, switch the engine toggle at the top to Classic (Goessner): that mode runs a Goessner-compatible evaluator (built on jsonpath-plus, constructed with eval disabled) and will reproduce the behavior you saw in the source tool. If you are writing a new expression or targeting a system that advertises RFC 9535 compliance, keep the default RFC 9535 engine. The cheat sheet and built-in examples are written to evaluate identically in both engines so you have a known-good starting point.
How do filter expressions [?()] work?
A filter selector keeps only the array elements (or object members) for which a predicate is true. Inside the filter, @ refers to the current element being tested. $.store.book[?(@.price < 10)] returns every book whose price member is less than 10. You can compare against literals (@.isbn, @.category == 'fiction'), combine conditions with && and ||, test for the existence of a member (@.isbn selects elements that have an isbn at all), and in RFC 9535 use the function extensions inside the predicate (?(length(@.tags) > 2)). Comparison operators are ==, !=, <, <=, >, >=. RFC 9535 is precise about types: comparing a missing member to a value is well-defined and does not throw. The classic dialect is looser about whitespace, so [?(@.price<10)] and [?(@.price < 10)] are both accepted there; RFC 9535 follows its grammar exactly.
What does recursive descent (..) do?
The .. operator searches every level of the document, not just the immediate children. $..author collects every author member wherever it occurs — inside the top-level object, inside arrays, inside nested objects, at any depth. It is the fastest way to extract a field from a deeply nested or irregularly shaped structure when you do not want to (or cannot) spell out the full path. You can follow .. with any selector: $..book[*] finds every element of every book array anywhere in the tree, $..* enumerates every value in the document, and $..['price'] gathers all price members. Recursive descent can match a lot — switch to the Paths view to see exactly where each result came from via its normalized path.
What are the RFC 9535 functions length(), count(), match(), search(), and value()?
RFC 9535 defines five standard function extensions, and the key rule is that they are only callable inside a filter expression [?...] — never as a standalone path segment. Writing $.store.book.length() is not valid RFC 9535 and the standard grammar rejects it (that segment-call form is a jsonpath-plus extension, not part of the spec). length() returns the length of a string, array, or object, so you use it to filter by size: $.store.book[?length(@.title) > 15] keeps books whose title is longer than 15 characters. count() returns the number of nodes a nodelist contains, again inside a filter: $.store.book[?(count(@.authors) > 1)]. match() tests whether a string matches a regular expression against the whole value, and search() tests for a match anywhere within the string — both take an I-Regexp pattern. value() converts a single-node nodelist to its value so it can be used in a comparison. These functions are part of the RFC 9535 standard, so they are available in the default engine; the Classic (Goessner) engine does not implement them. If a function-based expression fails, confirm you are calling it inside a filter and that the engine toggle is set to RFC 9535.
How do array slices [start:end:step] work?
Slices use the same half-open convention as Python and JavaScript: [start:end] selects from index start up to but not including index end, so [0:2] returns the first two elements (indices 0 and 1). Omit a bound to run to the edge — [2:] from index 2 onward, [:3] for the first three. A negative index counts from the end: [-1:] selects the last element. The optional third field is a step — [::2] takes every other element, [::-1] reverses (in engines that support negative steps). The exclusive end bound is the single most common slice bug; the Paths view shows the exact index of every selected element so you can confirm the boundary at a glance.
What is a union selector and how do I select multiple keys at once?
A union selector lists several names or indices inside one bracket and gathers all of them: $['title','author'] selects both members from an object, and $.store.book[0,2] selects the first and third elements of the book array. You can mix it with other selectors — $.store.book[*]['title','price'] pulls the title and price of every book. Unions are handy when you want a fixed projection of a few fields rather than a whole object or a wildcard. The Both view is the clearest way to read a union result because it pairs each selected value with its normalized path, so you can tell which name or index produced each entry.
Can I share a JSONPath query and its JSON via a link?
Yes — and the link involves no server roundtrip. Click Copy link in the action bar: the tester encodes the JSON, the expression, the active engine, and the result view into the URL hash. Anyone who opens the link hydrates the page with the same state, locally on their own machine. Because the data lives in the hash fragment, it is never transmitted to the go-tools.org server — browsers do not send the fragment in HTTP requests — and it never appears in our access logs. The link length grows with the size of the JSON, so for large documents share just the expression and let the recipient paste their own data, or use the Upload button to load a file locally. This makes permalinks safe for collaborative debugging without exposing the payload to any backend.
Is there a maximum JSON size?
Evaluation is bounded by your browser's memory rather than a hard cap, but the practical sweet spot is documents up to a few megabytes — comfortably larger than almost any single API response. Very large arrays with broad selectors (a $..* recursive wildcard over tens of thousands of nodes) will produce a large result set that takes longer to render; narrow the expression to keep the output readable. The Upload button reads a .json or .txt file entirely in the browser (it is never sent anywhere), and Format JSON re-indents the input so you can read the structure before querying it. For multi-megabyte data pipelines, validate your expression here against a representative slice, then run the same path in your application code or in a CLI tool like jq.
How is this different from jsonpath.com and is it safe — no eval?
Four differences. (1) Privacy: jsonpath.com and most online evaluators run on a server or embed a library that evaluates filters with JavaScript eval; this tool runs entirely in your browser and uses no eval at all. The default RFC 9535 engine is a zero-dependency implementation with no eval path, and the Classic (Goessner) engine is built on jsonpath-plus pinned to a patched release with eval explicitly disabled — closing the remote-code-execution class of bugs tracked as CVE-2024-21534 and CVE-2025-1302. That also means the tool works under a strict Content-Security-Policy. (2) Standards: this is one of the few online testers offering a true RFC 9535 engine, not just the legacy Goessner dialect. (3) Dual-engine: you can switch between RFC 9535 and Classic to compare results or to run expressions copied from older tools, side by side. (4) Languages: the interface is available in 15 languages. If you only need quick legacy-syntax checks, jsonpath.com still works; for standards-compliant, private, no-eval evaluation, this is the safer choice.
What do the Values, Paths, and Both views show?
The result of a JSONPath query is a nodelist — a set of nodes inside your document. The Values view renders those nodes as a JSON array of the matched values, exactly what you would consume in code. The Paths view renders the normalized path of each match instead — a canonical, bracket-quoted location like $['store']['book'][0]['title'] that uniquely identifies where in the document the value lives, regardless of how your expression was written. Normalized paths are an RFC 9535 concept and are invaluable for debugging: two different expressions that select the same node produce the same normalized path. The Both view shows the two side by side so you can match each value to its location at a glance. Your chosen view persists across sessions via localStorage.
Does this work offline, and what about a Content-Security-Policy?
Yes on both counts. Because every evaluation runs in your browser with no network calls, the tool keeps working once the page has loaded even if you go offline. And because neither engine uses eval or the Function constructor to evaluate filter expressions, the tool runs under a strict Content-Security-Policy that forbids unsafe-eval — the policy that many security-conscious organizations enforce and that breaks eval-based JSONPath libraries. The RFC 9535 engine parses and interprets expressions with its own grammar rather than compiling them to JavaScript, and the Classic engine is configured with eval disabled. If you need to evaluate JSONPath inside a hardened internal environment, this tool is designed to run there without policy exceptions.

Related Tools

View all tools →