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

# JavaScript Instructions

> Automate page interactions like clicking buttons, filling forms, scrolling, and running custom JavaScript during headless browser rendering.

JavaScript Instructions enable you to interact with web pages dynamically by automating user actions like clicking buttons, filling forms, waiting for content to load, and executing custom JavaScript code. This powerful feature allows you to scrape content that requires user interaction or appears after specific actions are performed.

These instructions are essential for modern web scraping because many websites load content dynamically, hide information behind user interactions, or require form submissions to access data. With JavaScript Instructions, you can automate these interactions to extract the complete content you need.

<Note>JavaScript Instructions require `js_render=true` to function, as they operate within the browser environment during page rendering.</Note>

## How JavaScript Instructions work

JavaScript Instructions execute sequentially within a real browser environment, simulating genuine user interactions. Each instruction waits for the previous one to complete before executing, ensuring reliable automation of complex user workflows.

The process works as follows:

1. **Page loads** - The browser renders the initial page content
2. **Wait/Wait\_for parameters execute** - Global wait conditions are processed first
3. **JavaScript Instructions execute** - Each instruction runs in order, waiting for completion
4. **DOM updates** - The page responds to interactions, potentially loading new content
5. **Final capture** - The complete rendered page is captured after all instructions finish

This sequential execution ensures that dynamic content has time to load and that user interactions trigger the expected page changes.

<Warning>JavaScript Instructions have a **40-second timeout limit**. If your instruction sequence takes longer than 40 seconds to complete (due to many interactions, slow page responses, or redirects), the execution will stop and return whatever content is currently visible on the page. For complex workflows that may exceed this limit, consider using our [Scraping Browser](/scraping-browser) which provides up to 15 minutes of execution time and more advanced automation capabilities.</Warning>

## Basic usage

