mrkeyoor.com_
Wed 05 Aug 05:07 UTC
npmTestingupdated 05 Aug 2026

puppeteer

Puppeteer is a Node.js library that drives Chrome or Firefox through the DevTools Protocol or WebDriver BiDi, headless by default. You script a real browser: open pages, click, type, wait for selectors, run JavaScript inside the page, capture screenshots and PDFs, and intercept network requests. Installing the puppeteer package also downloads a matching Chrome build so the API and browser version stay in sync (puppeteer-core skips the download). It is maintained by the Chrome DevTools team, which is why new Chrome capabilities land here first.

Verdict

Still the cleanest way to script Chrome specifically, and the Chrome team keeps it current with every browser release. For cross-browser test suites, start with Playwright instead and keep Puppeteer for Chrome-centric automation.

API stability4/5The core launch/page/locator API has been steady for years, but majors land frequently in step with Chrome releases (currently v25), and older APIs like page.cookies get deprecated along the way.
Docs4/5pptr.dev has full API reference, guides, an FAQ, and an unusually honest troubleshooting page; test-runner integration and larger architecture patterns are left to you.
Maintenance5/5Chrome DevTools team project with daily pushes and releases tracking every Chrome version; 95k stars and an active issue tracker.
Ecosystem4/5Large ecosystem of scraping and stealth plugins, and Google builds on it (chrome-devtools-mcp is Puppeteer-based); the testing-framework ecosystem, however, has consolidated around Playwright.

Use it if

  • You need programmatic Chrome for scraping, screenshots, or PDF generation from HTML
  • You are automating something Chrome-specific: extensions, DevTools Protocol features, performance traces
  • You want the Chrome-team-maintained way to drive the browser most of your users actually run
  • You run crawling infrastructure where a pinned, auto-downloaded Chrome per package version keeps CI reproducible
Skip it if

Setup reality

npm i puppeteer downloads a compatible Chrome during install, except that npm, pnpm, Yarn, Bun, and Deno now block install scripts by default, so the browser silently never arrives and you get a could-not-find-Chrome error at runtime. The fix is npx puppeteer browsers install or allow-listing the script in package.json. Node 22.12+ is required as of v24. In Docker and CI you additionally need a stack of system libraries and usually --no-sandbox and --disable-dev-shm-usage flags; the troubleshooting page is required reading before containerizing.

Patterns

Launch a browser and open a pagelaunch-and-navigate

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
// ...
await browser.close();

launch() is headless by default; pass { headless: false } to watch it work.

Take a screenshotscreenshot

await page.setViewport({ width: 1280, height: 800 });
await page.screenshot({ path: 'page.png', fullPage: true });

The default viewport is 800x600; set it explicitly or layouts render narrower than you expect.

Render a page to PDFgenerate-pdf

await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.pdf({ path: 'page.pdf', format: 'A4', printBackground: true });

printBackground defaults to false, which strips CSS backgrounds and surprises everyone the first time.

Fill a form with locatorsclick-and-type

await page.locator('input[name="q"]').fill('puppeteer');
await page.locator('button[type="submit"]').click();

Locators auto-wait for the element to be visible and stable; prefer them over the older page.click and page.type.

Wait for content by text or ARIA rolewait-for-element

const handle = await page
  .locator('::-p-text(Search results)')
  .waitHandle();
const text = await handle.evaluate((el) => el.textContent);

::-p-text and ::-p-aria are Puppeteer selector extensions, handy when CSS selectors are brittle.

Run JavaScript inside the pageevaluate-in-page

const title = await page.evaluate(() => document.title);
const sum = await page.evaluate((a, b) => a + b, 2, 3);

The callback executes in the browser and cannot close over Node variables; pass them as arguments.

Extract data from many elementsscrape-list

const links = await page.$$eval('a.result', (anchors) =>
  anchors.map((a) => ({ href: a.href, text: a.textContent })),
);

The return value must be JSON-serializable; DOM nodes cannot cross the browser-to-Node boundary.

Block or modify network requestsintercept-requests

await page.setRequestInterception(true);
page.on('request', (req) => {
  if (['image', 'font'].includes(req.resourceType())) req.abort();
  else req.continue();
});

Once interception is on, every request must be continued or aborted exactly once or the page hangs.

Save and restore a login sessionreuse-cookies

import fs from 'node:fs';

// after logging in once
const cookies = await browser.cookies();
fs.writeFileSync('cookies.json', JSON.stringify(cookies));

// in a later session
await browser.setCookie(...JSON.parse(fs.readFileSync('cookies.json', 'utf8')));

page.cookies() is deprecated; the cookie APIs now live on the Browser object.

Launch inside Docker or CIdocker-ci-flags

const browser = await puppeteer.launch({
  args: ['--no-sandbox', '--disable-dev-shm-usage'],
});

Most containers need both flags; the tiny default /dev/shm otherwise crashes Chrome on heavier pages.

Drive an existing Chrome with puppeteer-coreuse-system-chrome

import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  executablePath: '/usr/bin/google-chrome',
});

puppeteer-core skips the browser download entirely, but version compatibility becomes your problem.

Install Chrome when the postinstall was blockedinstall-browser

npx puppeteer browsers install chrome

Modern package managers block install scripts by default, so this step is now routine in CI.

Alternatives

PackageRegistryPick it when
playwrightnpmYou need cross-browser coverage or an integrated test runner with fixtures and traces
selenium-webdrivernpmYou must target the WebDriver standard across many browsers or an existing Selenium grid
cypressnpmYou want an all-in-one interactive testing experience for your own web app rather than a scripting driver