JSON Path Extractor

$ (root) $.store $.store.book $.store.book[*].title $.store.book[0] $.store.book[?(@.price>10)]

-- Extracted Result --

Quick Access to JSON Tools

Go straight to the JSON utility you need.

How to Use the JSON Path Extractor

1

Paste your JSON data

Paste your JSON data.

2

Enter the JSONPath expression

Enter the JSONPath expression.

3

See the extracted values

See the extracted values.

JSON Path Extractor — Query JSON Data with JSONPath

JSONPath is a query language for JSON, much the same way XPath serves XML documents. It gives you a concise, declarative syntax to navigate through nested structures, filter arrays, and pull out exactly the data you need — all without writing loops, conditionals, or manual traversal code. If you've ever chained property access like data.users[0].address.city in JavaScript or Python, you already grasp the underlying idea. JSONPath takes that concept and formalizes it into a portable expression language with wildcards, filters, recursive descent, and array slicing built in.

Our free JSON Path Extractor runs entirely in your browser, meaning your data never leaves your machine. Paste your JSON document, type or select a JSONPath expression, and instantly see the matched results. The quick-select chips above the input field let you try common queries with a single click, or you can write custom expressions from scratch.

Why JSONPath Is Worth Learning

For small, flat JSON objects, reaching in with direct property access works perfectly well. But real-world data is rarely that cooperative. API responses from services like Stripe, GitHub, Shopify, or Elasticsearch routinely return deeply nested structures with multiple levels of arrays, mixed objects, and inconsistent nesting depth. Trying to manually trace through these structures to locate a handful of values is slow, brittle, and a recipe for subtle bugs.

JSONPath lets you describe what you want declaratively. Rather than constructing a loop that iterates through an array, checks a condition on each element, pushes matching values into a results array, and then maps over those results to pluck a single field — you write one expression. The path $.store.book[?(@.price < 15)].title returns every book title priced below $15. That single line replaces what would otherwise be six or eight lines of imperative code, and it's immediately clear to anyone reading it.

This matters most when you're testing API responses during development, building ETL data pipelines, writing integration or contract tests, or debugging incoming webhook payloads. A JSONPath expression is a precise, shareable, and version-controllable query. You can drop it into a test file, store it in a configuration document, or send it to a colleague so they run the exact same extraction you described.

JSONPath Syntax: A Complete Guide

Every JSONPath expression starts with the $ symbol, which represents the root of the JSON document. From there, you chain operators to drill down into the structure. Here are all the core building blocks:

Root and Dot Notation

$ — The root reference. Every expression begins here. $ alone returns the entire document.

.keyname — Child access using dot notation. $.store reaches the top-level store property. You can chain these: $.store.book accesses the book array inside store. Dot notation is clean and readable, but it only works with keys that are valid identifiers — no spaces, no special characters, no leading digits.

Bracket Notation

['keyname'] — Bracket notation does the same thing as dot notation but handles keys with special characters. $['store']['book list'] reaches a key literally named book list (with a space). You can also use computed bracket notation: $['store'] is equivalent to $.store. When in doubt, bracket notation is the safer choice because it never misinterprets your key names.

A common mistake is forgetting quotes inside brackets. Writing $[store] without quotes around store will not work — the engine interprets the bare word as a filter expression rather than a literal key. Always wrap key names in single or double quotes inside brackets.

Array Index Access

[index] — Access a specific array element by its numeric index, which starts at zero. $.store.book[0] returns the first book object. Negative indices count from the end: $.store.book[-1] returns the last book, [-2] the second-to-last, and so on. This mirrors the convention used in Python and many other languages.

Array Slicing

[start:end] — Slice an array into a sub-range. The start index is inclusive, the end index is exclusive. $.store.book[0:3] returns the first three elements (indices 0, 1, 2). [2:] returns everything from index 2 onward. [:5] returns the first five elements. This is extremely handy when dealing with paginated or chunked data where you want a specific window of results.

