Skip to main content

Confirm

Are you sure?

Rendered HTML API

The HTML after JavaScript, not the source

Everything a browser built from the page, serialized — so your parser, your tests or your scraper see what a visitor sees.

By · Last updated: September 2026

TL;DR

POST a URL to /html and get the page's rendered DOM as a string: the document after headless Chrome has run its JavaScript and followed its redirects — what you see in DevTools' Elements panel, not View Source. wait_for_selector holds the capture until late content arrives. 1 credit per page.

Free plan, no credit card. 1,000 credits a month.

Try it now — no signup

Try it on a page

Try your own URL

Free · no signup · 2 runs every 10 minutes

Your result will appear here.

Pick one of the pages above to get started.

The request

One POST, one bearer token

POST /html
curl -X POST https://urlpipe.dev/html \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/app/pricing", "sync": true, "page_options": {"wait_for_selector":"#pricing-table"}}'
Response (text/plain)
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Pricing — Example</title>
    …
  </head>
  <body>
    <div id="root">
      <main>
        <h1>Pricing</h1>
        <table id="pricing-table">
          <tr><th>Starter</th><td>$19/mo</td></tr>
          …
        </table>
      </main>
    </div>
  </body>
</html>

The difference

Rendered DOM vs source

A server sends HTML — the source. A browser parses it and runs the page's scripts, which add, remove and rewrite elements. On a server-rendered page the two are nearly the same. On a single-page app the source is an empty container and a bundle, and every heading, price and paragraph arrives later. /html returns the rendered DOM.

curl / requestsURLpipe /html
JavaScriptNot runRun in headless Chrome
Content on a React/Vue/Angular appUsually missingPresent
RedirectsIf you askFollowed
Late contentNowait_for_selector, delay
Cookie banners, adsIn the markupRemovable with page_options
CostOne HTTP request1 credit per page

A quick test for whether you need this: fetch the page with curl and search for a sentence you can see in the browser. If it isn't there, the page is rendered by script. The rendered vs raw HTML guide goes deeper.

Page options

Waiting for the content you want

"Loaded" is not the same as "done". Prices that come from an API call, reviews that load on scroll, a dashboard that renders after authentication checks — all arrive after the load event. page_options handle it:

  • wait_for_selector — wait up to 10 seconds for an element matching a CSS selector. If it never appears the request fails, and costs nothing.
  • delay — wait up to 10,000 ms more after the page settles.
  • block_ads, block_cookie_banners, remove_selectors — take clutter out of the document before it is serialized. Ad-heavy pages usually load much faster with ads blocked.

Residential

Pages that turn datacentre visitors away

Most pages come back complete from our standard network, and when a site puts a bot check in front of us we work it and retry before you hear about it. When that isn't enough — a site that won't serve a datacentre address, or one that serves it a thinner page — send residential: true to load the page from a home-ISP connection. It adds 25 credits per page visit, it is one exit rather than a rotating pool, and it is not a guarantee: a site that blocks every automated visitor blocks this one too. See residential exits.

Bot checks we couldn't clear, target 4xx and 5xx responses and robots.txt refusals are never billed. Every project follows robots.txt by default; you can turn that off per project, and you are then responsible for having the right to fetch the pages you request.

In practice

Parsing it

The response body is the document as a string, so any HTML parser takes it as it is:

Rendered HTML into BeautifulSoup
import requests
from bs4 import BeautifulSoup

res = requests.post(
    "https://urlpipe.dev/html",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "url": "https://example.com/app/pricing",
        "page_options": {"wait_for_selector": "#pricing-table"},
        "sync": True,
    },
)
soup = BeautifulSoup(res.text, "html.parser")
prices = [td.get_text(strip=True) for td in soup.select("#pricing-table td")]

Common jobs: extracting data with your own selectors from sites that render client-side; checking what a JavaScript site actually puts in front of a search engine that renders; snapshotting pages as test fixtures; and feeding your own extraction or diffing pipeline. For many URLs, drop sync and let results arrive at your webhook — requests are async by default, and your plan's parallel-request limit sets how many run at once.

Choosing

Rendered HTML, or something smaller?

Take the HTML when you parse it yourself — CSS selectors, XPath, your own extraction rules, or a snapshot for tests. If the next step is a language model, /markdown costs the same and returns the content without the markup, several times fewer tokens. For the title, image and dates, /meta returns them as fields. /scrape gives you the HTML plus any of those from one page visit.

Limits

What it does not do

  • No interaction. No clicks, form fills, logins or scripted steps before capture.
  • No custom headers or cookies on the request to the target, and no URLs with credentials in them.
  • No error pages. A target that answers 404 or 500 is reported as a failure (and not billed), not returned as HTML.
  • No crawling. One URL per request; there is no link following.
  • No non-HTML. PDFs, images and downloads are refused as not a web page.
  • Public pages only. Private and loopback addresses, including ones reached by redirect, are refused.

Pricing

What it costs

CallCreditsFree (calls/mo)Starter (calls/mo)Pro (calls/mo)Scale (calls/mo)
/html1 credit1,00020,00055,000175,000

Cache hits and failed requests cost nothing. Paid plans are never cut off: past the allowance, extra credits are $1.50 per 1,000 credits. See every plan.

FAQ

Frequently asked questions

What is the difference between rendered HTML and page source?
The source is what the server sent. The rendered HTML is the document after the browser ran the page's JavaScript — what DevTools' Elements panel shows. On single-page apps only the rendered HTML has the content.
Does it follow redirects?
Yes. The page is loaded in a real browser, which follows redirects to the final page. A redirect to a private or loopback address is refused.
How do I wait for content that loads after the page?
Send page_options.wait_for_selector with a CSS selector for the element you need. The capture waits up to 10 seconds for it; if it never appears, the request fails and costs nothing.
Can I send cookies or log in first?
No. The API loads public pages as an anonymous visitor, with no custom headers, cookies or scripted steps.
How much does it cost?
1 credit per page, plus 25 credits per visit if you ask for a residential exit. Cache hits and failed requests are free.

Make your first request in five minutes.

Free plan, no card. Confirm your email and your API key is live — you'll be making real requests in minutes.