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

Puppeteer is a JavaScript library that lets a Node.js program control a real Chrome or Firefox browser. Your code launches or connects to a browser, opens a tab represented by a Page object, navigates to a URL, performs actions such as clicking and typing, and then reads page data or saves a screenshot or PDF.

Puppeteer sends those high-level commands through a browser automation protocol: Chrome uses the Chrome DevTools Protocol (CDP) by default, while Firefox uses WebDriver BiDi by default. It runs headlessly unless you configure a visible browser window.

What Puppeteer is—and what it is not

Puppeteer runs inside Node.js; it is neither a browser nor a replacement for the Node.js runtime. It provides JavaScript objects and methods for driving a browser as if a user were operating it. The browser still performs the rendering, networking, JavaScript execution and security checks.

A normal Puppeteer program can automate a browser workflow from start to finish:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Launch a locally managed browser or connect to one that already exists.
  2. Create a browser context and a new page (a tab).
  3. Navigate to a URL and wait for the page state your task needs.
  4. Interact with elements, keyboard input and forms.
  5. Read text or DOM data, or capture a screenshot, PDF or performance trace.
  6. Close the page and browser when the job is complete.

The Page abstraction represents one browser tab. It exposes navigation, interaction, output and inspection methods while Puppeteer handles the protocol messages underneath.

How Puppeteer controls Chrome and Firefox

Puppeteer is a client for browser automation protocols. A method such as page.click() is translated into protocol commands, sent to the browser process, and resolved when the browser reports the result. This separation lets the same Node.js style of code work across supported browsers, but it does not make every feature identical everywhere.

Chrome: CDP by default

For Chrome, Puppeteer uses the Chrome DevTools Protocol (CDP) by default. CDP exposes domains for page navigation, input, network activity, runtime evaluation, screenshots, PDF output and tracing.

WebDriver BiDi

Puppeteer can select WebDriver BiDi when you need that protocol. BiDi is designed for interoperable browser automation, but its feature coverage is not identical to CDP. Check Puppeteer’s BiDi support documentation before choosing it for a feature that depends on a protocol-specific capability.

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

Firefox: BiDi by default

Firefox automation uses WebDriver BiDi by default. A script that relies on a CDP-only behavior may therefore need adjustment when moved to Firefox. Treat the browser and protocol pair—Chrome plus CDP, Chrome plus BiDi, or Firefox plus BiDi—as part of your compatibility decision.

Install the right package

Use the standard puppeteer package when you want Puppeteer to manage its compatible browser download. Use puppeteer-core when your team manages the browser itself or connects to a remote browser.

Package Browser management Best fit Important setup detail
puppeteer Normally downloads a compatible Chrome for Testing browser during installation. A self-contained local automation project. A package manager that blocks install scripts can prevent the download.
puppeteer-core Does not download Chrome. An externally managed, system, containerized or remote browser. Supply the browser connection yourself; a locally launched browser needs an explicit executable path or channel.

Standard installation

npm install puppeteer

The package’s installation step normally fetches the matching Chrome for Testing binary. In locked-down CI or package-manager environments, installation scripts may be disabled. If that happens, install the browser explicitly:

npx puppeteer browsers install

That command fixes a browser-download setup problem; it does not change how Puppeteer automates pages.

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

When puppeteer-core is appropriate

npm install puppeteer-core

With this package, you provide the browser. For a local executable, pass its path when launching; for a browser hosted elsewhere, use the connection mechanism exposed by Puppeteer and your browser service. This choice gives you control over browser images, patching and lifecycle, but you also own compatibility and availability.

A complete Node.js example

Save this as screenshot.mjs after installing puppeteer, then run node screenshot.mjs. It launches the managed Chrome, opens a page, waits for network activity to settle, and writes both a full-page image and an A4 PDF.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();

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

await browser.close();

