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.
The JSON Response parameter requires js_render=true to function, as it monitors network activity and JavaScript execution within the browser environment.

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:
# 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)
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
{
  "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
For comprehensive guidance on debugging JavaScript Instructions using JSON Response, see our JavaScript Instructions Debugging documentation.

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
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
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

IssueCauseSolution
Empty XHR arrayNo network requests madeVerify the page actually makes AJAX calls
Missing expected requestsRequests happen after page loadIncrease wait time or use wait_for
Large response sizeMany network requests capturedFilter requests to focus on relevant ones
JSON parsing errorsMalformed response dataAdd error handling for JSON parsing
Incomplete request dataRequests still in progressEnsure adequate wait time for completion
Response size exceeds plan limitsToo much data capturedUpgrade 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:
    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
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.

Debugging missing network requests

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

Verify if XHR requests are actually made

Python
# 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")
2

Increase wait time for slow requests

Python
params = {
    'js_render': 'true',
    'json_response': 'true',
    'wait': '10000',  # Wait 10 seconds for slow API calls
}
3

Use `wait_for` to ensure content loads

Python
params = {
    'js_render': 'true',
    'json_response': 'true',
    'wait_for': '.api-loaded-content',  # Wait for specific content
}

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.

Frequently Asked Questions (FAQ)