Query JSON with JSONPath-style expressions
Pull values out of a data document with one short expression: $.store.books[*].title returns North and South, one title per book, in the order they appear. A path that finds nothing gives an empty list, not an error. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Path
- $.store.books[*].title
- Matches
- North, South
The supported syntax covers direct properties, quoted property names, array indexes, and wildcards while deliberately rejecting filters, recursive descent, slices, unions, and executable expressions. That narrow contract makes results predictable for debugging, testing, data inspection, and lightweight automation.
Build a path from the top of the document
Every expression begins with <code>$</code>, which represents the complete parsed document. Add a dot followed by a simple property name, such as <code>$.customer.name</code>, to descend through objects. Property names used with dot notation must begin with a letter or underscore and may then contain letters, digits, or underscores.
When a key contains a space, hyphen, dot, or another character that does not fit that rule, use a quoted bracket step instead, for example <code>$['display-name']</code> or <code>$["shipping address"]</code>. Quoted steps accept either single or double quotes and allow the matching quote or a backslash to be escaped. Paths are evaluated from left to right, and a missing property simply produces no value for that branch.
The response always contains a <code>matches</code> array, even when the path identifies one scalar, so callers can handle single results, wildcard results, and empty results with the same output shape.
Select array entries and expand wildcards
Use a non-negative integer in brackets to select one array position, such as <code>$.orders[0].id</code>. Indexes are zero-based, so the first element is zero and an index beyond the array length yields no match. Use <code>[*]</code> to expand every element of an array, then continue the path to read a field from each element.
For example, <code>$.store.books[*].title</code> returns the title from every book object that has that property. The dot wildcard form <code>.*</code> is also supported. Wildcards can be combined with later property or index steps, and unmatched branches are discarded without affecting branches that still match.
The final ordering therefore follows the source document and the sequence of traversal.
Recognize the intentionally unsupported syntax
This capability implements a small JSONPath-style language rather than every JSONPath dialect. It rejects recursive descent such as <code>$..name</code>, filters such as <code>$[?( @.price < 10)]</code>, slices, unions, negative indexes, script expressions, functions, and unquoted property names inside brackets.
Rejection is deliberate because those features differ between libraries and some permit evaluation behavior that is inappropriate for a deterministic parser. A syntactically supported path that finds nothing is not an error: it returns an empty <code>matches</code> array, which lets automation distinguish malformed instructions from valid queries over absent optional data. For reliable integration, validate paths during development, keep them within the documented subset, and decide explicitly whether an empty match set is acceptable for your workflow.
FAQ
Which JSONPath features are supported?
The supported subset includes the root symbol, dot properties, quoted bracket properties, non-negative array indexes, and wildcards.
What happens when a path has no matches?
Missing data is different from invalid path syntax.
Can I use filters or recursive descent?
No. Filters, recursive descent, slices, unions, scripts, functions, and negative indexes are rejected as unsupported syntax.
How do I read a key that contains a space or a hyphen?
Put the name in quotes inside square brackets, for example $['display-name'] or $["shipping address"]. A plain dot only works for names that start with a letter or underscore and continue with letters, digits or underscores.
Do array positions start at 0 or at 1?
At 0: $.orders[0].id reads the first order. A position past the end of the list simply gives no match rather than an error, and negative positions are not accepted.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev2/json-path-query \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"json":"{\"store\":{\"books\":[{\"title\":\"North\",\"price\":12},{\"title\":\"South\",\"price\":18}]}}","path":"$.store.books[*].title"}'const res = await fetch("https://api.kit.forhosting.com/dev2/json-path-query", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"json": "{\"store\":{\"books\":[{\"title\":\"North\",\"price\":12},{\"title\":\"South\",\"price\":18}]}}",
"path": "$.store.books[*].title"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev2/json-path-query",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"json": "{\"store\":{\"books\":[{\"title\":\"North\",\"price\":12},{\"title\":\"South\",\"price\":18}]}}",
"path": "$.store.books[*].title"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev2/json-path-query", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"json":"{\\"store\\":{\\"books\\":[{\\"title\\":\\"North\\",\\"price\\":12},{\\"title\\":\\"South\\",\\"price\\":18}]}}","path":"$.store.books[*].title"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"json":"{\"store\":{\"books\":[{\"title\":\"North\",\"price\":12},{\"title\":\"South\",\"price\":18}]}}","path":"$.store.books[*].title"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev2/json-path-query", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"json": "{\"store\":{\"books\":[{\"title\":\"North\",\"price\":12},{\"title\":\"South\",\"price\":18}]}}",
"path": "$.store.books[*].title"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev2.json_path_query",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
This JSONPath-style query tool extracts values from a JSON document without requiring a script, dependency, or command-line setup. Paste valid JSON, enter a path beginning with the root symbol, and receive an ordered array of matches.
Build a path from the JSON root
The root expression by itself is valid and returns the entire JSON value as its only match.
Select array entries and expand wildcards
On an object, a wildcard visits its values in standard JSON property order; on an array, it visits elements from first to last. JSON values retain their native types: strings remain strings, numbers remain numbers, and objects, arrays, booleans, and null values are returned without conversion.
Recognize the intentionally unsupported syntax
Unsupported expressions return an <code>invalid_input</code> error with a message that identifies the syntax problem; they are never treated as a partially valid path. Invalid JSON is rejected separately before traversal begins. The API price begins at $0.002 per request, while browser execution can use the same deterministic logic.
Integration use cases
Inspect an API response
Extract a deeply nested status, identifier, or list of values while debugging a response payload.
Create stable test assertions
Select only the fields a regression test needs instead of comparing an entire changing document.
Prepare lightweight automation
Pull values from configuration, webhook, or export JSON before passing them to the next deterministic step.
Technical questions
Are matched values converted to text?
No. Values retain their JSON types, including numbers, booleans, null, objects, and arrays.
How much does an API request cost?
The API price begins at $0.002 per request. The capability is also suitable for free browser execution.