Comparison7 min read

Cheerio vs Puppeteer

Short answer

Cheerio is an HTML parser: it reads the HTML you download and lets you select elements with jQuery-style syntax, but it runs no JavaScript. Puppeteer is a real Chrome or Firefox browser driven from Node.js: it runs the page's scripts, clicks and scrolls, at the cost of far more CPU, memory and traffic. Use Cheerio when the data is in the HTML the server sends, and Puppeteer only when JavaScript builds it. Either way, ProxyField residential proxies carry the requests from $1.95/GB; start with the Easy Trial: 1 GB for $2.95.

residential IPs
412M+
from, traffic never expires
$1.95/GB
Easy Trial
1 GB for $2.95
On this page 10 sections
  1. Cheerio vs Puppeteer at a glance
  2. How to tell which one a page needs
  3. The same scrape in Puppeteer
  4. Speed, memory and proxy traffic
  5. Using Cheerio and Puppeteer together
  6. The same choice in Python: Beautiful Soup vs Selenium
  7. Proxies with Cheerio and Puppeteer
  8. Which should you use?
  9. Proxies for Node.js scrapers
  10. Cheerio vs Puppeteer FAQ

Cheerio vs Puppeteer at a glance

FeatureCheerioPuppeteer
What it is"The fast, flexible & elegant library for parsing and manipulating HTML and XML" (npm)A library that controls Chrome or Firefox over the DevTools Protocol or WebDriver BiDi (what is Puppeteer)
Version, October 20261.2.0, MIT, Node.js 20.18.1 or later25.16.0, Apache-2.0, Node.js 22.12.0 or later
Runs JavaScriptNoYes, a full browser engine
Fetches pagesOptional: cheerio.fromURL() fetches and parses in one call; for a proxy, custom headers or retries, pair load() with fetch, Axios or gotYes, the browser loads the page and its resources
Clicks, forms, scrollingNoYes
Typical cost per pageOne HTML download, a few milliseconds of parsingThe page and its scripts, images and fonts, unless you block them
Screenshots and PDFsNoYes
SelectorsCSS selectors with a jQuery-like API ($('.price').text())CSS, XPath, text and ARIA selectors through page.locator() and $$eval
Install sizeA small npm packageThe library plus a downloaded browser

Cheerio's own docs put the trade-off plainly: it does no visual rendering, no CSS, no loading of external resources and no JavaScript execution, which makes it "much faster than browser-based tools", but content a single-page app renders on the client will not be there (Cheerio introduction).

How to tell which one a page needs

Open the page, then view its source (Ctrl+U or Cmd+Option+U), not the Elements panel. If the prices, names or links you want are in that raw source, Cheerio can read them. If the source holds only an empty <div id="root"> and script tags, JavaScript builds the content in the browser, and Cheerio sees nothing.

You can test it in code. The practice site Quotes to Scrape serves the same quotes as plain HTML at / and as JavaScript-built content at /js/:

JavaScript
// npm i cheerio   (Node.js 20.18.1+ has fetch built in)
import * as cheerio from 'cheerio';

const res = await fetch('https://quotes.toscrape.com/');
const $ = cheerio.load(await res.text());
const quotes = $('.quote').map((_, el) => ({
  text: $(el).find('.text').text(),
  author: $(el).find('.author').text(),
})).get();
console.log(quotes.length, quotes[0]);   // 10 quotes

const js = await fetch('https://quotes.toscrape.com/js/');
const $js = cheerio.load(await js.text());
console.log($js('.quote').length);       // 0: the quotes are built by JavaScript

We ran this on October 23, 2026: 10 quotes from /, 0 from /js/. Before you reach for Puppeteer on a page like /js/, look for the data itself. It is often in a <script> tag as JSON or in a request the page makes to an API, and you can read either without a browser; see how to scrape hidden APIs and embedded JSON.

The same scrape in Puppeteer

Puppeteer opens the page in Chrome, lets the scripts run and reads the result:

JavaScript
// npm i puppeteer   (downloads a matching Chrome for Testing)
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://quotes.toscrape.com/js/');
await page.waitForSelector('.quote');
const quotes = await page.$$eval('.quote', els => els.map(el => ({
  text: el.querySelector('.text').textContent,
  author: el.querySelector('.author').textContent,
})));
console.log(quotes.length, quotes[0]);
await browser.close();

It gets the quotes Cheerio missed, but it starts a browser, downloads every script and stylesheet, and uses far more memory and CPU than a parser. For a tutorial that goes further (waits, infinite scroll, many pages), see web scraping with Puppeteer.

Speed, memory and proxy traffic

The difference is large because the work is different, not because one library is better written. A Cheerio scraper downloads one HTML document and parses it in memory. Puppeteer runs a browser that downloads the document plus its scripts, styles, fonts and images, and executes the JavaScript. We do not quote a ratio, because it depends on the page, but you can measure it: log the bytes of the HTML response for Cheerio, and the sum of all responses in Puppeteer.

This matters for proxy cost. Residential proxies are priced per GB, so every script, image and font a browser pulls is billed traffic. As an assumed example, a page whose HTML is 100 KB but which loads 2 MB in a browser costs about 20 times more traffic in Puppeteer than in Cheerio; measure your own pages as above. If you must use Puppeteer, block what you do not need:

JavaScript
await page.setRequestInterception(true);
page.on('request', req =>
  ['image', 'font', 'media', 'stylesheet'].includes(req.resourceType()) ? req.abort() : req.continue());

Using Cheerio and Puppeteer together