JavaScript Instructions are provided as a JSON array where each instruction is an object specifying the action and its parameters:

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

  url = 'https://www.example.com'
  apikey = 'YOUR_ZENROWS_API_KEY'
  params = {
      'url': url,
      'apikey': apikey,
      'js_render': 'true',
      'js_instructions': """[{"click":".button-selector"},{"wait":500}]""",
  }
  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://www.example.com';
  const apikey = 'YOUR_ZENROWS_API_KEY';
  axios({
      url: 'https://api.zenrows.com/v1/',
      method: 'GET',
      params: {
          'url': url,
          'apikey': apikey,
          'js_render': 'true',
          'js_instructions': `[{"click":".button-selector"},{"wait":500}]`,
      },
  })
      .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%2Fwww.example.com&js_render=true&js_instructions=%255B%257B%2522click%2522%253A%2522.button-selector%2522%257D%252C%257B%2522wait%2522%253A500%257D%255D";
          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%2Fwww.example.com&js_render=true&js_instructions=%255B%257B%2522click%2522%253A%2522.button-selector%2522%257D%252C%257B%2522wait%2522%253A500%257D%255D');
  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%2Fwww.example.com&js_render=true&js_instructions=%255B%257B%2522click%2522%253A%2522.button-selector%2522%257D%252C%257B%2522wait%2522%253A500%257D%255D", 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%2Fwww.example.com&js_render=true&js_instructions=%255B%257B%2522click%2522%253A%2522.button-selector%2522%257D%252C%257B%2522wait%2522%253A500%257D%255D')
  conn = Faraday.new()
  conn.options.timeout = 180
  res = conn.get(url, nil, nil)
  print(res.body)
  ```

  ```csharp C# theme={null}
  using RestSharp;
  namespace TestApplication {
      class Test {
          static void Main(string[] args) {
              var client = new RestClient("https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.example.com&js_render=true&js_instructions=%255B%257B%2522click%2522%253A%2522.button-selector%2522%257D%252C%257B%2522wait%2522%253A500%257D%255D");
              var request = new RestRequest();

              var response = client.Get(request);
              Console.WriteLine(response.Content);
          }
      }
  }
  ```

  ```bash cURL theme={null}
  curl "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.example.com&js_render=true&js_instructions=%255B%257B%2522click%2522%253A%2522.button-selector%2522%257D%252C%257B%2522wait%2522%253A500%257D%255D"
  ```
</CodeGroup>

<Tip>Use the [ZenRows Playground](https://app.zenrows.com/builder) to create and test your JavaScript Instructions visually, or use an <a href="https://www.url-encode-decode.com/" target="_blank" rel="noopener noreferrer nofollow">Online URL Encoder</a> to properly encode your instructions for API requests.</Tip>

## Available instructions

### Click interactions

Simulates clicking on page elements like buttons, links, or interactive areas. This is one of the most fundamental interactions for web automation, enabling you to trigger actions that reveal hidden content, navigate through interfaces, or activate dynamic functionality.

```json JSON theme={null}
[
    {"click": ".read-more-button"},
    {"click": "#submit-btn"},
    {"click": "button[data-action='load-more']"}
]
```

**Common use cases**

* Expanding collapsed content sections to access full article text
* Navigating through pagination to scrape multiple pages of results
* Triggering modal dialogs or popups that contain additional information
* Activating dropdown menus to access navigation options
* Loading additional content dynamically (infinite scroll triggers)
* Accepting cookie consent banners or terms of service

**Best practices**

* Always wait for elements to be clickable before clicking
* Use specific selectors to avoid clicking wrong elements
* Combine with `wait_for` to handle dynamic content loading

  ```json JSON theme={null}
  # Example: Click through pagination to scrape multiple pages

  [
      {"wait_for": ".product-list"},           # Wait for initial content
      {"click": ".pagination .next-page"},     # Click next page
      {"wait_for": ".product-list"},           # Wait for new content to load
      {"click": ".pagination .next-page"},     # Click next page again
      {"wait": 1000}                           # Final wait for stability
  ]
  ```

### Wait for selector

Pauses execution until a specific element appears in the DOM. This instruction is crucial for handling asynchronous content loading, which is common in modern web applications that use AJAX, React, Vue, or other dynamic frameworks.

```json JSON theme={null}
[
    {"wait_for": ".dynamic-content"},
    {"wait_for": "#ajax-loaded-section"},
    {"wait_for": "[data-loaded='true']"}
]
```

**When to use**

* Content loads asynchronously via AJAX or fetch requests
* Elements appear after animations or CSS transitions
* Waiting for user-triggered content to become available
* Ensuring forms are fully rendered before interaction
* After clicking buttons that trigger content loading
* When dealing with single-page applications (SPAs)

<Warning>If the selector doesn't appear within the timeout period (default: 10 seconds), the instruction will fail and execution will continue to the next instruction. This contributes to the overall 40-second timeout limit for all JavaScript Instructions.</Warning>

### Wait for specific duration

Pauses execution for a fixed amount of time in milliseconds. While less precise than `wait_for`, this instruction is useful when you need to accommodate processes that don't have visible indicators or when you need to ensure stability after rapid interactions.

```json JSON theme={null}
[
    {"wait": 1000},    # Wait 1 second
    {"wait": 5000},    # Wait 5 seconds
    {"wait": 500}      # Wait 0.5 seconds
]
```

**Use cases**

* Allowing animations to complete before taking screenshots
* Giving time for slow-loading content when no loading indicator exists
* Preventing rate limiting by spacing requests appropriately
* Ensuring page stability after rapid-fire interactions
* Waiting for third-party widgets or ads to load
* Accommodating server processing time for form submissions

```json JSON theme={null}
# Example: Handle slow-loading content with strategic waits

