NEW ScrapingAnt MCP for Claude Code, Cursor & Windsurf — try it free →
★★★★★ 5.0 on Capterra

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>
browser=false RAW HTML <!DOCTYPE html> <html> <head>...</head> <body> <div id="root"></div> <script src= "/bundle.js"> </body> </html> CONTENT JS shell PLAIN HTTP FETCH vs browser=true RENDERED DOM <div id="root"> <header>...</header> <main> <h1>Dashboard</h1> <table> <tr>...</tr>×5k </table> </main> </div> CONTENT real DOM HEADLESS CHROME flip browser=true · same key, same call
without browser=true empty // what your code receives <!DOCTYPE html> <html> <body> <div id="root"></div> <script src="/bundle.js"></script> + browser=true with browser=true populated // what your code receives <div id="root"> <header>...</header> <main class="dashboard"> <table> ... 5,000 rows ... </table> </main>
The rendering problem

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
$ curl …/v2/general ?browser=true&wait_for_selector=.charts-loaded 1 navigate load /products 2 wait .charts-loaded to appear 3 return populated DOM timeout cap: 30s default · 180s max // agent code stays a single fetch const html = await r.text(); // already populated · no polling on your side
wait_for_selector

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=180 when needed
js_snippet (base64-encoded) // scroll to bottom window.scrollTo(0, document.body.scrollHeight); // click load-more document.querySelector(".load-more").click(); // dismiss cookie banner document.querySelector("#accept")?.click(); // fill a form field document.querySelector("#zip").value = "94110"; document.querySelector("#submit").click(); runs inside Chrome before the HTML returns click scroll type / submit → rendered HTML reflects every action
js_snippet

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_selector to wait for results of your snippet
  • Same Chrome runtime as the page, no sandbox surprises
js_snippet docs →
return_page_source Get the raw HTML — pre-JS, as the server sent it. Useful for debugging the diff between source & rendered DOM. block_resource Skip image, font, media, or stylesheet downloads. Faster page loads · fewer credits on bandwidth-heavy pages. proxy_type datacenter · residential 50K+ DC IPs (cheap, fast) 2M+ residential (anti-bot). proxy_country us · de · uk · jp · … 25+ countries — geo-restricted content & localized pricing.
Advanced controls

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,font trims most pages by 60–80%
  • proxy_type=residential for tougher anti-bot walls — same call
  • proxy_country=us for geo-restricted content across 25+ regions
  • return_page_source=true to see what the server sent before JS
Pricing

Industry leading pricing that scales with your business.

Compare plans side by side. Every tier includes 10,000 free credits to start.
👈Swipe to compare all 5 plans👉
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 Email 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 included included included included
Custom proxy pools included included included
Custom anti-bot avoidances included included included
Dedicated account manager included included included
Start Free Start Free → Start Free Start Free Talk to Sales
Hit your limit mid-month?
Restart your plan instantly — no waiting for the next billing cycle. Credits refresh the moment you pay, so scraping never has to stop.
10,000 free credits every month
No credit card required
Pay only for successful scrapes — failed requests cost 0
Customers

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.

Illia K.
Android Software Developer
★★★★★

“Great communication with co-founders helped me to get the job done. Great proxy diversity and good price.”

Andrii M.
Senior Software Engineer
★★★★★

“This product helps me to scale and extend my business. The setup is easy and support is really good.”

Dmytro T.
Senior Software Engineer
FAQ

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.

Talk to us

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

Oleg Kulyk
Founder, ScrapingAnt

A real human replies within a few hours · we don't share your email

Thanks — we'll be in touch shortly.
Something went wrong submitting the form. Please try again or email us directly.

Ready to scrape the web?

10,000 free credits every month. No credit card. Pay only for successful requests.

Sign up in under 30 seconds — no card, no commitment.