> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zenrows.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JSON Response

> Return scraped page content along with captured XHR and Fetch network requests as structured JSON for debugging and data analysis in ZenRows.

The JSON Response feature transforms ZenRows' standard HTML output into a structured JSON object containing the page content, network requests, and optional execution reports. This format provides comprehensive insights into page behavior, making it ideal for debugging, monitoring network activity, and analyzing dynamic content loading patterns.

When you enable JSON Response with `json_response=true`, ZenRows captures not only the final HTML content but also all XHR, Fetch, and AJAX requests made during page rendering. This gives you complete visibility into how modern web applications load and update their content.

<Note>The JSON Response parameter requires `js_render=true` to function, as it monitors network activity and JavaScript execution within the browser environment.</Note>

## How JSON Response works

JSON Response intercepts and records most network activity during JavaScript rendering, creating a comprehensive report of the page's behavior. The browser monitors every HTTP request made by the page, including background API calls, resource loading, and dynamic content updates.

This process captures:

* All XHR and Fetch requests with full request/response details
* The final rendered HTML content
* Optional JavaScript instruction execution reports
* Optional screenshot data of the rendered page
* Complete request and response headers for network analysis

The data is structured in a JSON format making it easy to programmatically analyze page behavior and extract specific information from network requests.

## Basic usage

Enable JSON Response by adding the `json_response=true` parameter to your JavaScript rendering request:

<CodeGroup>
  ```python Python theme={null}
  # pip install requests
  import requests

  url = 'https://httpbin.io/anything'
  apikey = 'YOUR_ZENROWS_API_KEY'
  params = {
      'url': url,
      'apikey': apikey,
      'js_render': 'true',
      'json_response': 'true',
  }
  response = requests.get('https://api.zenrows.com/v1/', params=params)
  print(response.text)
  ```

  ```javascript Node.js theme={null}
  // npm install axios
  const axios = require('axios');

  const url = 'https://httpbin.io/anything';
  const apikey = 'YOUR_ZENROWS_API_KEY';
  axios({
      url: 'https://api.zenrows.com/v1/',
      method: 'GET',
      params: {
          'url': url,
          'apikey': apikey,
          'js_render': 'true',
          'json_response': 'true',
      },
  })
      .then(response => console.log(response.data))
      .catch(error => console.log(error));
  ```

  ```java Java theme={null}
  import org.apache.hc.client5.http.fluent.Request;

  public class APIRequest {
      public static void main(final String... args) throws Exception {
          String apiUrl = "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fanything&js_render=true&json_response=true";
          String response = Request.get(apiUrl)
                  .execute().returnContent().asString();

          System.out.println(response);
      }
  }
  ```

  ```php PHP theme={null}
  <?php
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, 'https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fanything&js_render=true&json_response=true');
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  $response = curl_exec($ch);
  echo $response . PHP_EOL;
  curl_close($ch);
  ?>
  ```

  ```go Go theme={null}
  package main

  import (
      "io"
      "log"
      "net/http"
  )

  func main() {
      client := &http.Client{}
      req, err := http.NewRequest("GET", "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fanything&js_render=true&json_response=true", nil)
      if err != nil {
          log.Fatalln(err)
      }
      resp, err := client.Do(req)
      if err != nil {
          log.Fatalln(err)
      }
      defer resp.Body.Close()

      body, err := io.ReadAll(resp.Body)
      if err != nil {
          log.Fatalln(err)
      }

      log.Println(string(body))
  }
  ```

  ```ruby Ruby theme={null}
  # gem install faraday
  require 'faraday'

  url = URI.parse('https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fanything&js_render=true&json_response=true')
  conn = Faraday.new()
  conn.options.timeout = 180
  res = conn.get(url, nil, nil)
  print(res.body)
  ```

  ```bash cURL theme={null}
  curl "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fhttpbin.io%2Fanything&js_render=true&json_response=true"
  ```
</CodeGroup>

This example returns a JSON object containing the HTML content and any network requests made during page rendering, instead of just the raw HTML string.

## JSON Response structure

The JSON Response contains several key fields that provide different types of information. Here's a complete example of what a typical JSON response looks like:

```json JSON expandable theme={null}
{
  "html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Product Page</title>\n</head>\n<body>\n    <div class=\"product-container\">\n        <h1 class=\"product-title\">Wireless Headphones</h1>\n        <div class=\"price-display\">$99.99</div>\n        <div class=\"stock-status\">In Stock</div>\n        <div class=\"reviews-section\">\n            <div class=\"review-item\">Great sound quality!</div>\n            <div class=\"review-item\">Comfortable to wear</div>\n        </div>\n    </div>\n</body>\n</html>",
  "xhr": [
    {
      "url": "https://api.example.com/product/123/price",
      "body": "{\"price\": 99.99, \"currency\": \"USD\", \"discount\": 0.15}",
      "status_code": 200,
      "method": "GET",
      "headers": {
        "content-type": "application/json",
        "content-length": "54",
        "cache-control": "no-cache"
      },
      "request_headers": {
        "accept": "application/json",
        "user-agent": "Mozilla/5.0 (compatible; ZenRows)"
      }
    },
    {
      "url": "https://api.example.com/product/123/inventory",
      "body": "{\"in_stock\": true, \"quantity\": 25, \"warehouse\": \"US-EAST\"}",
      "status_code": 200,
      "method": "GET",
      "headers": {
        "content-type": "application/json",
        "content-length": "67"
      },
      "request_headers": {
        "accept": "application/json",
        "authorization": "Bearer token123"
      }
    },
    {
      "url": "https://api.example.com/product/123/reviews",
      "body": "{\"reviews\": [{\"rating\": 5, \"comment\": \"Great sound quality!\"}, {\"rating\": 4, \"comment\": \"Comfortable to wear\"}], \"average_rating\": 4.5}",
      "status_code": 200,
      "method": "GET",
      "headers": {
        "content-type": "application/json",
        "content-length": "156"
      },
      "request_headers": {
        "accept": "application/json"
      }
    }
  ],
  "js_instructions_report": {
    "instructions_duration": 1041,
    "instructions_executed": 2,
    "instructions_succeeded": 2,
    "instructions_failed": 0,
    "instructions": [
      {
        "instruction": "wait_for_selector",
        "params": {
          "selector": ".price-display"
        },
        "success": true,
        "duration": 40
      },
      {
        "instruction": "wait",
        "params": {
          "timeout": 1000
        },
        "success": true,
        "duration": 1001
      }
    ]
  },
  "screenshot": {
    "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
    "type": "image/png",
    "width": 1920,
    "height": 1080
  }
}
```

### Response fields

* **`html`** - The complete rendered HTML content of the page as a string. This content is JSON-encoded and contains the final DOM state after all JavaScript execution and dynamic loading.

* **`xhr`** - An array containing all XHR, Fetch, and AJAX requests made during page rendering. Each request object includes:
  * `url` - The complete URL of the request
  * `body` - The response body content
  * `status_code` - HTTP status code (200, 404, 500, etc.)
  * `method` - HTTP method used (GET, POST, PUT, DELETE, etc.)
  * `headers` - Response headers from the server
  * `request_headers` - Headers sent with the original request

* **`js_instructions_report`** *(Optional - only present when using JavaScript Instructions)* - Detailed execution report including:
  * `instructions_duration` - Total execution time in milliseconds
  * `instructions_executed` - Number of instructions processed
  * `instructions_succeeded` - Number of successful instructions
  * `instructions_failed` - Number of failed instructions
  * `instructions` - Array of individual instruction details with parameters, success status, and timing

* **`screenshot`** *(Optional - only present when using the Screenshot feature)* - Screenshot data containing:
  * `data` - Base64-encoded image data
  * `type` - Image format (typically "image/png")
  * `width` - Screenshot width in pixels
  * `height` - Screenshot height in pixels

## When to use JSON Response

JSON Response is essential for these scenarios:

### Dynamic content loading:

* **AJAX-loaded content** - When page content is loaded dynamically via XHR calls, JSON Response captures these API requests so you can access the raw data directly from the network calls rather than parsing it from the rendered HTML
* **API-dependent data** - Content that appears after external API calls
* **Progressive loading** - Pages that load content in stages
* **Conditional content** - Elements that appear based on user state or preferences
* **Real-time applications** - Capture live data feeds and WebSocket-like communications
* **Search platforms** - Monitor search API calls and result loading patterns