What each call does

  • puppeteer.launch() starts a browser process. headless: true keeps it off-screen; set headless mode to a visible configuration when diagnosing a visual problem.
  • browser.newPage() creates a tab represented by a Page object.
  • page.goto() requests the URL. The waitUntil choice determines which navigation milestone Puppeteer waits for; “network idle” is useful for many static pages but is not proof that every application task has finished.
  • page.screenshot() captures the rendered page. fullPage: true extends the capture beyond the viewport.
  • page.pdf() produces a PDF with the selected paper format when the browser supports PDF output.
  • browser.close() releases the browser process. Always close it in production code, including error paths.

Adding interaction

Interaction methods follow the same model: wait for the target, click or type, then wait for the resulting UI state before collecting output.

await page.waitForSelector('form#signup');
await page.type('input[name="email"]', 'person@example.com');
await page.click('button[type="submit"]');
await page.waitForSelector('.success-message');
const message = await page.$eval('.success-message', el => el.textContent?.trim());
console.log(message);

Use selectors that are stable in your application, and make waits describe a meaningful state rather than relying on arbitrary delays.

Free tools Windows power users keep installed

One-click scans. No signup required.

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

Or skip the browser setup

If your goal is a clean screenshot or PDF rather than browser automation, ScreenshotNeo provides a single HTTP request. Its API accepts a URL and returns PNG, JPEG, WebP or PDF output; documentation is at screenshotneo.com/docs/.

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

Equivalent calls are available from Python and Node.js:

import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
open('shot.webp', 'wb').write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Before capture, ScreenshotNeo accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets. Each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and each response reports its result in the X-Page-Verdict and X-Billed headers.

It also includes an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. Its 63 options cover full-page capture with lazy images loaded; CSS-selector element capture; dark mode; 12 device presets plus arbitrary viewports; retina scale; PDF paper size, margins, landscape mode and page ranges; HTML/CSS-to-image rendering; custom CSS and JavaScript; pre-capture clicks; hidden selectors; waits for selectors, delays or network idle; blocking ads, trackers, requests or resource types; custom headers, cookies, user agents and Authorization; timezone and geolocation; transparent backgrounds; image resizing; user-selected cache TTLs; signed links for public image tags; asynchronous jobs with signed webhooks; bulk capture of up to 100 URLs per call; a usage API; an OpenAPI specification; and compatibility with parameter names used by other screenshot APIs.

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.
Plan Included screenshots Price
Free 1,000 per month No charge, no card
Starter 3,000 $5
Growth 15,000 $15
Pro 60,000 $39
Scale 250,000 $99
Business 1,000,000 $249

Every feature is available on every plan, and yearly billing gives two months free. Sign up for the free plan to get 1,000 screenshots a month without adding a card.

What Puppeteer is used for

  • UI and end-to-end testing: submit forms, exercise navigation and verify the resulting page state in a real browser.
  • Screenshot and PDF generation: produce visual snapshots, reports and printable documents after the page reaches the required state.
  • Data collection from rendered applications: read content that appears only after client-side JavaScript runs, subject to the website’s rules and access controls.
  • Keyboard and pointer workflows: reproduce clicks, typing and other user-like interactions.
  • Performance investigation: collect traces and inspect page behavior while a browser renders the application.

Automation capability does not grant permission to access a site. Check the site’s terms, robots guidance, authentication requirements and applicable law before running jobs.

Headless versus headful execution

Puppeteer runs headlessly by default, so no desktop window appears. This is efficient for CI servers and background jobs. A headful run displays the browser and is useful when you need to watch navigation, inspect a selector or compare what the automation sees with a human-visible session.

Headless and headful runs can differ in timing, viewport, fonts and environment. Set the viewport and other relevant browser settings explicitly, and debug a failure headfully before assuming the page itself is broken.

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

Choosing a browser and protocol