One thing that catches people off guard: the slice syntax [start:end] is different from a filter that uses comparison operators. [0:3] is a positional slice. [?(@.index >= 0 && @.index < 3)] is a logical filter. They might return the same data in some cases, but they operate on fundamentally different principles — position versus condition.

Wildcard Operator

* — The wildcard matches every element at the current level. When applied to an object, it returns all property values. When applied to an array, it returns every element. $.store.book[*].title collects every title field from all book objects in the array. $.* returns all top-level property values. Wildcards are the backbone of most JSONPath queries because they let you operate on entire collections without knowing the exact count or structure ahead of time.

Recursive Descent

.. — The double-dot operator searches every level of nesting beneath the current position. $..price finds every field named price anywhere in the entire document, regardless of how deeply nested it is. $.store..author finds every author field under store at any depth.

Recursive descent is powerful but comes with a trade-off: it traverses the entire subtree, which can be expensive on large documents. Use it when you genuinely don't know where a field lives in the structure. If you know the path, always prefer an explicit path — it's faster and produces more predictable results. A classic gotcha: $..book[0] will match the first book array encountered at every level of recursion, which might not be what you intended.

Filter Expressions: Conditional Selection

Filter expressions are where JSONPath goes from a simple path navigator to a legitimate query language. The syntax [?(@.field operator value)] tests a condition against each element in an array and keeps only the elements that pass.

Comparison Operators

  • == — Equality. [?(@.status == "active")] matches elements where status is literally the string "active".
  • != — Inequality. [?(@.role != "admin")] matches everything that isn't an admin.
  • > and >= — Greater than / greater than or equal. [?(@.price > 100)] filters by numeric price.
  • < and <= — Less than / less than or equal. [?(@.quantity <= 5)] finds low-stock items.

A frequent source of confusion is type sensitivity. The expression [?(@.id == 42)] will not match an element where id is the string "42". The comparison is type-aware. If your data inconsistently mixes strings and numbers for the same field, you may need to run two separate queries or normalize the data before querying it.

Logical Operators

You can combine multiple conditions using logical operators:

  • && — Logical AND. [?(@.price >= 10 && @.price <= 50)] returns elements in a price range.
  • || — Logical OR. [?(@.type == "book" || @.type == "magazine")] matches either type.
  • ! — Logical NOT (prefix). [?([email protected])] matches elements where archived is falsy.

When combining AND and OR in a single filter, remember that AND binds tighter than OR, just as it does in most programming languages. If you need OR to evaluate first, you'll need to restructure the expression or break it into simpler parts.

Script Expressions

Some JSONPath implementations support script expressions using parentheses: [?(@.price * 0.9 < 20)]. This evaluates a JavaScript-like expression and tests the result for truthiness. Script expressions give you access to arithmetic, string operations, and method calls inside the filter. They're less portable across implementations than standard comparisons, but they're indispensable when you need to apply a transformation before filtering — for example, checking whether a discounted price falls below a threshold.

Nested Object Traversal Patterns

Real JSON data rarely follows a clean, uniform structure. Consider a typical e-commerce API response:

{
  "data": {
    "order": {
      "id": "ORD-2847",
      "customer": {
        "name": "Jane Smith",
        "addresses": [
          {"type": "billing", "zip": "90210"},
          {"type": "shipping", "zip": "10001"}
        ]
      },
      "lineItems": [
        {"sku": "WIDGET-A", "qty": 2, "price": 24.99},
        {"sku": "WIDGET-B", "qty": 1, "price": 39.99}
      ]
    }
  }
}

To reach the customer's name: $.data.order.customer.name. To get all shipping zip codes: $.data.order.customer.addresses[?(@.type == "shipping")].zip. To sum up line item prices, you'd extract $.data.order.lineItems[*].price and handle the aggregation outside JSONPath, since JSONPath is a selection language, not an aggregation language.