### Debugging and development:

* **Network troubleshooting** - Identify failed requests or slow API calls
* **Content loading analysis** - Understand how content loads in stages
* **Performance monitoring** - Track request timing and response sizes
* **Integration testing** - Verify that all expected API calls are made
* **Security analysis** - Monitor for unexpected network activity
* **JavaScript Instructions debugging** - When using JavaScript Instructions, JSON Response provides detailed execution reports to help debug instruction failures and timing issues

<Note>For comprehensive guidance on debugging JavaScript Instructions using JSON Response, see our [JavaScript Instructions Debugging documentation](/universal-scraper-api/features/js-instructions#debugging-javascript-instructions).</Note>

## Best practices

### Combine with appropriate parameters

Use JSON Response with other features such as `wait` or `wait_for` to guarantee the content will be loaded:

```python Python theme={null}
params = {
  'url': url,
  'apikey': 'YOUR_ZENROWS_API_KEY',
  'js_render': 'true',
  'json_response': 'true',
  'premium_proxy': 'true',  # For protected sites
  'wait': '3000',           # Allow time for API calls
  'screenshot': 'true',     # Include visual verification
}
```

### Filter and process network requests

Focus on relevant requests to avoid information overload

```python Python theme={null}
def filter_relevant_requests(xhr_requests, filters):
    # Filter XHR requests based on specified criteria
    
    relevant_requests = []
    
    for request in xhr_requests:
        include_request = True
        
        # Apply filters
        if 'methods' in filters:
            if request['method'] not in filters['methods']:
                include_request = False
        
        if 'status_codes' in filters:
            if request['status_code'] not in filters['status_codes']:
                include_request = False
        
        if 'url_contains' in filters:
            if not any(pattern in request['url'] for pattern in filters['url_contains']):
                include_request = False
        
        if 'exclude_extensions' in filters:
            if any(request['url'].endswith(ext) for ext in filters['exclude_extensions']):
                include_request = False
        
        if include_request:
            relevant_requests.append(request)
    
    return relevant_requests

# Filter for API calls only
api_filters = {
    'methods': ['GET', 'POST'],
    'status_codes': [200, 201, 202],
    'url_contains': ['/api/', '.json', '/v1/', '/v2/'],
    'exclude_extensions': ['.css', '.js', '.png', '.jpg', '.gif', '.svg'],
}

api_requests = filter_relevant_requests(json_data['xhr'], api_filters)
print(f"Found {len(api_requests)} relevant API requests")
```

## Troubleshooting

### Common issues and solutions

| Issue                             | Cause                           | Solution                                      |
| --------------------------------- | ------------------------------- | --------------------------------------------- |
| Empty XHR array                   | No network requests made        | Verify the page actually makes AJAX calls     |
| Missing expected requests         | Requests happen after page load | Increase `wait` time or use `wait_for`        |
| Large response size               | Many network requests captured  | Filter requests to focus on relevant ones     |
| JSON parsing errors               | Malformed response data         | Add error handling for JSON parsing           |
| Incomplete request data           | Requests still in progress      | Ensure adequate wait time for completion      |
| Response size exceeds plan limits | Too much data captured          | Upgrade plan or use Block Resources parameter |

### Handling oversized responses

When JSON responses become too large and exceed your plan's limits:

**Response size exceeded error**: If your response exceeds the maximum size allowed by your plan, you'll receive an error indicating the limit has been reached.

**Solutions**:

1. **Upgrade your plan** - Higher-tier plans support larger response sizes
2. **Use Block Resources parameter** - Remove unnecessary content like images, stylesheets, and scripts:
   ```python theme={null}
   params = {
       'json_response': 'true',
       'block_resources': 'image,stylesheet,script,font',  # Block heavy resources
   }
   ```
3. **Filter XHR requests** - Focus on specific API endpoints rather than capturing all network activity
4. **Use shorter wait times** - Reduce the time window to capture fewer requests

<Tip>The Block Resources parameter can significantly reduce response sizes by preventing the loading of images, CSS files, JavaScript files, and fonts that aren't essential for your scraping needs.</Tip>

### Debugging missing network requests

When expected API calls don't appear in the XHR array:

<Steps>
  <Step title="Verify if XHR requests are actually made">
    ```python Python theme={null}
    # Check if any requests were captured
    if not json_data.get('xhr'):
        print("No network requests captured - verify page makes AJAX calls")
    else:
        print(f"Captured {len(json_data['xhr'])} requests")
    ```
  </Step>

  <Step title="Increase wait time for slow requests">
    ```python Python theme={null}
    params = {
        'js_render': 'true',
        'json_response': 'true',
        'wait': '10000',  # Wait 10 seconds for slow API calls
    }
    ```
  </Step>

  <Step title="Use `wait_for` to ensure content loads">
    ```python Python theme={null}
    params = {
        'js_render': 'true',
        'json_response': 'true',
        'wait_for': '.api-loaded-content',  # Wait for specific content
    }
    ```
  </Step>
</Steps>

## Pricing

The `json_response` parameter doesn't increase the request cost. You pay the JavaScript Render (5 times the standard price) regardless of the wait value you choose.

<Tip>
  You can monitor your ZenRows usage in multiple ways to stay informed about your account activity and prevent unexpected overages.

  **Dashboard monitoring**: View real-time usage statistics, remaining requests, success rates, and request history on your [Analytics Page](https://app.zenrows.com/analytics/scraper-api). You can also set up usage alerts in your [notification settings](https://app.zenrows.com/account/notifications) to receive notifications when you approach your limits.

  **Programmatic monitoring**: For automated monitoring in your applications, call the `/v1/subscriptions/self/details` endpoint with your API key in the `X-API-Key` header. This returns real-time usage data that you can integrate into your monitoring systems. [Learn more about the usage endpoint](https://docs.zenrows.com/universal-scraper-api/features/other#plan-usage).

  **Response header monitoring**: Track your concurrency usage through response headers included with each request:

  * `Concurrency-Limit`: Your maximum concurrent requests
  * `Concurrency-Remaining`: Available concurrent request slots
  * `X-Request-Cost`: Cost of the current request
</Tip>

## Frequently Asked Questions (FAQ)

<Accordion title="Do I need js_render=true to use json_response?">
  Yes, the `json_response` parameter requires `js_render=true` because it monitors network activity that occurs during JavaScript execution. Without JavaScript rendering, there would be no XHR/Fetch requests to capture.
</Accordion>

<Accordion title="Will json_response capture all network requests made by the page?">
  JSON Response captures XHR, Fetch, and AJAX requests made during the page rendering process. It does not capture initial resource loading (like CSS, images, or the main HTML request), but focuses on dynamic API calls and background requests.
</Accordion>

<Accordion title="How large can the JSON response become?">
  The size depends on the number of network requests and their response sizes. Pages with many API calls can generate large JSON responses. Consider filtering requests or processing data in chunks for very active pages.
</Accordion>

<Accordion title="Can I get only the XHR data without the HTML content?">
  No, the JSON Response always includes both HTML and XHR data. However, you can ignore the HTML field in your processing and focus only on the XHR array if that's all you need.
</Accordion>

<Accordion title="What happens if a network request fails during page loading?">
  Failed requests are still captured in the XHR array with their actual status codes (e.g., 404, 500). This allows you to analyze both successful and failed network activity.
</Accordion>

<Accordion title="Does json_response work with Premium Proxy?">
  Yes, JSON Response works perfectly with Premium Proxy. Network monitoring occurs within the browser environment, regardless of the type of proxy used.
</Accordion>

<Accordion title="Can I use json_response to monitor WebSocket connections?">
  No, JSON Response only captures HTTP-based requests (XHR, Fetch, AJAX). WebSocket connections use a different protocol and are not captured in the XHR array.
</Accordion>

<Accordion title="How do I handle pages that make requests after user interactions?">
  Use JavaScript Instructions to simulate user interactions (such as clicks and scrolls) before capturing the page. This will trigger additional network requests that will be included in the JSON response.
</Accordion>
