VOOZH about

URL: https://alterlab.io/docs/guides/javascript-rendering


Guide
$0.004

JavaScript Rendering

Scrape dynamic websites that require JavaScript execution using our headless browser infrastructure.

Cost

JavaScript rendering uses Tier 4 (Browser). A basic JS-rendered scrape costs $0.004 per request.

When to Use JS Rendering

Most websites work fine with standard HTTP requests. Use JavaScript rendering only when needed:

Use JS Rendering For:

  • Single Page Applications (React, Vue, Angular)
  • Content loaded via AJAX/fetch
  • Infinite scroll pages
  • Sites requiring user interaction simulation
  • Pages with anti-bot JavaScript checks

Don't Need JS For:

  • Static HTML pages
  • Server-rendered content
  • APIs returning JSON
  • Most news/blog articles
  • Traditional e-commerce product pages

Auto Mode

Use mode: "auto" (default) and AlterLab will automatically detect if JS rendering is needed and escalate only when necessary.

Basic Usage

Enable JavaScript rendering by setting render_js: true in the advanced options:

Bash
curl-X POST https://api.alterlab.io/api/v1/scrape \-H"X-API-Key: YOUR_API_KEY"\-H"Content-Type: application/json"\-d'{
 "url": "https://example.com/spa-page",
 "advanced": {
 "render_js": true
 }
 }'

Wait Conditions

Control when the page is considered "ready" for scraping. This is crucial for SPAs where content loads asynchronously.

ConditionDescriptionBest For
domcontentloadedDOM is ready, external resources may still loadFast pages, minimal JS
loadPage and all resources fully loadedImage-heavy pages
networkidleNo network activity for 500ms (default)SPAs, AJAX-heavy pages
Python
# Wait for network to be idle (default, best for SPAs)response = requests.post("https://api.alterlab.io/api/v1/scrape", headers={"X-API-Key":"YOUR_API_KEY"}, json={"url":"https://react-app.example.com","advanced":{"render_js":True,"wait_condition":"networkidle"}})
# Fast mode - don't wait for all resourcesresponse = requests.post("https://api.alterlab.io/api/v1/scrape", headers={"X-API-Key":"YOUR_API_KEY"}, json={"url":"https://simple-page.example.com","advanced":{"render_js":True,"wait_condition":"domcontentloaded"}})

Wait for Selector

Wait for a specific element to appear before capturing the page. This is the most reliable way to ensure dynamic content is loaded.

Python
# Wait for product grid to loadresponse = requests.post("https://api.alterlab.io/api/v1/scrape", headers={"X-API-Key":"YOUR_API_KEY"}, json={"url":"https://shop.example.com/products","advanced":{"render_js":True},"wait_for":".product-grid"# CSS selector})
# Wait for specific data attributeresponse = requests.post("https://api.alterlab.io/api/v1/scrape", headers={"X-API-Key":"YOUR_API_KEY"}, json={"url":"https://app.example.com/dashboard","advanced":{"render_js":True},"wait_for":"[data-loaded='true']"})

Timeout

The selector wait has a default timeout of 30 seconds. If the element doesn't appear, the request will return with whatever content is available.

Capturing Screenshots

Capture a full-page screenshot along with the HTML content. Screenshots are returned as base64-encoded PNG.

Python
import base64

response = requests.post("https://api.alterlab.io/api/v1/scrape", headers={"X-API-Key":"YOUR_API_KEY"}, json={"url":"https://example.com","advanced":{"render_js":True,"screenshot":True}})
data = response.json()
# Save screenshot to fileif data.get("screenshot"): screenshot_bytes = base64.b64decode(data["screenshot"])withopen("screenshot.png","wb")as f: f.write(screenshot_bytes)

Cost

Screenshots add +$0.0002 to your request.

PDF Generation

Generate a PDF of the rendered page. Useful for archiving or creating printable versions of web pages.

Python
import base64

response = requests.post("https://api.alterlab.io/api/v1/scrape", headers={"X-API-Key":"YOUR_API_KEY"}, json={"url":"https://example.com/report","advanced":{"render_js":True,"generate_pdf":True}})
data = response.json()
# Save PDF to fileif data.get("pdf"): pdf_bytes = base64.b64decode(data["pdf"])withopen("page.pdf","wb")as f: f.write(pdf_bytes)