[
    {"click": ".load-data-button"},    # Trigger data loading
    {"wait": 3000},                    # Wait for server response
    {"wait_for": ".data-table"},       # Wait for table to appear
    {"wait": 1000}                     # Additional stability wait
]
```

<Warning>The maximum allowed wait time for a single `wait` instruction is 10 seconds, and the total combined duration of all `wait` instructions cannot exceed 30 seconds. For example, you could use three `{"wait": 10000}` instructions (10 seconds each) but not four. This 30-second limit contributes to the overall 40-second timeout for the entire JavaScript Instructions sequence.</Warning>

### Wait for browser events

Waits for specific browser events to occur, providing more sophisticated timing control based on actual browser state rather than arbitrary time delays. This is particularly useful for ensuring that all network activity has completed or that the page has reached a stable state.

```json JSON theme={null}
[
    {"wait_event": "networkidle"},        # Wait until network is idle
    {"wait_event": "networkalmostidle"},  # Wait until network is almost idle
    {"wait_event": "load"},               # Wait for page load event
    {"wait_event": "domcontentloaded"}    # Wait for DOM to be ready
]
```

**Event descriptions**

* `networkidle` - No network requests for 500ms (ideal for SPAs with API calls)
* `networkalmostidle` - No more than 2 network requests for 500ms (less strict timing)
* `load` - Page load event fired (all resources including images loaded)
* `domcontentloaded` - DOM parsing completed (faster than load event)

**Use cases**

* Ensure all API calls and resource loading have completed
* Wait for specific browser lifecycle events
* Avoid unnecessary waiting by responding to actual browser state
* Use browser events as more accurate timing signals than fixed delays

### Fill input fields

Populates form fields with specified values, enabling automation of data entry tasks. This instruction is essential for logging into websites, submitting forms, or providing input data that triggers dynamic content loading.

```json JSON theme={null}
[
    {"fill": ["#username", "john_doe"]},
    {"fill": ["input[name='email']", "user@example.com"]},
    {"fill": [".search-box", "search query"]}
]
```

**Supported input types**

* Text inputs (single-line text fields)
* Email fields (with built-in validation)
* Password fields (securely handled)
* Search boxes (often trigger autocomplete)
* Textarea elements (multi-line text)
* Number inputs (numeric data entry)

**Common applications**

* Login automation for accessing protected content
* Search form submission to find specific content
* Filter application to narrow down results
* Contact form completion for lead generation
* Registration form automation for account creation
* Configuration forms for customizing page content

```json JSON theme={null}
# Example: Complete a contact form