When you encounter inconsistent nesting — the same field appearing at different depths — recursive descent is your fallback: $..sku grabs every SKU regardless of where it sits in the tree. Just keep in mind that recursive descent will also match fields in unrelated subtrees if they happen to share the same name.

Real-World API Response Parsing

Nearly every REST API wraps its response in an envelope. A GitHub API call to list repository issues returns something like {"total_count": 142, "items": [...], "incomplete_results": false}. Extracting the count: $.total_count. Pulling all issue titles: $.items[*].title. Filtering to open issues only: $.items[?(@.state == "open")].title.

Stripe's API nests charge details under $.data[0].balance_transaction. The Twitter API nests tweet text under $.data.text. OpenAPI/Swagger schemas put model definitions under $.components.schemas and endpoint paths under $.paths. In every case, JSONPath gives you a quick, repeatable way to navigate the structure and pull the fields you care about without writing boilerplate parsing code.

Webhooks present a different challenge: you often receive payloads you didn't design and need to extract key fields quickly for debugging or logging. A JSONPath like $..event_type or $..created_at lets you immediately locate the important metadata regardless of the payload's layout.

Configuration files — whether in .json, exported from tools in .jsonc, or embedded inside YAML — are another common target. Kubernetes manifests, Terraform state files, and docker-compose configs all export to JSON formats that benefit from JSONPath queries during debugging or automated validation.

JSONPath vs. JavaScript Property Access

In JavaScript, you reach into nested data with property chains like data.store.book[0].title. This works fine for simple, known structures, but it has real limitations when you need flexibility:

  • JavaScript property chains require you to know the exact structure at write time. JSONPath can match patterns dynamically against data you haven't seen before.
  • JavaScript has no built-in "all elements" wildcard. You'd need .map(), .flatMap(), or .filter() calls to achieve the same effect.
  • Optional chaining (?.) handles null values gracefully, but it provides no filtering, no slicing, and no recursive search capability.
  • JSONPath expressions are plain strings — they can be stored in configuration files, passed as URL parameters, serialized into databases, or evaluated by entirely different tools in different languages.

For one-off access inside application code, property chains are perfectly fine and often clearer. But for queries that need to be reusable, configurable, or applied to arbitrary and unpredictable JSON structures, JSONPath is the stronger tool.

Performance Considerations with Large JSON

JSONPath performance depends on two things: the size of the document and the complexity of the expression. For documents under a few megabytes, browser-based evaluation is essentially instant. Once you push past 5–10 MB, you'll start noticing a delay, particularly with recursive descent or complex filter expressions.

Recursive descent (..) is the most expensive operation because it traverses the entire subtree at every level. On a 20 MB JSON document, a query like $..id might scan hundreds of thousands of nodes. If you know the approximate location of your target field, always use an explicit path instead: $.data.items[*].id is orders of magnitude faster than $..id when you know the data lives under data.items.

Wildcards combined with deep nesting can also produce unexpectedly large result sets. $.data[*].children[*].value on a document with 1,000 items, each with 50 children, generates 50,000 results. This is technically correct but can strain rendering if you try to display all of them at once. Always consider whether you actually need every result or whether a slice like [0:10] would suffice.

For JSON files exceeding 50 MB, browser-based tools will struggle. Consider switching to command-line utilities like jq, which streams input and processes data in chunks, or language-specific libraries like jsonpath-ng for Python or Jayway JsonPath for Java. These tools handle large documents more gracefully because they operate outside the browser's memory and rendering constraints.

Another practical tip: if you're querying the same large document repeatedly with different expressions, parse the JSON into a structured object once and then run your queries against the parsed result. Re-parsing the same string repeatedly is a common and completely avoidable performance bottleneck.

