What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Cheerio is usually faster when the HTML you need is already in the HTTP response. It parses markup without launching a browser or executing page JavaScript. Puppeteer is slower for that narrow task because it starts and controls a browser, but it is the right choice when JavaScript, clicks, scrolling, authentication, or other browser state creates the data you need. The useful question is not “which library wins universally?” but “what content state must I reach?”

There is no reliable, apples-to-apples speed ratio to quote. Results depend on page size, browser version, network, concurrency, extraction work and machine. Use the decision flow below, then benchmark your own representative workload if latency is important.

Cheerio and Puppeteer do different jobs

Question Cheerio Puppeteer
Main job Parse and manipulate HTML or XML supplied by your code. Control Chrome or Firefox through browser automation protocols.
Runs page JavaScript? No. Yes, as part of browser execution.
Renders CSS and loads page resources? No. Yes, according to the browser state you create.
Best input A response whose target data is already in the markup. An app shell or page whose data appears after scripts or interaction.
Typical overhead Package startup plus parsing the supplied bytes. Browser installation, launch, navigation, rendering and lifecycle management.

Cheerio’s documentation describes it plainly: “Cheerio is not a web browser.” Its jQuery-like API is useful after you have obtained HTML; it is not a replacement for a browser. Puppeteer’s project describes its library as a high-level API for controlling Chrome or Firefox over DevTools Protocol or WebDriver BiDi.

Is Cheerio faster than Puppeteer?

For static HTML parsing, generally yes. Cheerio does not pay for browser startup, page rendering, script execution, layout, or resource loading. That is a capability-based conclusion, not a measured percentage. Puppeteer performs substantially more work, but that work is what lets it expose content that Cheerio cannot produce from the initial response.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why a universal speed number would mislead

A comparison that parses one saved HTML string with Cheerio and compares it with a full Puppeteer navigation is not an apples-to-apples benchmark. The two programs are solving different problems. A valid test must specify the same URLs, network conditions, browser and library versions, concurrency, machine, wait conditions and extraction result. The available comparison evidence does not provide such a controlled benchmark or a trustworthy milliseconds, throughput or memory ratio.

Where Puppeteer can be the faster overall solution

If a site returns only an empty application shell, Cheerio may finish quickly while returning no records. You would then need another request or reverse-engineering effort. Puppeteer may take longer per page but complete the actual task in one browser workflow. “Fastest” should mean time to correct data, not merely time until a process exits.

Choose the required data source

  1. Obtain the response. Use your authorized HTTP client and keep the received HTML.
  2. Look for the target data. Search the source for a known title, product ID, table row, JSON fragment or CSS selector.
  3. If it is present, parse with Cheerio. Pass the string, buffer or stream to Cheerio and extract only the fields you need.
  4. If it is absent, identify the browser requirement. An app shell, client-side fetch, click, scroll, login state or consent flow indicates a browser automation step.
  5. Use Puppeteer when that state is required. Navigate, wait for a meaningful selector or network condition, interact, then read the resulting DOM.

Cheerio example: parse HTML you already received

Install Cheerio in a Node.js project:

npm install cheerio

This complete example parses a local response string. In production, obtain the HTML with your permitted HTTP client and handle status codes and timeouts before parsing.

import * as cheerio from 'cheerio';

const html = `<ul class="products">
  <li class="product" data-id="42">
    <a class="name" href="/item/42">Keyboard</a>
    <span class="price">$49</span>
  </li>
</ul>`;

const $ = cheerio.load(html);
const products = $('.product').map((_, el) => ({
  id: $(el).attr('data-id') ?? null,
  name: $(el).find('.name').text().trim(),
  price: $(el).find('.price').text().trim(),
  href: $(el).find('.name').attr('href') ?? null
})).get();

console.log(products);

Cheerio’s loading guide documents loaders for strings, buffers, streams and URLs. Treat a URL supplied by an untrusted user as a security-sensitive input and follow the project’s URL-loading guidance rather than blindly fetching it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Parser choice inside Cheerio

parse5 is Cheerio’s default HTML parser. Cheerio documents htmlparser2 as faster and lower-memory, while noting that it is a different parser option. Consider htmlparser2 for performance-critical parsing only after confirming that its parsing behavior matches your input and selectors. It does not add JavaScript execution or browser rendering.

Puppeteer example: wait for browser-rendered data

Install the full package:

npm install puppeteer

