By Vivek - October 6, 2026
Filter a Nested API Response with JSONPath
When an API returns an envelope containing metadata and a list of records, finding one value by eye quickly becomes awkward. JSONPath selects the part you need without editing the original document. A filter can narrow a collection to records whose fields match a condition.
Open the JSONPath Tester. This guide uses its JSONPath Plus implementation. Syntax can vary between JSONPath libraries, so check expressions in the implementation your application uses. The JSONPath Plus documentation describes its selectors and result modes.
Start with a nested response
Paste this into JSON input:
{
"data": {
"users": [
{ "id": 101, "name": "Ada", "active": true, "profile": { "city": "London" } },
{ "id": 102, "name": "Grace", "active": false, "profile": { "city": "Cambridge" } },
{ "id": 103, "name": "Linus", "active": true, "profile": { "city": "Helsinki" } }
]
},
"meta": { "total": 3 }
} Enter $.data.users[*].name into JSONPath expression, choose Values in Result format, and click Run. The expected output is:
["Ada", "Grace", "Linus"] $ starts at the document root. .data.users reaches the array, [*] selects every item and .name selects each item’s name. Array indexes start at zero: $.data.users[0].name returns ["Ada"].
The tester always wraps matching results in an array, including a single match. A query returning no matches produces []; it does not necessarily mean the JSON is invalid.
Filter records, then select a field
Use $.data.users[?(@.active == true)].name. Inside the filter, @ refers to the record being checked. This expression selects names from records with a boolean active value of true:
["Ada", "Linus"] To keep whole matching records, remove .name and run $.data.users[?(@.active == true)]. You should see Ada’s and Linus’s objects, including their IDs and profiles. Copy that output if you need to compare two collections by record ID.
To read a nested field, use $.data.users[?(@.active == true)].profile.city. The result is:
["London", "Helsinki"] Find the location behind each match
Keep the active-name expression and choose JSON Pointers. The result identifies the original locations:
["/data/users/0/name", "/data/users/2/name"] Choose JSONPath locations to get:
["$['data']['users'][0]['name']", "$['data']['users'][2]['name']"] These locations are useful when tracing a value back to its source. They describe the current response; array positions can change in the next request.
Common reasons a query returns nothing
Check the envelope first. $.users[*] will not find this response’s records because the array sits under data. Property names are case-sensitive, and a literal dot in a key needs bracket notation, such as $['request.id'].
Keep boolean values distinct from strings: this example contains true, not "true". Use the exact field path before trying recursive descent. $..name searches throughout the document and can pick up unrelated names in other sections.
If parsing fails before the query runs, fix the JSON syntax first. If you are investigating changes across requests, keep timestamps separate with ignored paths in JSON Diff. Return to the JSON tools and API debugging hub for the complete workflow.
Related Posts
- Compare JSON Arrays by ID Without Reorder Noise
- Find and Fix Common JSON Syntax Errors
- Generate JSON Schema from a Sample API Response
- Compare API JSON Responses While Ignoring Timestamps
- Min Heap Heapify - A Worked Example With Every Swap
- How to Install Node.js and NPM on Ubuntu
- AWS Lambda Function with Response Streaming using Node.js
- Build a Chrome Extension with Svelte
- Focus a Dynamic Input Field in Svelte
- Svelte 5 Tutorial - A Thorough Introduction to Svelte