Common Pitfalls and How to Avoid Them

  • Forgetting that indices start at zero. $.items[1] returns the second element, not the first. This is second nature for most developers but trips up newcomers regularly.
  • Case sensitivity in key names. $.Users and $.users are different paths. JSON key names are case-sensitive, and so are JSONPath expressions. Double-check the exact casing in your source data.
  • Comparing strings to numbers. If your JSON has "price": "24.99" (a string), then [?(@.price > 20)] may not behave as expected. String comparison and numeric comparison produce different results. Inspect the actual data types in your JSON before writing filters.
  • Recursive descent where explicit paths would suffice. $..name is tempting as a catch-all, but it's slower and less predictable than $.users[*].name when you know the structure.
  • Mismatched quotes inside brackets. $['store']['book list'] is correct. $[store][book list] is not. Always quote your key names in bracket notation.
  • Expecting JSONPath to aggregate data. JSONPath selects and filters — it does not sum, count, average, or sort. If you need aggregation, extract the values with JSONPath and process them afterward in code.

Frequently Asked Questions

The tool supports standard JSONPath expressions including dot notation, bracket notation, wildcards (*), array slicing ([start:end]), recursive descent (..), filter expressions with comparison operators (==, !=, >, <, >=, <=), and logical operators (&&, ||). This covers the vast majority of common querying needs for API responses, configuration files, and data exports.
An empty result means the expression didn't match any nodes. Start by checking the basic path: does the key actually exist at that level? Then verify case sensitivity — $.Users and $.users are different. If you're using filters, confirm that the data type matches your comparison (string vs. number is the most common culprit). Finally, paste the JSON into a formatter to confirm the structure matches what you expect — indentation can hide nesting mistakes that are hard to spot in raw text.
Dot notation ($.store.book) is shorter and more readable for simple key names. Bracket notation ($['store']['book']) is required when key names contain special characters like spaces, dots, hyphens, or start with a digit. Both produce identical results for valid identifier keys. Bracket notation also supports computed keys, making it slightly more versatile.
Use a negative index: $.array[-1] selects the last element. $.array[-2] gets the second-to-last, and so on. This mirrors the negative indexing convention found in Python, Ruby, and many other languages. You can also combine negative indices with slices — for instance, $.array[-3:] returns the last three elements.
The browser-based extractor handles documents up to several megabytes without issues. For files larger than 10 MB, you may experience a noticeable delay, especially with recursive descent or complex filters. At 50 MB or more, browser performance degrades significantly. For those cases, switch to command-line tools like jq, Python's jsonpath-ng library, or Java's Jayway JsonPath — these tools stream input and manage memory more efficiently than a browser environment.
The core syntax — dot notation, bracket notation, wildcards, array indexing — is consistent across implementations. Where languages diverge is in advanced features: filter expression syntax, script expression support, and recursive descent behavior can all vary. Python's jsonpath-ng, Java's Jayway implementation, and JavaScript's various libraries each have their own quirks. Always test your expressions against the specific runtime you plan to use in production.
JSONPath is a value-selection language — it extracts values, not property names. To retrieve the keys of an object, you'd need to use JavaScript (Object.keys()), Python (dict.keys()), or a tool like jq that supports key extraction natively. The JSONPath specification focuses on locating and filtering values, not enumerating structural metadata.
JSON Pointer (RFC 6901) uses a simple slash-separated path: /store/book/0/title. It's like a filesystem path — direct, specific, and always points to exactly one value. JSONPath is far more expressive: it supports wildcards, filters, recursive descent, and array slicing. Use JSON Pointer when you know the exact location. Use JSONPath when you need pattern matching, conditional selection, or multi-result queries.
Combine conditions with logical operators inside a single filter expression. Use && for AND and || for OR. For example, $.orders[?(@.status == "shipped" && @.total > 50)] returns shipped orders over $50. You can nest conditions for more complex logic, but keep in mind that AND binds tighter than OR — structure your expression accordingly or break it into separate queries if readability suffers.
No. JSONPath is purely a selection and filtering language — it can find and return matching values, but it cannot sort, sum, count, or average them. For those operations, extract the values with JSONPath and then process them in your application code. Some extended implementations add sorting or aggregation as non-standard extensions, but these are not portable across tools and should be avoided if you need cross-platform compatibility.