The full puppeteer package downloads a compatible browser during installation. The installation guide lists approximate Chrome for Testing download sizes of 170 MB on macOS, 282 MB on Linux and 280 MB on Windows. Those are download sizes, not runtime RAM measurements. Use puppeteer-core when you manage a browser separately or connect to a remote browser.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
try {
  const page = await browser.newPage();
  await page.goto('https://example.com/catalog', {
    waitUntil: 'domcontentloaded',
    timeout: 30_000
  });
  await page.waitForSelector('.product', { timeout: 15_000 });

  const products = await page.$$eval('.product', nodes => nodes.map(node => ({
    name: node.querySelector('.name')?.textContent?.trim() ?? null,
    price: node.querySelector('.price')?.textContent?.trim() ?? null
  })));
  console.log(products);
} finally {
  await browser.close();
}

Choose a wait condition that represents usable data. A fixed delay can be wasteful when a page is ready early and insufficient when it is slow. A selector tied to the result is usually more meaningful; network-idle waiting can help when the page’s requests are predictable.

Why is my Cheerio selection empty?

The response is an application shell

Open the raw response, not just the browser’s Elements panel. If it contains a root element and script tags but no product, article or table records, the browser is expected to create them later. Use Puppeteer or find an authorized data endpoint that returns the records directly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The selector does not match the received markup

Log a short, sanitized portion of the HTML and verify class names, nesting and casing. Check whether the data is in an attribute, a script block or a different element than the rendered view suggests.

The content is in a different response

Some pages load data through subsequent requests. Cheerio only sees the bytes you give it. Capture and inspect the relevant response using your normal HTTP tooling, or let Puppeteer execute the page and then query the resulting DOM.

The page requires state

Cookies, authentication, a click, scrolling or a consent choice can change what is returned or rendered. Reproduce that state with a browser workflow when it is legitimate and permitted.

Setup, reliability and cost trade-offs

Cheerio operational profile

  • Small input-to-output path when HTML is already available.
  • No browser binary to install or keep alive.
  • Predictable parsing work, with parser choice affecting speed and memory.
  • No CSS layout, JavaScript, external-resource loading or interaction.

Puppeteer operational profile

  • Browser download and configuration are part of deployment unless you use a separately managed browser.
  • Launches, pages and contexts need explicit cleanup; always close the browser in a finally path.
  • Navigation, rendering and waits introduce variable latency tied to the target site.
  • Browser capabilities justify the cost when the required state cannot be obtained from raw HTML.

Installation failures

If package-manager install scripts are blocked, Puppeteer may skip its browser download. Install a compatible browser separately and configure its executable path, or use puppeteer-core with a managed browser. Do not assume that installing the Node package alone provides a runnable browser in that environment.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How to benchmark your own workload

  1. Freeze versions of Node.js, Cheerio, Puppeteer and the browser.
  2. Use the same page set, region, network path and authorization state.
  3. Define the same output fields and correctness checks.
  4. Warm up each process, then record multiple runs rather than one lucky result.
  5. Test the concurrency you will actually deploy and record failures, timeouts and incomplete pages.
  6. Report latency and resource use with the conditions attached; do not generalize one machine’s result to every workload.

For static pages, compare the complete fetch-plus-parse pipeline against your alternative. For dynamic pages, compare complete browser workflows, including waits and interactions. Otherwise you are measuring different jobs.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

When your goal is a clean screenshot rather than extracted DOM data, ScreenshotNeo provides a website screenshot API and MCP server. One request can return PNG, JPEG, WebP or PDF. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers identify the page verdict and billing status.

Use the documented options for full-page captures with lazy images, CSS-selector element shots, dark mode, device presets or custom viewports, retina scale, PDF paper size and ranges, custom CSS or JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks and bulk capture of up to 100 URLs per call. An MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo documentation for parameters and response headers. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Decision checklist

  • Use Cheerio when the target bytes are already in the response and you need parsing or transformation.
  • Use Puppeteer when scripts, rendering or interaction creates the target state.
  • Use Cheerio’s htmlparser2 option only after checking its parsing requirements against the default parse5 behavior.
  • Benchmark complete, representative workflows when a numeric speed decision matters.
  • Use a screenshot API when the deliverable is a visual capture rather than structured extracted data.

Frequently Asked Questions

Does Cheerio execute JavaScript?

No. It parses the markup supplied to it; it does not run page scripts or render a browser view.

Can Puppeteer replace Cheerio?

Puppeteer can read browser-rendered DOM, but it adds browser setup and execution. For already-received static HTML, Cheerio is the simpler path.

Is puppeteer-core smaller than puppeteer?

puppeteer-core does not bundle a compatible browser and is intended for remote or independently managed browsers; the full package downloads one during installation.

Should I use a fixed delay in Puppeteer?

Prefer a condition tied to usable content, such as a result selector, when possible. Fixed delays can be either wasteful or too short.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.