By use case · Node.js
Node.js web scraping API for JavaScript web scraping, crawling and Puppeteer alternatives
The short answer
A Node.js web scraping API is an HTTP endpoint you call from your own JavaScript instead of installing Cheerio, Puppeteer and a proxy layer inside your app. With ClawEngine you POST a URL, and optionally a schema of the fields you want, then read back clean markdown or typed JSON with the page already rendered. Native fetch is enough, so there is no SDK and no Chromium binary in your Docker image. Cheerio is still the right call for small static pages, and Playwright is still the right call when you need to click through a flow you own. The API takes over when content is built in the browser, when selectors keep breaking, or when a crawl has to run unattended. Plans start at $39 a month.
Clean markdown & JSON · JavaScript rendered · robots.txt respected
Last updated July 2026
Hit Extract to turn this page into clean, LLM-ready data.
robots.txt respected · public data only
Node is a good place to scrape from, right up to the moment you deploy. Locally, `puppeteer.launch()` feels like nothing. Then the container image passes a gigabyte, the Lambda cold start doubles, Chromium wants shared memory your orchestrator will not give it, and someone spends a Friday pinning `@sparticuz/chromium` to a version that matches the Puppeteer major. None of that work produced a single field of data. It just kept the browser alive.
ClawEngine moves that half of the job to a server. From Node you send one POST with the target URL, pick markdown or JSON, and pass a schema if you want typed output. Rendering runs remotely, so a Next.js or Vue page that returns a hollow `<div id="root">` to a plain fetch comes back with its content in place. Crawling is the same request with a seed URL and scope patterns instead of one address, which means an entire docs site or category tree arrives without you writing a frontier queue, a visited set, a politeness delay and a retry wrapper on top of `undici`.
Here is the part most vendors skip. Cheerio is excellent and you should keep using it. If the markup is server rendered, the selectors are stable, and the volume is a few hundred pages, `fetch` plus `cheerio.load()` is faster than any network round trip to a third party and costs nothing. Playwright and Puppeteer are also genuinely better than an API for anything interactive: driving a form on your own staging site, screenshotting a dashboard behind your own session, or running end to end tests. Those are control problems, and control is what a local browser gives you.
The trade flips when the failure modes become operational rather than logical. Client-side rendering you cannot see with `curl`. Twenty different source layouts that each need their own selector file. A nightly job that has to survive a marketing redesign without paging anyone. A serverless function where a 900 MB browser bundle is simply not an option. At that point the useful question is not whether Cheerio could do it, since it usually could with enough glue, but whether your team wants to own the glue. Teams building RAG pipelines, price trackers, lead enrichment and agent tools generally do not.
Any URL in LLM-ready data out
robots.txt respected public data only
Why it works
What you get with Node.js
No Chromium in your image
Native fetch and an API key replace Puppeteer, the browser binary and the memory it needs. Docker images stay small and serverless functions stay under their limits.
Rendered before you see it
React, Vue and Svelte pages that hand a plain fetch an empty root element come back complete, because rendering finishes server side before extraction starts.
Schemas instead of selectors
Describe the fields you want and get a typed object back. A source redesign stops being a pull request against a file full of CSS selectors.
What it handles
Any URL in, clean structured data out
Point ClawEngine at a public page and it crawls, renders the JavaScript and extracts clean markdown or typed JSON in one call. Define a schema for structured fields, and respect robots.txt and Terms of Service by default.
- Works with native fetch, no SDK to install
- Returns clean markdown or typed JSON
- Renders React, Vue and Svelte pages remotely
- Crawls a whole site from one seed URL
- Runs fine in Lambda, Workers and small containers
- Feeds LangChain.js, vector stores and queues directly
{
"url": "https://example.com/products/atlas",
"title": "Atlas Field Notebook",
"markdown": "# Atlas Field Notebook\n\nDurable...",
"data": {
"name": "Atlas Field Notebook",
"price": 24.00,
"currency": "USD",
"rating": 4.7
},
"links": [ "/products", "/cart" ],
"metadata": { "rendered": true }
}
Why ClawEngine
One API that crawls, renders and extracts
Not a raw HTML dump, not a headless browser fleet to run, and not a brittle parser to maintain. One call crawls a public page, renders its JavaScript and returns clean markdown or typed JSON, built for RAG pipelines and AI agents.
LLM-ready output
Clean markdown or typed JSON with the boilerplate stripped, so the data drops straight into a vector store, a prompt or an agent without a cleanup step.
JavaScript rendered
Each page loads in a real browser environment before extraction, so single-page apps and client-rendered content come back complete, not as an empty shell.
Compliance-first
ClawEngine works on public, permitted data only. It respects robots.txt and site Terms of Service and honors crawl-delay, so responsible scraping is the default.
Code examples
Scrape a page from Node in one call
No SDK, no browser binary. Send a URL and the fields you want with native fetch and read a typed object back. Swap the endpoint for /crawl to pull a whole site.
const BASE = "https://api.clawengine.ai/v1";
const headers = {
Authorization: `Bearer ${process.env.CLAWENGINE_API_KEY}`,
"Content-Type": "application/json",
};
const res = await fetch(`${BASE}/extract`, {
method: "POST",
headers,
body: JSON.stringify({
url: "https://example.com/products/widget-pro",
format: "json",
render: true, // content is built client-side
schema: {
product_name: "string",
price: "number",
currency: "string",
in_stock: "boolean",
},
}),
});
if (!res.ok) throw new Error(`extract failed: ${res.status}`);
const { data } = await res.json();
console.log(data.product_name, data.price, data.currency);
import { mkdir, writeFile } from "node:fs/promises";
const BASE = "https://api.clawengine.ai/v1";
const job = await fetch(`${BASE}/crawl`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CLAWENGINE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/docs",
include: ["/docs/*"], // stay inside the docs tree
max_pages: 400,
format: "markdown",
}),
}).then((r) => r.json());
await mkdir("./corpus", { recursive: true });
for (const page of job.pages) {
const name = new URL(page.url).pathname.replaceAll("/", "_") + ".md";
// markdown arrives without nav, banners or script tags, so chunk it directly
await writeFile(`./corpus/${name}`, `# source: ${page.url}\n\n${page.markdown}`);
}
console.log(`wrote ${job.pages.length} pages`);
const BASE = "https://api.clawengine.ai/v1";
const headers = {
Authorization: `Bearer ${process.env.CLAWENGINE_API_KEY}`,
"Content-Type": "application/json",
};
async function extract(url) {
const res = await fetch(`${BASE}/extract`, {
method: "POST",
headers,
body: JSON.stringify({ url, format: "json", render: true,
schema: { title: "string", published_at: "string", author: "string" } }),
signal: AbortSignal.timeout(90_000),
});
if (!res.ok) return { url, error: res.status };
return { url, ...(await res.json()).data };
}
// hand-rolled pool: keep your own concurrency sane, no p-limit needed
async function pool(urls, size = 8) {
const queue = [...urls];
const out = [];
const worker = async () => {
for (let next = queue.shift(); next; next = queue.shift()) {
out.push(await extract(next));
}
};
await Promise.all(Array.from({ length: size }, worker));
return out;
}
const rows = await pool(["https://example.com/a", "https://example.com/b"]);
console.table(rows);
People also ask
Node.js web scraping API: the questions buyers ask
How do I scrape a website in Node js?
Fetch the page and parse it, or call an API that does both. The classic route is `fetch()` for the HTML and Cheerio for the selectors, which works whenever the server sends real markup. If the content appears only after JavaScript runs, you either launch Puppeteer or Playwright locally, or POST the URL to a scraping API and read back rendered markdown or typed JSON.
Is Puppeteer or Cheerio better for web scraping?
Cheerio is better whenever the HTML already contains your data, because it is a parser with no browser attached and it runs in milliseconds. Puppeteer is better when the page builds itself in the browser or you need to click, scroll and wait. The cost difference is large: Cheerio adds a small dependency, Puppeteer adds Chromium plus the operational care it needs in production.
Can Node js scrape JavaScript rendered pages?
Yes, but not with fetch alone, since fetch returns the same empty shell the server sent. Your options are running a headless browser through Puppeteer or Playwright, or sending the URL to a service that renders it and returns the finished DOM as markdown or JSON. The first keeps everything in your process and adds a browser to maintain. The second keeps your deployment small.
What is the best Node js web scraping library?
There is no single best one, only a best fit. Cheerio for parsing static HTML, Playwright for interactive or client-rendered pages, Crawlee when you want a full crawling framework with queues and session handling, `undici` when you just need fast HTTP. An API replaces the combination rather than any one of them, and it is worth it mainly when maintenance, not capability, is your bottleneck.
How do I avoid getting blocked when scraping?
Scrape like a well behaved client instead of trying to look like a different one. Read robots.txt and follow it, send a User-Agent that identifies who you are, cap concurrency, respect crawl-delay, back off on 429 and 503 rather than retrying instantly, and cache so repeat runs do not refetch unchanged pages. If a site still refuses you, treat that as an answer and find a licensed source.
How much does a Node js web scraping API cost?
Pricing is usually per request or per credit, with rendered pages costing more than plain fetches. ClawEngine is $39 a month on Hobby, $99 on Startup and $399 on Scale, with Enterprise quoted, and there is no free plan. Compare it against the hours you spend upgrading Chromium images and repairing selectors, not against the zero on the Cheerio npm page.
Good questions
Questions about Node.js
Explore more
More ways to turn the web into data with ClawEngine
Stop wrangling raw HTML. Get LLM-ready data.
Point ClawEngine at a public page and one call crawls, renders the JavaScript and extracts clean markdown or typed JSON, ready for your RAG pipeline or AI agent. Public, permitted data only.
Crawl · render JS · extract markdown & JSON · robots.txt respected, public data only