Cost

PDF generation adds +$0.0004 to your request.

Single Page Apps (SPAs)

Modern SPAs built with React, Vue, or Angular require special handling. Here's a reliable pattern:

Python
# Scraping a React applicationresponse = requests.post("https://api.alterlab.io/api/v1/scrape", headers={"X-API-Key":"YOUR_API_KEY"}, json={"url":"https://react-store.example.com/products/123","advanced":{"render_js":True,"wait_condition":"networkidle"},# Wait for the main content container"wait_for":"[data-testid='product-details']","timeout":60# Allow more time for complex apps})
# Scraping a Vue application with lazy loadingresponse = requests.post("https://api.alterlab.io/api/v1/scrape", headers={"X-API-Key":"YOUR_API_KEY"}, json={"url":"https://vue-app.example.com/dashboard","advanced":{"render_js":True,"wait_condition":"networkidle"},"wait_for":".dashboard-loaded"})

Tips for SPAs:

  • 1. Find a reliable selector: Look for elements that only appear after data loads
  • 2. Use networkidle: This waits for all AJAX calls to complete
  • 3. Increase timeout: Complex apps may need 60-90 seconds
  • 4. Check for loading states: Wait for spinners/skeletons to disappear

Timeout & Scroll Configuration

Request Timeout

Control the maximum time (in seconds) for a JS rendering request with the timeout parameter:

ParameterRangeDefault
timeout1 - 300 seconds90 seconds

Scroll Configuration

Use the enable_scroll parameter to control automatic page scrolling for lazy-loaded images and content:

ValueBehaviorOverhead
trueAlways scroll to capture lazy-loaded images+5-10 seconds
falseNever scroll (faster, may miss dynamic images)None
null (default)Auto-detect: scrolls unless the site is a social media platformVaries
JSON
{"url":"https://example.com/gallery","advanced":{"render_js":true},"enable_scroll":true,"timeout":120}

Infinite Scroll Pages

For pages with infinite scroll, you'll typically get the initial viewport content. For full content, consider using pagination or the async API with custom scroll handling.

Python
# Get initial content from infinite scroll pageresponse = requests.post("https://api.alterlab.io/api/v1/scrape", headers={"X-API-Key":"YOUR_API_KEY"}, json={"url":"https://social-feed.example.com","advanced":{"render_js":True,"wait_condition":"networkidle"},# Wait for initial items to load"wait_for":".feed-item:nth-child(10)"})
# For more content, look for pagination APIs# Many "infinite scroll" sites have underlying REST/GraphQL APIs# that you can call directly without JS rendering

Pro Tip

Many infinite scroll sites have underlying APIs that return JSON. Use browser DevTools to find these APIs, then scrape them directly without JS rendering for better performance and lower costs.

Cost Optimization

JS rendering costs 4x more than basic scraping. Here's how to minimize costs:

1. Use Auto Mode

Set mode: "auto" and let AlterLab detect when JS is needed. We'll try cheaper methods first.

2. Set Cost Controls

Limit how much you're willing to spend per request:

JSON
{"url":"https://example.com","cost_controls":{"max_tier":"3",// Don't escalate beyond stealth"max_cost":0.001,// Cap at $0.001 per request"prefer_cost":true// Optimize for lowest cost}}

3. Cache Results

Enable caching for pages that don't change frequently:

JSON
{"url":"https://example.com","cache":true,"cache_ttl":3600// Cache for 1 hour}

Troubleshooting

Content is empty or incomplete

  • Try using wait_for with a specific selector
  • Increase the timeout value
  • Use wait_condition: "networkidle"

Page shows "Please enable JavaScript"

  • Make sure render_js: true is set in advanced options
  • The site may have additional anti-bot measures - try using a higher tier

Request times out

  • Increase timeout (max 300 seconds)
  • Use sync: false for long-running scrapes
  • Check if the selector in wait_for actually exists

Getting blocked or CAPTCHAs

  • AlterLab automatically handles most anti-bot measures
  • For persistent blocks, we'll escalate to CAPTCHA-solving tier automatically
  • Consider using your own proxies with use_own_proxy: true