[
    {"wait_for": "#contact-form"},                   # Wait for form to load
    {"fill": ["#name", "John Smith"]},               # Fill name field
    {"fill": ["#email", "john@example.com"]},        # Fill email field
    {"fill": ["#message", "Hello, I need help..."]}, # Fill message
    {"click": "#submit-button"},                     # Submit form
    {"wait": 10000}                                  # Wait 10 seconds
]
```

### Checkbox interactions

Check or uncheck checkbox and radio button elements, allowing you to select options, agree to terms, or configure settings. These interactions are crucial for forms that require user consent or option selection.

```json JSON theme={null}
[
    {"check": "#agree-terms"},           # Check a checkbox
    {"uncheck": "#newsletter-signup"},   # Uncheck a checkbox
    {"check": "input[name='payment'][value='credit']"}  # Select radio button
]
```

**Use cases**

* Accepting cookie consent or privacy policies
* Selecting payment methods or shipping options
* Configuring notification preferences
* Filtering product catalogs by features
* Agreeing to terms of service during registration
* Enabling optional services or add-ons

<Warning>Using `check` on an already checked element will not uncheck it. Use `uncheck` specifically to deselect elements. This prevents accidental state changes in your automation.</Warning>

### Select dropdown options

Choose options from dropdown menus by their value, enabling selection from predefined lists of options. This is essential for forms that use select elements for categories, locations, or other structured data.

```json JSON theme={null}
[
    {"select_option": ["#country-select", "USA"]},
    {"select_option": [".size-dropdown", "large"]},
    {"select_option": ["select[name='category']", "electronics"]}
]
```

**Important notes**

* The second parameter must match the value attribute of the option, not the displayed text
* Use the actual value from the HTML, which may differ from what users see
* Works with both single and multiple select elements
* Triggers change events that may load additional content

**Common scenarios**

* Selecting countries for shipping calculations
* Choosing product categories for filtered browsing
* Setting language preferences for localized content
* Selecting time zones or date formats
* Choosing sorting options for search results
* Configuring display preferences (items per page, view type)

### Vertical scrolling

Scroll the page vertically by a specified number of pixels, essential for triggering content that loads based on scroll position or for ensuring elements are visible before interaction.

```json JSON theme={null}
[
    {"scroll_y": 1000},    # Scroll down 1000 pixels
    {"scroll_y": -500},    # Scroll up 500 pixels
    {"scroll_y": 2000}     # Scroll down 2000 pixels
]
```

**Common applications**

* Social media feeds with scroll loading
* E-commerce sites with lazy-loaded product images
* News sites with continuous article loading
* Search results that load more items on scroll
* Long-form content with progressive disclosure
* Image galleries with scroll-triggered loading

### Horizontal scrolling

Scroll the page horizontally by a specified number of pixels, useful for content that extends beyond the viewport width or for navigating horizontal carousels and galleries.

```json JSON theme={null}
[
    {"scroll_x": 800},     # Scroll right 800 pixels
    {"scroll_x": -400},    # Scroll left 400 pixels
    {"scroll_x": 1200}     # Scroll right 1200 pixels
]
```

**Use cases**

* Product image carousels on e-commerce sites
* Data tables with many columns
* Horizontal navigation menus
* Timeline or calendar interfaces
* Wide charts or graphs
* Panoramic image viewers

### Execute custom JavaScript (`evaluate`)

Run arbitrary JavaScript code within the page context, providing unlimited flexibility for complex interactions or page modifications that aren't covered by standard instructions.

```json JSON theme={null}
[
    {"evaluate": "document.querySelector('.modal').style.display = 'none';"},
    {"evaluate": "window.scrollTo(0, document.body.scrollHeight);"},
    {"evaluate": "document.querySelector('.load-more').scrollIntoView();"}
]
```

**Common JavaScript patterns**

```javascript JavaScript theme={null}
// Scroll to specific element
"document.querySelector('.target-element').scrollIntoView();"

// Modify page styling
"document.body.style.backgroundColor = '#ffffff';"

// Trigger custom events
"document.querySelector('.button').dispatchEvent(new Event('click'));"

// Access page data
"window.dataLayer = window.dataLayer || [];"

// Remove overlays
"document.querySelectorAll('.overlay').forEach(el => el.remove());"

// Trigger infinite scroll
"window.scrollTo(0, document.body.scrollHeight);"

