Puppeteer is an Apache-2.0 JavaScript and TypeScript library that provides a high-level API for driving Chrome and Firefox over the DevTools Protocol or WebDriver BiDi, written for developers who automate browsers from Node.js.
What it is
Puppeteer is a browser automation library published on npm. It exposes a high-level JavaScript API that controls Chrome or Firefox through one of two protocols: the Chrome DevTools Protocol or WebDriver BiDi. It runs headless by default, meaning no visible browser UI is required, and the source is written in TypeScript under the Apache-2.0 licence. Documentation lives at pptr.dev, with separate pages for the API reference, FAQ, contributing guide and troubleshooting. The repository is a widely used Node module with topics covering automation, Chrome, Chromium, Firefox, headless Chrome, testing and the web.
The problem it solves is the cost of talking to a browser engine directly. Driving Chrome or Firefox over the DevTools Protocol or WebDriver BiDi means handling protocol sessions, targets, framing and browser lifecycle by hand before any page work can begin. Puppeteer wraps that layer in a high-level API, so navigation, viewport sizing, keyboard input, element location and page evaluation are expressed as ordinary async calls on a browser and a page object. It replaces hand-written protocol plumbing, not the browser itself, and it ships as a Node module rather than a hosted service.
Key capabilities
- One API controls both Chrome and Firefox, over the DevTools Protocol or WebDriver BiDi.
- Runs headless by default, so no visible UI is needed on a server or in a pipeline.
- Two install paths:
npm i puppeteer downloads a compatible Chrome during installation, while npm i puppeteer-core installs the library without downloading a browser.
npx puppeteer browsers install fetches required browsers manually when install scripts are blocked by the package manager.
- Locators that target accessibility and text rather than brittle selectors, such as
page.locator('::-p-aria(Search)') and page.locator('::-p-text(Customize and automate)'), with waitHandle() and evaluate() for extracting content.
- Page control primitives including
page.goto(url), page.setViewport({width, height}) and page.keyboard.press('/'), plus browser.close() for teardown.
- Browser automation for agents through
chrome-devtools-mcp, a Puppeteer-based MCP server, alongside support for the experimental WebMCP API.
Who uses it and how
- Test engineers use it to drive real Chrome and Firefox in automated browser test suites, which the
testing and automation topics reflect.
- Node.js developers use it as a
node-module dependency when browser behaviour has to be scripted from within an existing JavaScript application.
- Headless deployments use it for server-side and CI work, since the default mode requires no visible browser UI.
- Cross-browser teams use it to cover Chromium and Firefox from a single library instead of maintaining separate drivers.
- Teams on npm, pnpm, Yarn, Bun or Deno must account for blocked dependency install scripts, since these block the browser download and cause runtime errors until the browser is installed manually.
Getting started
Install with npm i puppeteer to download a compatible Chrome during installation, or npm i puppeteer-core to add the library without a browser, then run npx puppeteer browsers install if the install script was blocked.
How it compares
The facts provided name no comparable tools and no paid products that Puppeteer replaces, so no contrast can be drawn on licence, hosting, data ownership or cost model. It stands alone in this registry on that basis.
When to use it — and when not to
A self-hoster must supply a Node.js runtime and a compatible browser, and must handle the case where modern package managers block the install script that fetches that browser. Anyone who wants a hosted browser-automation service, a graphical recorder, or support for a language other than JavaScript and TypeScript should not pick it. The Apache-2.0 licence is clear and activity is current, but 259 open issues indicate a broad surface of ongoing browser-compatibility work to track.
project readme (upstream, from github) — read inline
Puppeteer


Puppeteer is a JavaScript library which provides a high-level API to control
Chrome or Firefox over the
DevTools Protocol or WebDriver BiDi.
Puppeteer runs in the headless (no visible UI) by default
Installation
npm i puppeteer # Downloads compatible Chrome during installation.
npm i puppeteer-core # Alternatively, install as a library, without downloading Chrome.
:::note
Modern package managers (including npm (see the RFC), pnpm, Yarn, Bun, and Deno) block dependency install scripts by default. If the install script is blocked, Puppeteer will not download the browser during installation, leading to runtime errors.
You can manually download the required browsers after installation by running:
npx puppeteer browsers install
Alternatively, you can configure your package manager to allow the install script to run (for example, with npm, by adding "puppeteer" to "allowScripts" in your package.json).
:::
MCP
Install chrome-devtools-mcp,
a Puppeteer-based MCP server for browser automation and debugging.
Puppeteer also supports the experimental WebMCP API.
Example
import puppeteer from 'puppeteer';
// Or import puppeteer from 'puppeteer-core';
// Launch the browser and open a new blank page.
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Navigate the page to a URL.
await page.goto('https://developer.chrome.com/');
// Set the screen size.
await page.setViewport({width: 1080, height: 1024});
// Open the search menu using the keyboard.
await page.keyboard.press('/');
// Type into search box using accessible input name.
await page.locator('::-p-aria(Search)').fill('automate beyond recorder');
// Wait and click on first result.
await page.locator('.devsite-result-item-link').click();
// Locate the full title with a unique string.
const textSelector = await page
.locator('::-p-text(Customize and automate)')
.waitHandle();
const fullTitle = await textSelector?.evaluate(el => el.textContent);
// Print the full title.
console.log('The title of this blog post is "%s".', fullTitle);
await browser.close();