A common pattern is to let Puppeteer do only what needs a browser and hand the HTML to Cheerio: log in or click through a cookie banner in Puppeteer, take await page.content(), and parse it with cheerio.load(). Your parsing code stays the same for static and dynamic pages, and you can switch pages from the browser to plain fetch as soon as you find they do not need JavaScript. Node.js crawling libraries such as Crawlee offer both modes, an HTTP crawler with Cheerio and a browser crawler with Puppeteer or Playwright, behind one API.

The same choice in Python: Beautiful Soup vs Selenium

Python has the same split. Beautiful Soup is "a Python library for pulling data out of HTML and XML files" (Beautiful Soup docs), paired with Requests or httpx to download pages, like Cheerio with fetch. Selenium, or Playwright for Python, plays Puppeteer's role. The decision rule is identical: parse the HTML when the data is in it, start a browser only when JavaScript builds it. Python tool choices are compared in Scrapy vs BeautifulSoup vs Selenium vs Playwright, and the languages themselves in Python vs JavaScript for web scraping.

Proxies with Cheerio and Puppeteer

Cheerio can fetch a page itself with fromURL, but when you scrape through a proxy, the usual route is to fetch the HTML with an HTTP client and pass it to cheerio.load: an agent for Axios or got, or undici's ProxyAgent for fetch (Node.js proxy setup). The full Cheerio workflow, including fromURL and extract, is in Cheerio web scraping. Puppeteer takes the proxy at launch with --proxy-server=http://gate.proxyfield.io:7000 and the login through page.authenticate (Puppeteer proxy setup). With the ProxyField gateway, the username <login>-country-us-city-new_york asks for a New York exit IP, and the gateway gives each request a new IP (rotating) or keeps one IP for 30 s to 36 h (sticky).

Which should you use?

  • Data in the page source: Cheerio with fetch. Faster, lighter and less traffic per page.
  • Data in a JSON request or a <script> tag: neither; call the API or parse the JSON directly.
  • Content built by JavaScript, logins, clicks, infinite scroll: Puppeteer, with heavy resources blocked.
  • Mixed sites: Puppeteer for the steps that need a browser, Cheerio for the parsing.

More on the Node.js stack in JavaScript web scraping and HTML scraping.

Proxies for Node.js scrapers

Whether you parse with Cheerio or render with Puppeteer, a scraper that sends more than a few hundred requests to one site needs rotating IPs. ProxyField gives every request a new IP, or a sticky session up to 36 h, over HTTP, HTTPS or SOCKS5, with targeting by country, region (state) and city and unlimited concurrent threads. Residential proxies cost $2.95/GB for 1 GB and fall to $1.95/GB from 1,000 GB, with no subscription; traffic never expires, and all purchases are final. Start with residential proxies and the Easy Trial: 1 GB for $2.95.

Cheerio vs Puppeteer FAQ

Should you use Cheerio or Puppeteer for web scraping?

ProxyField residential proxies work with both from $1.95/GB, and for web scraping the cheaper choice is Cheerio whenever the data is in the page source. Cheerio downloads one HTML document per page instead of every script, image and font a browser loads. Use Puppeteer only when JavaScript builds the content or you must click, scroll or log in.

Is Cheerio faster than Puppeteer?

Yes, by a wide margin on the same page: Cheerio only parses HTML in memory, while Puppeteer starts a browser, downloads the page's resources and runs its JavaScript. Cheerio's own docs call it much faster than browser-based tools. The catch is that it cannot see content that scripts add after the page loads.

Why can't Cheerio extract JavaScript-rendered content?

Cheerio parses the HTML you give it and never runs scripts, so anything a single-page app adds in the browser is not in its input. Find the JSON the page loads or embeds and read that, or render the page in Puppeteer or Playwright and pass page.content() to Cheerio.

When should I switch from Cheerio to a browser-based crawler?

Switch when the fields you need are missing from the raw page source, when the site needs a login flow or clicks to reveal data, or when it returns a JavaScript challenge instead of content. Check first for an API request in the browser's Network tab, which usually costs far less traffic than a browser.

Can I use Cheerio and Puppeteer together?

Yes. Let Puppeteer handle the steps that need a browser, such as a login or a cookie banner, then take await page.content() and parse it with cheerio.load(). Your parsing code stays the same whether the HTML came from a browser or from fetch.

jsdom vs Cheerio: which is best?

Cheerio is lighter and faster when you only need to select and read elements. jsdom emulates a browser DOM in Node.js and can run some page scripts, which helps for simple dynamic pages, but it is slower and still not a real browser; for heavy single-page apps use Puppeteer or Playwright.

Is BeautifulSoup or Selenium better for scraping?

Beautiful Soup, when the data is in the HTML: it parses pages downloaded with Requests or httpx and uses a fraction of the resources. Selenium is for pages that need a real browser to run JavaScript or to click and scroll. The choice mirrors Cheerio vs Puppeteer in Node.js.

When should I switch from a headless browser to Cheerio?

As soon as you find the data in the raw page source or in a JSON response, because then the browser only adds time and traffic. Many scrapers start in a browser to explore a site and move each page type to fetch plus Cheerio once they know where the data lives.

Does Cheerio work with proxies?

Yes, through the HTTP client that downloads the HTML: Cheerio's own fromURL() fetches pages too, but the usual proxy route is fetch with undici's ProxyAgent, or Axios or got with a proxy agent, and then cheerio.load(). Point the agent at your gateway, for example gate.proxyfield.io:7000 with your ProxyField username and password.

Easy Trial: 1 GB for $2.95.

Try for the price of 1 GB, no subscription, traffic never expires.