// Click multiple elements
"document.querySelectorAll('.expand-button').forEach(btn => btn.click());"
```

**Advanced use cases**

* Removing cookie banners or overlay advertisements
* Triggering complex JavaScript functions specific to the site
* Modifying page state to reveal hidden content
* Collecting data from JavaScript variables
* Simulating complex user interactions
* Bypassing client-side restrictions

### CAPTCHA solving

Automatically solve CAPTCHAs using integrated solving services, enabling automation of forms and processes that are protected by CAPTCHA challenges.

CAPTCHA solving requires a [2Captcha](https://www.zenrows.com/go/2captcha) API key configured in your [ZenRows Integration Settings](https://app.zenrows.com/account/integrations).

```json JSON theme={null}
[
    {"solve_captcha": {"type": "recaptcha"}},
    {"solve_captcha": {"type": "cloudflare_turnstile"}},
    {"solve_captcha": {"type": "recaptcha", "options": {"solve_inactive": true}}}
]
```

**Supported CAPTCHA types**

* **reCAPTCHA v2** - Standard checkbox and image challenges
* **reCAPTCHA v3** - Invisible background verification
* **Cloudflare Turnstile** - Cloudflare's CAPTCHA system

<Tip>
  To ensure the CAPTCHA is solved before proceeding, add `wait` instructions **before** and **after** the CAPTCHA-solving step, allowing time for the CAPTCHA to load and be resolved.

  ```javascript theme={null}
  [
      {"wait": 3000}, // Wait for 3 seconds to allow the page to load
      {"solve_captcha": {"type": "recaptcha"}},
      {"wait": 2000} // Wait 2 seconds to confirm CAPTCHA resolution
  ]
  ```
</Tip>

### Working with iframes

Standard instructions don't work inside iframe elements due to browser security restrictions. Iframes create isolated contexts that require special handling to access their content and interact with their elements.

#### Frame instructions

All frame instructions require specifying the iframe selector as the first parameter

```json JSON theme={null}
[
    {"frame_click": ["#payment-iframe", ".submit-button"]},
    {"frame_wait_for": ["#content-iframe", ".loaded-content"]},
    {"frame_fill": ["#form-iframe", "#email", "user@example.com"]},
    {"frame_check": ["#options-iframe", "#agree-checkbox"]},
    {"frame_uncheck": ["#settings-iframe", "#notifications"]},
    {"frame_select_option": ["#dropdown-iframe", "#country", "USA"]},
    {"frame_evaluate": ["iframe-name", "document.body.style.color = 'red';"]}
]
```

#### Revealing iframe content

Extract content from iframes for processing:

```json JSON theme={null}
[
    {"frame_reveal": "#payment-iframe"}
]
```

This creates a hidden div element with the iframe content encoded in base64:

```php HTML theme={null}
<div class="iframe-content-element" style="display: none;" data-id="#payment-iframe">
    <!-- Base64 encoded iframe content -->