Start with the browser your users or test matrix require. Chrome with CDP is the default path with the broadest established Puppeteer examples. Choose BiDi when interoperability or a BiDi-specific environment is more important, and verify the exact feature you need. Firefox uses BiDi by default, so test selectors, downloads, PDF output and other browser-sensitive behavior on Firefox rather than assuming Chrome parity.

Protocol selection is not merely a transport preference: CDP and BiDi expose different capabilities and maturity levels. Keep browser/protocol combinations explicit in CI so a change does not silently move a job to a different implementation.

Remote browsers and operational design

A managed local browser is simplest for a small script. Larger systems often use puppeteer-core with a browser image or remote service controlled by the platform team. In that model, document the browser version, executable location or endpoint, protocol, viewport and installed fonts as part of the deployment contract.

Reuse a browser process for a batch of related pages instead of launching a new process for every URL, but close each page when its work ends. Isolate jobs that require different cookies, credentials or browser state. Set explicit navigation and selector waits, record failures with the URL and step that failed, and make cleanup run even when a page throws.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting common failures

“Browser was not found” or launch fails immediately

With puppeteer, the compatible browser download may have been skipped because installation scripts were blocked. Run npx puppeteer browsers install, then retry. With puppeteer-core, provide a valid executable path or connect to the remote browser you manage.

Navigation times out

Confirm the URL is reachable from the machine running Node.js, then choose a navigation wait condition that matches the application. Some pages keep long-lived network connections open, so waiting for network idle can be inappropriate. Increase the relevant timeout only after checking DNS, proxy, authentication and the page’s own loading behavior.

A selector never appears

Verify that the selector exists in the rendered DOM, not only in server-side source. Wait for the state that actually proves the component is ready, and check whether the element is inside a frame or appears only after an earlier click. Use a headful run and a screenshot to inspect the page at the failure point.

The screenshot is blank or incomplete

Capture after the meaningful content is present, set the viewport deliberately and account for lazy-loaded sections. A full-page capture can expose content below the fold that a viewport-only image misses, but it can also make very long pages expensive to render.

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

Chrome works but Firefox does not

Check whether the failing operation depends on CDP. Firefox uses WebDriver BiDi by default, and feature coverage differs between protocols. Reduce the example to navigation and one action, identify the unsupported operation, and consult the BiDi support documentation before changing application code.

The site presents a bot check or CAPTCHA

Puppeteer does not make an access challenge disappear. Treat the response as a site-access condition, follow the site’s rules, and use an authorized test environment or integration when one is available.

Performance, reliability and cost considerations

Puppeteer itself is a control library; your infrastructure pays for the Node.js process, browser memory, CPU, storage and network traffic. Launching browsers is heavier than issuing an ordinary HTTP request, so keep a controlled pool for repeated work and cap concurrent pages according to available resources.

For reliable jobs, pin the browser and Puppeteer versions you have tested, keep viewport and locale settings stable, and save diagnostic screenshots or logs only on failure. Design retries around the failed stage: a transient navigation error may be retried, while a missing selector usually requires a code or page change. Always close pages and browsers in cleanup handlers.

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

When Puppeteer is the right tool

Choose Puppeteer when you need to operate a browser: multi-step interaction, authenticated sessions, JavaScript-rendered state, keyboard input, testing or a custom sequence before capturing output. Choose a screenshot API when you only need a rendered asset and prefer an HTTP call, managed browser infrastructure and usage-based billing instead of packaging and operating browsers yourself. The browser/protocol and package choice should follow that primary requirement.

Frequently Asked Questions

Is a successful Puppeteer screenshot proof that the page loaded correctly?

No. A browser can render a blank state, an error page or an access challenge without throwing a navigation exception. Have the script verify an expected title, selector or content before treating the image as valid.

How should a batch job handle browser state?

Reuse one browser process where practical, but give jobs with different credentials or cookies isolated pages or contexts. Close each page after capture and close the browser when the batch ends so state and memory do not leak between jobs.

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.

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