JavaScript Automation
Execute custom interactions on web pages before extracting content. Click buttons, fill forms, and wait for dynamic elements—all without managing browsers yourself.
mode=browser or mode=auto. It’s automatically available when browser rendering is used.Structured Actions
Use js_instructions to define a sequence of actions to perform:
{
"url": "https://example.com",
"mode": "browser",
"js_instructions": [
{"wait_for": "#search-input"},
{"fill": ["#search-input", "web scraping"]},
{"click": "#search-button"},
{"wait": 2000}
]
}Supported Actions
Click
Click any element on the page.
Syntax: {"click": "selector"}
{"click": "#submit-button"}
{"click": ".cookie-accept"}
{"click": "button[type='submit']"}Example:
curl -X POST "https://scrape.evomi.com/api/v1/scraper/realtime" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"mode": "browser",
"js_instructions": [
{"click": ".show-more-button"}
]
}'Fill
Fill form fields with text.
Syntax: {"fill": ["selector", "value"]}
{"fill": ["#email", "[email protected]"]}
{"fill": ["input[name='username']", "johndoe"]}
{"fill": ["#search-box", "product search term"]}Example:
{
"js_instructions": [
{"fill": ["#username", "[email protected]"]},
{"fill": ["#password", "secret123"]},
{"click": "#login-button"}
]
}Wait
Pause execution for a specified duration.
Syntax: {"wait": milliseconds}
{"wait": 1000} // 1 second
{"wait": 2500} // 2.5 seconds
{"wait": 5000} // 5 secondsExample:
{
"js_instructions": [
{"click": "#load-more"},
{"wait": 3000}, // Wait for content to load
{"click": "#load-more"}
]
}Wait For
Wait until an element appears on the page.
Syntax: {"wait_for": "selector"}
{"wait_for": ".results"}
{"wait_for": "#dynamic-content"}
{"wait_for": "div.loaded"}Example:
{
"js_instructions": [
{"click": "#search-button"},
{"wait_for": ".search-results"} // Wait until results appear
]
}CSS Selectors
Use standard CSS selectors to target elements:
| Selector | Description | Example |
|---|---|---|
#id |
Element by ID | #submit-btn |
.class |
Elements by class | .accept-cookies |
tag |
By tag name | button, input |
[attribute] |
By attribute | [name="email"], [type="submit"] |
parent > child |
Direct child | .nav > a |
ancestor descendant |
Descendant | .container button |
:pseudo |
Pseudo-selector | :first-child, :last-of-type |
Common Patterns
1. Search Form Interaction
{
"url": "https://example.com",
"mode": "browser",
"js_instructions": [
{"wait_for": "#search-input"},
{"fill": ["#search-input", "web scraping"]},
{"click": "#search-button"},
{"wait": 2000},
{"wait_for": ".search-results"}
]
}2. Login Flow
{
"url": "https://example.com/login",
"mode": "browser",
"js_instructions": [
{"fill": ["input[name='username']", "[email protected]"]},
{"fill": ["input[name='password']", "password123"]},
{"click": "button[type='submit']"},
{"wait_for": ".dashboard"}
]
}3. Accept Cookie Banner
{
"url": "https://example.com",
"mode": "browser",
"js_instructions": [
{"wait_for": ".cookie-banner"},
{"click": ".accept-cookies"},
{"wait": 500}
]
}4. Load More Content
{
"url": "https://example.com",
"mode": "browser",
"js_instructions": [
{"click": ".load-more"},
{"wait": 2000},
{"wait_for": ".new-content"},
{"click": ".load-more"},
{"wait": 2000}
]
}5. Navigate Menu
{
"url": "https://example.com",
"mode": "browser",
"js_instructions": [
{"wait_for": "nav.main-menu"},
{"click": "nav a[href='/products']"},
{"wait": 1000},
{"wait_for": ".product-grid"}
]
}6. Multi-Step Form
{
"url": "https://example.com/form",
"mode": "browser",
"js_instructions": [
{"fill": ["#firstName", "John"]},
{"fill": ["#lastName", "Doe"]},
{"fill": ["#email", "[email protected]"]},
{"fill": ["#phone", "555-1234"]},
{"click": "#submit"},
{"wait_for": ".success-message"}
]
}Raw JavaScript Execution
For advanced use cases, execute custom JavaScript code with execute_js:
{
"url": "https://example.com",
"mode": "browser",
"execute_js": "return document.title + ' - ' + window.location.href;"
}The result is available in the js_result field:
{
"success": true,
"js_result": "Example Domain - https://example.com/"
}Extract Data with JavaScript
{
"execute_js": "return Array.from(document.querySelectorAll('.product')).map(p => ({name: p.querySelector('.name').textContent, price: p.querySelector('.price').textContent}));"
}Response:
{
"js_result": [
{"name": "Product 1", "price": "$19.99"},
{"name": "Product 2", "price": "$29.99"}
]
}Modify Page Before Scraping
{
"execute_js": "document.querySelectorAll('.ad').forEach(ad => ad.remove()); return 'Ads removed';"
}Response Format
Instructions Result
When using js_instructions, the response includes execution details:
{
"js_instructions_result": [
{"action": "wait_for", "selector": "#button", "status": "success"},
{"action": "click", "selector": "#button", "status": "success"},
{"action": "wait", "duration": 2000, "status": "success"}
]
}Execute JS Result
When using execute_js, the return value is in js_result:
{
"js_result": "Return value from your JavaScript code"
}Best Practices
1. Always Wait for Dynamic Elements
Bad:
[
{"click": "#dynamic-button"}
]Good:
[
{"wait_for": "#dynamic-button"},
{"click": "#dynamic-button"}
]2. Add Delays After Actions
Give pages time to respond to interactions:
[
{"click": "#submit"},
{"wait": 1000}, // Wait for response
{"wait_for": ".result"}
]3. Use Specific Selectors
Bad (too generic):
{"click": "button"}Good (specific):
{"click": "#submit-btn"}
{"click": "button.primary-action"}4. Test Selectors First
Before automating, test your selectors in the browser console:
document.querySelector("#your-selector")5. Handle Errors Gracefully
If an element isn’t found, the API will retry automatically. Use wait_for to ensure elements exist:
[
{"wait_for": ".ajax-content"}, // Ensures element loads
{"click": ".ajax-content button"}
]6. Choose Appropriate Wait Times
| Scenario | Wait Time |
|---|---|
| Fast interactions | 500-1000ms |
| API/AJAX calls | 2000-3000ms |
| Page transitions | 3000-5000ms |
| Heavy animations | 2000ms+ |
7. Combine with Other Features
With Screenshots:
{
"mode": "browser",
"screenshot": true,
"js_instructions": [
{"wait_for": ".modal"},
{"click": ".close-modal"}
]
}With Resource Blocking:
{
"mode": "browser",
"block_resources": ["image", "font"],
"js_instructions": [
{"click": "#load-more"}
]
}With AI Enhancement:
{
"mode": "browser",
"js_instructions": [
{"click": ".show-full-article"}
],
"ai_enhance": true,
"ai_source": "markdown",
"ai_prompt": "Summarize in 3 bullet points"
}Limitations
Maximum Actions
Keep instruction sequences reasonable (< 20 actions). Very long sequences may timeout.
Timeout Limits
Browser mode has a 45-second timeout. Ensure your instruction sequence completes within this time.
Element Visibility
Elements must be visible on the page to be clicked. Hidden or off-screen elements may fail.
Dynamic Content
For heavily dynamic sites, increase wait_seconds at the page level:
{
"mode": "browser",
"wait_seconds": 5,
"js_instructions": [...]
}Troubleshooting
Element Not Found
{"action": "click", "selector": "#button", "status": "failed", "error": "Element not found"}Solutions:
- Add
{"wait_for": "#button"}before clicking - Check selector spelling in browser DevTools
- Ensure element isn’t in an iframe
- Use more specific selector
Click Not Working
Possible causes:
- Element is covered by another element
- Element is outside viewport
- Element requires specific wait condition
Solutions:
[
{"wait_for": "#button"},
{"wait": 500}, // Give page time to settle
{"click": "#button"}
]Form Fill Not Working
Solutions:
- Ensure input field is visible and enabled
- Wait for field to be ready:
[
{"wait_for": "#email"},
{"wait": 200},
{"fill": ["#email", "[email protected]"]}
]Timeout Errors
If instructions timeout, optimize your sequence:
- Remove unnecessary waits
- Use
wait_forinstead of fixedwait - Block resources to speed up page load
- Consider splitting into multiple requests