</div>
```

<Warning>For security reasons, iframe content isn't included in the standard response. Use frame\_reveal to explicitly extract iframe content when needed.</Warning>

### Using XPath selectors

In addition to CSS selectors, you can use XPath expressions for more precise element targeting:

```json JSON theme={null}
[
    {"click": "//button[text()='Submit']"},
    {"wait_for": "//div[@class='content' and @data-loaded='true']"},
    {"fill": ["//input[@placeholder='Enter email']", "user@example.com"]}
]
```

**XPath advantages**

* **Text-based selection** - Select elements by their text content
* **Complex conditions** - Use logical operators and functions
* **Hierarchical navigation** - Navigate parent/child relationships easily
* **Attribute matching** - Complex attribute-based selection

## Debugging JavaScript Instructions

Enable detailed execution reporting by adding `json_response=true` to your request:

```python Python theme={null}
params = {
    'js_render': 'true',
    'js_instructions': """[{"click":".button-selector"},{"wait":500}]""",
    'json_response': 'true'  # Enable debugging information
}
```

### Understanding the debug report

The debug report provides comprehensive execution details:

```json JSON expandable theme={null}
{
    "instructions_duration": 5041,
    "instructions_executed": 4,
    "instructions_succeeded": 3,
    "instructions_failed": 1,
    "instructions": [
        {
            "instruction": "wait_for",
            "params": {"selector": ".content"},
            "success": true,
            "duration": 1200
        },
        {
            "instruction": "click",
            "params": {"selector": ".button"},
            "success": true,
            "duration": 150
        },
        {
            "instruction": "wait_for",
            "params": {"selector": ".missing-element"},
            "success": false,
            "duration": 30000
        },
        {
            "instruction": "fill",
            "params": {"selector": "#input", "value": "test"},
            "success": true,
            "duration": 80
        }
    ]
}
```

## Common use cases and workflows

<Tabs>
  <Tab title="Multi-step form automation">
    <CodeGroup>
      ```python Python theme={null}
      def automate_registration_form(signup_url, user_data):
      # Complete multi-step registration process

      instructions = [
          # Step 1: Basic information
          {"wait_for": "#registration-form"},
          {"fill": ["#first-name", user_data['first_name']]},
          {"fill": ["#last-name", user_data['last_name']]},
          {"fill": ["#email", user_data['email']]},
          {"click": ".next-step"},
          
          # Step 2: Account details
          {"wait_for": "#account-details"},
          {"fill": ["#username", user_data['username']]},
          {"fill": ["#password", user_data['password']]},
          {"fill": ["#confirm-password", user_data['password']]},
          {"click": ".next-step"},
          
          # Step 3: Preferences
          {"wait_for": "#preferences"},
          {"check": "#newsletter-signup"},
          {"select_option": ["#country", user_data['country']]},
          {"click": ".submit-registration"},
          
          # Step 4: Confirmation
          {"wait_for": ".registration-success"},
      ]

      return requests.get('https://api.zenrows.com/v1/', params={
          'url': signup_url,
          'apikey': 'YOUR_ZENROWS_API_KEY',
          'js_render': 'true',
          'js_instructions': json.dumps(instructions),
      })
      ```

      ```javascript Node.js theme={null}
      async function automateRegistrationForm(signupUrl, userData) {
          /**
           * Complete multi-step registration process
           */
          const instructions = [
              // Step 1: Basic information
              {"wait_for": "#registration-form"},
              {"fill": ["#first-name", userData.firstName]},
              {"fill": ["#last-name", userData.lastName]},
              {"fill": ["#email", userData.email]},
              {"click": ".next-step"},
              
              // Step 2: Account details
              {"wait_for": "#account-details"},
              {"fill": ["#username", userData.username]},
              {"fill": ["#password", userData.password]},
              {"fill": ["#confirm-password", userData.password]},
              {"click": ".next-step"},
              
              // Step 3: Preferences
              {"wait_for": "#preferences"},
              {"check": "#newsletter-signup"},
              {"select_option": ["#country", userData.country]},
              {"click": ".submit-registration"},
              
              // Step 4: Confirmation
              {"wait_for": ".registration-success"},
          ];
          
          try {
              const response = await axios({
                  url: 'https://api.zenrows.com/v1/',
                  method: 'GET',
                  params: {
                      'url': signupUrl,
                      'apikey': 'YOUR_ZENROWS_API_KEY',
                      'js_render': 'true',
                      'js_instructions': JSON.stringify(instructions),
                  }
              });
              
              return response.data;
          } catch (error) {
              console.error('Error automating registration:', error);
              throw error;
          }
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Search and pagination">
    <CodeGroup>
      ```python Python theme={null}
      def scrape_search_results(search_url, query, max_pages=3):
      # Search and navigate through multiple result pages

      instructions = [
          # Perform search
          {"wait_for": "#search-form"},
          {"fill": ["#search-input", query]},
          {"click": "#search-button"},
          {"wait_for": ".search-results"},
      ]

      # Navigate through pagination
      for page in range(2, max_pages + 1):
          instructions.extend([
              {"click": f".pagination a[data-page='{page}']"},
              {"wait_for": ".search-results"},
              {"wait": 1000},  # Allow page to stabilize
          ])

      return requests.get('https://api.zenrows.com/v1/', params={
          'url': search_url,
          'apikey': 'YOUR_ZENROWS_API_KEY',
          'js_render': 'true',
          'js_instructions': json.dumps(instructions),
      })
      ```

      ```javascript Node.js theme={null}
      async function scrapeSearchResults(searchUrl, query, maxPages = 3) {
          /**
           * Search and navigate through multiple result pages
           */
          const instructions = [
              // Perform search
              {"wait_for": "#search-form"},
              {"fill": ["#search-input", query]},
              {"click": "#search-button"},
              {"wait_for": ".search-results"},
          ];
          
          // Navigate through pagination
          for (let page = 2; page <= maxPages; page++) {
              instructions.push(
                  {"click": `.pagination a[data-page='${page}']`},
                  {"wait_for": ".search-results"},
                  {"wait": 1000}  // Allow page to stabilize
              );
          }
          
          try {
              const response = await axios({
                  url: 'https://api.zenrows.com/v1/',
                  method: 'GET',
                  params: {
                      'url': searchUrl,
                      'apikey': 'YOUR_ZENROWS_API_KEY',
                      'js_render': 'true',
                      'js_instructions': JSON.stringify(instructions),
                  }
              });
              
              return response.data;
          } catch (error) {
              console.error('Error scraping search results:', error);
              throw error;
          }
      }

      // Usage examples
      async function runExamples() {
          try {
              // E-commerce example
              const productData = await scrapeProductWithShipping('https://shop.example.com/product/123');
              console.log('Product data scraped successfully');
              
              // Social media example
              const feedData = await scrapeSocialFeed('https://social.example.com/user/profile', 5);
              console.log('Social feed data scraped successfully');
              
              // Registration example
              const userData = {
                  firstName: 'John',
                  lastName: 'Doe',
                  email: 'john.doe@example.com',
                  username: 'johndoe',
                  password: 'SecurePass123',
                  country: 'USA'
              };
              const registrationResult = await automateRegistrationForm('https://app.example.com/signup', userData);
              console.log('Registration automated successfully');
              
              // Search example
              const searchResults = await scrapeSearchResults('https://marketplace.example.com', 'wireless headphones', 3);
              console.log('Search results scraped successfully');
              
          } catch (error) {
              console.error('Example execution failed:', error);
          }
      }

      // Run examples
      runExamples();
      ```
    </CodeGroup>
  </Tab>

  <Tab title="E-commerce product scraping">
    <CodeGroup>
      ```python Python theme={null}
      def scrape_product_with_shipping(product_url):
       #Scrape product page with shipping calculation by zip code

      instructions = [
          {"wait_for": ".product-details"},                    # Wait for product to load
          {"click": ".size-option[data-size='large']"},       # Select size
          {"wait": 500},                                      # Wait for price update
          {"click": ".color-option[data-color='blue']"},      # Select color
          {"wait": 500},                                      # Wait for price update
          {"click": ".shipping-calculator"},                  # Open shipping calculator
          {"wait_for": "#zip-code-input"},                    # Wait for shipping form
          {"fill": ["#zip-code-input", "90210"]},            # Enter zip code
          {"click": ".calculate-shipping"},                   # Calculate shipping
          {"wait_for": ".shipping-options"},                  # Wait for shipping options
      ]

      return requests.get('https://api.zenrows.com/v1/', params={
          'url': product_url,
          'apikey': 'YOUR_ZENROWS_API_KEY',
          'js_render': 'true',
          'js_instructions': json.dumps(instructions),
      })
      ```

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

      async function scrapeProductWithShipping(productUrl) {
          /**
           * Scrape product page with shipping calculation by zip code
           */
          const instructions = [
              {"wait_for": ".product-details"},                    // Wait for product to load
              {"click": ".size-option[data-size='large']"},       // Select size
              {"wait": 500},                                      // Wait for price update
              {"click": ".color-option[data-color='blue']"},      // Select color
              {"wait": 500},                                      // Wait for price update
              {"click": ".shipping-calculator"},                  // Open shipping calculator
              {"wait_for": "#zip-code-input"},                    // Wait for shipping form
              {"fill": ["#zip-code-input", "90210"]},            // Enter zip code
              {"click": ".calculate-shipping"},                   // Calculate shipping
              {"wait_for": ".shipping-options"},                  // Wait for shipping options
          ];
          
          try {
              const response = await axios({
                  url: 'https://api.zenrows.com/v1/',
                  method: 'GET',
                  params: {
                      'url': productUrl,
                      'apikey': 'YOUR_ZENROWS_API_KEY',
                      'js_render': 'true',
                      'js_instructions': JSON.stringify(instructions),
                  }
              });
              
              return response.data;
          } catch (error) {
              console.error('Error scraping product:', error);
              throw error;
          }
      }
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Troubleshooting

### Common issues and solutions

| Issue                  | Cause                                 | Solution                                       |
| ---------------------- | ------------------------------------- | ---------------------------------------------- |
| Element not found      | Selector doesn't match any elements   | Verify selector in browser DevTools            |
| Click not working      | Element not clickable or covered      | Use `wait_for` to ensure element is ready      |
| Form submission fails  | Missing required fields               | Fill all required fields before submitting     |
| Timeout errors         | Content takes too long to load        | Increase wait times or use `wait_for`          |
| Instructions skip      | Previous instruction failed           | Check debug report for failed instructions     |
| Iframe content missing | Using standard instructions on iframe | Use `frame_*` instructions for iframe elements |

### Debugging selector issues

When selectors aren't working as expected:

<Steps>
  <Step title="Verify selector in browser">
    Open the target page in your browser and test the selector in DevTools console:

    ```javascript JavaScript theme={null}
    // Test CSS selector
    document.querySelector('.your-selector')

    // Test XPath
    document.evaluate('//your/xpath', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue
    ```
  </Step>

  <Step title="Check element timing">
    Ensure the element exists when the instruction runs:

    ```json JSON theme={null}
    [
        {"wait_for": ".parent-container"},  // Wait for parent first
        {"click": ".child-element"}         // Then interact with child
    ]
    ```
  </Step>

  <Step title="Use alternative selectors">
    Try different selector strategies:

    ```json JSON theme={null}
    [
        {"click": "#button-id"},                    // Try ID first
        {"click": "button[data-action='submit']"},  // Try attribute
        {"click": "//button[text()='Submit']"}      // Try XPath with text
    ]
    ```
  </Step>

  <Step title="Check for dynamic content">
    Some elements are created dynamically:

    ```json JSON theme={null}
    [
        {"click": ".load-content"},         // Trigger content creation
        {"wait_for": ".dynamic-element"},   // Wait for element to appear
        {"click": ".dynamic-element"}       // Then interact with it
    ]
    ```
  </Step>
</Steps>

## Pricing

The `js_instructions` 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="What happens if an instruction fails?">
  When an instruction fails, execution continues with the next instruction. Use `json_response=true` to get detailed failure information and adjust your instructions accordingly. Critical failures may require adding `wait_for` instructions to ensure elements are available.
</Accordion>

<Accordion title="Can I use JavaScript Instructions without js_render?">
  No, JavaScript Instructions require `js_render=true` because they operate within a browser environment. Static HTML requests cannot execute dynamic interactions or JavaScript code.
</Accordion>

<Accordion title="How long do JavaScript Instructions take to execute?">
  Execution time varies based on the complexity of instructions and page responsiveness. Simple clicks take 50-200ms, while waiting for elements can take several seconds. Use the debug report to analyze timing and optimize your instruction sequences.
</Accordion>

<Accordion title="Can I interact with elements inside iframes?">
  Standard instructions don't work with iframe content. Use frame-specific instructions like `frame_click`, `frame_fill`, and `frame_wait_for` to interact with elements inside iframes. You'll need to specify the iframe selector as the first parameter.
</Accordion>

<Accordion title="What's the maximum number of instructions I can use?">
  There's no hard limit on instruction count, but longer sequences increase execution time and potential failure points. For complex workflows, consider breaking them into smaller, focused instruction sets and making multiple requests if needed.
</Accordion>

<Accordion title="How do I handle CAPTCHAs in my instructions?">
  Use the `solve_captcha` instruction with a configured [2Captcha](https://www.zenrows.com/go/2captcha) API key. Add wait instructions before and after CAPTCHA solving to allow time for loading and verification. Different CAPTCHA types require specific configuration options.
</Accordion>

<Accordion title="Can I modify the page content with JavaScript Instructions?">
  Yes, use the `evaluate` instruction to run custom JavaScript code that can modify page content, styling, or behavior. This is useful for removing overlays, triggering custom events, or preparing the page for data extraction.
</Accordion>
