JavaScript-rendered HTML, one parameter away.
Fresh Headless Chrome per request. wait_for_selector for dynamic content, js_snippet for clicks and scrolls, residential proxies and geo-targeting in the same call. No browser pool to run, no Docker, no Puppeteer code.
10,000 free credits · failed requests cost 0 · React · Vue · Angular · Next.js · Svelte
# Flip browser=true and you get the rendered DOM, not the JS shell.
$ curl -G "https://api.scrapingant.com/v2/general" \
--data-urlencode "url=https://spa-app.com/products" \
--data-urlencode "browser=true" \
--data-urlencode "wait_for_selector=.product-card" \
-H "x-api-key: YOUR_API_KEY"
<!DOCTYPE html>
<!-- fully rendered, post-hydration -->import requests
import base64
# Click "load more" before returning the HTML
js = "document.querySelector('.load-more').click();"
resp = requests.get(
"https://api.scrapingant.com/v2/general",
params={
"url": "https://example.com/feed",
"browser": "true",
"js_snippet": base64.b64encode(js.encode()).decode(),
"wait_for_selector": ".item:nth-child(50)",
},
headers={"x-api-key": "YOUR_API_KEY"},
)
print(resp.text)const qs = new URLSearchParams({
url: "https://dashboard.example.com",
browser: "true",
wait_for_selector: ".charts-loaded",
block_resource: "image,media,font",
proxy_type: "residential",
proxy_country: "us",
});
const res = await fetch(
`https://api.scrapingant.com/v2/general?${qs}`,
{ headers: { "x-api-key": "YOUR_API_KEY" } },
);
const html = await res.text();// Without browser=true — the SPA shell:
<div id="root"></div>
<script src="/static/js/bundle.js"></script>
// With browser=true and wait_for_selector — the rendered DOM:
<div id="root">
<header>...</header>
<main class="dashboard">
<section class="charts-loaded">...</section>
<table>... 5,000 rows ...</table>
</main>
</div> Built for the modern web.
Three controls that turn an HTTP fetch into a real browser session — without an HTTP fetch turning into a Kubernetes cluster.
Headless Chrome per request
Fresh browser instance, real fingerprint, full JS execution. No shared profiles, no leftover state.
See the diff →wait_for_selector
Wait until the element you actually need exists. Stops returning empty shells from SPAs that hydrate after first paint.
How it works →js_snippet
Run any JS in the page before the response — click, scroll, fill, scroll again. Base64 in, rendered DOM out.
Examples →Modern sites render client-side.
React, Next.js, Vue, Angular, Svelte — most of the web you actually want to scrape ships an empty <div id="root"> and a JS bundle, then renders the real content in the browser. Plain HTTP fetches see the shell. A single browser=true parameter routes the request through real headless Chrome and returns the post-hydration DOM.
- Same Chrome you'd run locally — same DOM, same selectors
- No Selenium, no Puppeteer, no Playwright on your side
- No Docker image, no browser pool to size, no zombie processes
Wait for the part you actually need.
SPAs and AJAX-heavy pages settle in stages. wait_for_selector tells ScrapingAnt to hold the response until your CSS selector appears in the DOM — then return the fully populated HTML. No more empty <tbody> tags coming back from sites that load rows over XHR after the initial paint.
- Infinite scroll lists — wait for the last item before returning
- Lazy-loaded product grids — wait for the loaded class
- Client-side dashboards — wait for the chart to mount
- Bumps the response timeout to
timeout=180when needed
Run JavaScript in the page.
Need to click a button, scroll past a paywall, expand an accordion, fill a form, dismiss a cookie banner — anything page.evaluate() would do in Playwright? Encode the JS as base64, pass it as js_snippet, and ScrapingAnt runs it inside the browser before returning the HTML.
- Click, scroll, type, submit — anything the DOM API supports
- Stack with
wait_for_selectorto wait for results of your snippet - Same Chrome runtime as the page, no sandbox surprises
Four extra knobs when you need them.
Browser rendering opens up four more parameters that map cleanly to Playwright equivalents — without the corresponding code on your side. Trim bandwidth on bloated pages, switch between datacenter and residential proxies per call, country-pin requests, or grab the raw page source for debugging.
block_resource=image,media,fonttrims most pages by 60–80%proxy_type=residentialfor tougher anti-bot walls — same callproxy_country=usfor geo-restricted content across 25+ regionsreturn_page_source=trueto see what the server sent before JS
Where the browser flag earns its keep.
Six common shapes of dynamic pages that fall over without real JS execution.
React / Next.js / Vue / Angular
Anything client-rendered. The agent gets the post-hydration DOM, not <div id="root"> and a bundle reference.
Infinite scroll & lazy lists
Scroll to the bottom inside the page via js_snippet, wait for the last item with wait_for_selector, return everything.
AJAX-loaded data tables
Wait for the rows to populate, then grab the rendered HTML. No need to reverse-engineer the XHR call yourself.
Talk to us →Live dashboards behind auth
Pass cookies/headers, wait for the chart to render, return the populated DOM. Same flow as a real user.
Talk to us →Geo-restricted content
Set proxy_country=us (or any of 25+ regions) and the rendered page reflects what a local visitor would see.
Anti-bot-walled SPAs
Cloudflare-protected React app? proxy_type=residential + headless Chrome handles the challenge in the background.
Pricing
Industry leading pricing that scales with your business.
|
Plans
|
Enthusiast
100K credits / mo
$19/mo
|
★ Most Popular
Startup
500K credits / mo
$49/mo
|
Business
3M credits / mo
$249/mo
|
Business Pro
8M credits / mo
$599/mo
|
Custom
10M+ credits / mo
$699+/mo
|
|---|---|---|---|---|---|
| Monthly API credits | 100,000 | 500,000 | 3,000,000 | 8,000,000 | 10M+ |
| Support channel | Priority email | Priority email | Priority email | Priority + dedicated | |
| Integration help | Docs only | Custom code snippets | Debug sessions | Priority debug sessions | Full enterprise onboarding |
| Expert assistance | — | ||||
| Custom proxy pools | — | — | |||
| Custom anti-bot avoidances | — | — | |||
| Dedicated account manager | — | — | |||
| Start Free | Start Free → | Start Free | Start Free | Talk to Sales |
What teams are saying.
From solo developers shipping side projects to enterprise pipelines at Fortune 500s.
★★★★★ 5.0 on Capterra →★★★★★“Onboarding and API integration was smooth and clear. Everything works great. The support was excellent.”
★★★★★“Great communication with co-founders helped me to get the job done. Great proxy diversity and good price.”
★★★★★“This product helps me to scale and extend my business. The setup is easy and support is really good.”
Frequently asked questions.
Still curious? Get in touch with our team — we usually reply within hours.
What is a JavaScript rendering API?
A JavaScript rendering API is a managed scraping endpoint that loads each request through real Headless Chrome, runs the page's JavaScript, waits for content to settle, and returns the post-hydration DOM as HTML. ScrapingAnt's /v2/general endpoint is one of them: pass a URL with browser=true and you get back the rendered HTML — same as opening “View Source” in a real browser after the SPA finished mounting. Compared to running Puppeteer / Playwright yourself, you skip browser binaries, crash recovery, retries, anti-bot handling, and the cluster scaling that goes with all of it. If you need cleaned Markdown instead of HTML, point at /v2/markdown; if you need typed JSON, point at /v2/extract.
What do I get back from a JavaScript rendering request?
When you set browser=true, ScrapingAnt returns the fully rendered HTML after all JavaScript has executed — dynamically loaded content, AJAX responses, post-hydration DOM, anything client-side scripts wrote in. Same HTML you'd see if you opened “View Source” in a real browser after the page settled.
How long can a JavaScript-rendered request run?
Default browser-rendered requests time out at 30 seconds. For complex SPAs or slow-loading pages, extend it with timeout up to 180 seconds. Pair with wait_for_selector to make sure the response only fires after the content you actually need is there.
Can I turn JavaScript rendering off?
Yes — browser=false (the default) uses simple HTTP fetching with no JavaScript execution. Faster, fewer credits per request, perfect for static pages or APIs. Only flip browser=true when the target requires it.
How many API credits does JavaScript rendering cost?
Browser-rendered requests cost 10 credits with standard datacenter proxies, 125 credits with residential proxies. Reduce the bill by setting block_resource=image,media,font to skip non-essential assets. Failed requests cost 0. Every account starts with 10,000 free credits per month, no card required.
How is this different from running my own Puppeteer or Playwright?
You skip browser binaries, crash recovery, proxy rotation, anti-bot handling, and the cluster scaling that goes with all of it. We run that infrastructure; you make a single HTTP call. Same Chrome, same selectors, none of the upkeep. See our dedicated Playwright alternative page for a side-by-side breakdown.
Can I call the JavaScript rendering API from an AI agent?
Yes. The same rendering pipeline is exposed through the ScrapingAnt MCP server as get_web_page_html / get_web_page_markdown / get_web_page_text. Drop the MCP URL into Claude, Cursor, Windsurf, or Claude Code and the agent reads JavaScript-rendered pages mid-conversation — no glue code.
Need a custom plan?
High-volume pricing, residential pool tuning, dedicated infrastructure, custom scrapers — drop us a line and a real human gets back within a few hours.
“Our clients are pleasantly surprised by the response speed of our team.”