What Is Puppeteer?

By Jeffrey Needles

October 28, 2026
Engineering
Puppeteer
Browser Automation

What Is Puppeteer?

Puppeteer is an open-source JavaScript library for controlling Chrome and Firefox through code. You can use it to open pages, fill out forms, run JavaScript, extract information and save screenshots. With Chrome, it can also print pages to PDF.

For example, a script can open an order dashboard, select the orders ready to ship and collect their details. It can use the same controls you'd use by hand, including on pages that load their content with JavaScript.

Puppeteer is maintained by Google's Chrome Browser Automation team. Most projects use it from Node.js on a server, a development machine or a continuous integration (CI) worker. You don't need to keep a browser window open.

We'll try that workflow below, then look at how an AI assistant can use Puppeteer through MCP. If you're already comparing libraries, see how to choose between Playwright and Puppeteer.

What Can You Do with Puppeteer?

Puppeteer is useful when a job needs a browser's rendering or interaction, rather than just the HTML returned by a server.

Common examples include:

  • Screenshots: Capture a web page, a dashboard or one specific element.
  • PDFs: Print invoices, account statements and reports using Chrome's print engine.
  • Browser automation: Fill forms, click through a workflow and download files.
  • Web scraping: Extract information after a page's JavaScript has loaded it.
  • Testing and debugging: Check a user flow, inspect network requests or investigate a Chrome-specific issue.

If you're generating a social card, for instance, Puppeteer can render the same HTML and CSS your frontend team already uses. If you're collecting a server-rendered page title, a regular HTTP request and an HTML parser may be enough. Running a browser for that would add work you don't need.

How Does Puppeteer Work?

Your script sends commands to a separate browser process. The browser loads the page and runs its JavaScript. Puppeteer gives your script access to the result.

The objects you'll see most often are:

Object What it represents
Browser The browser process your script launches or connects to
BrowserContext An isolated browsing session with its own cookies and storage
Page A tab where you navigate, interact with content or take a screenshot

Chrome uses the Chrome DevTools Protocol by default. Firefox uses WebDriver BiDi, a cross-browser automation protocol. You normally work with Puppeteer's methods rather than writing protocol messages yourself. The browser support FAQ explains the distinction.

What Does Headless Mean?

A headless browser runs without a visible window. It still loads images, applies CSS and executes JavaScript.

Puppeteer launches headless by default. Set headless: false in the launch options when you want to watch a script work. That's handy when it clicks the wrong button or gets stuck behind a dialog.

Chrome or Firefox still runs on the machine and uses memory and CPU, even without a visible window.

Example: Filter a Page and Extract Its Data

We'll use a small order dashboard. The script clicks Ready orders, waits for the filter to apply and returns the visible rows as JSON. The same pattern works for a report or admin page you have permission to automate.

Download the demo page and save it as orders.html. It runs locally without credentials or external resources.

In a new Node.js project, install Puppeteer:

npm install puppeteer

The standard package normally downloads a compatible Chrome during installation. If your package manager blocks the download script, run npx puppeteer browsers install. See the installation guide for supported setup options.

Save this as ready-orders.mjs beside the HTML file. The .mjs extension lets Node.js use imports and top-level await without changing your project's configuration.

import { readFile } from "node:fs/promises";
import puppeteer from "puppeteer";

const html = await readFile(new URL("./orders.html", import.meta.url), "utf8");
const browser = await puppeteer.launch();

try {
  const page = await browser.newPage();
  await page.setContent(html);

  await page.locator("#ready-orders").click();
  await page.waitForSelector('[data-filter="ready"]');

  const orders = await page.$$eval("tbody tr:not([hidden])", rows =>
    rows.map(row => ({
      order: row.cells[0].textContent.trim(),
      items: Number(row.cells[1].textContent),
      status: row.cells[2].textContent.trim(),
    })),
  );

  console.log(JSON.stringify(orders, null, 2));
} finally {
  await browser.close();
}

Run it with:

node ready-orders.mjs

The script prints two orders, RS-1042 and RS-1044. The packing order isn't included. $$eval() runs the extraction function inside the page and returns the data to Node.js.

setContent() loads the downloaded HTML. Use page.goto() to open your application's URL instead. The click and extraction can stay the same if the page has the same controls and table structure. There's also a downloadable copy of the script.

The finally block closes the browser even if a step fails. In a long-running service, you would usually reuse a browser and create a fresh page or context for each job.

Using Puppeteer with MCP and AI Assistants

Model Context Protocol (MCP) lets an AI application call tools supplied by another program. For browser automation, those tools might open a page, read its contents, fill an input or inspect a network request.

Chrome DevTools MCP uses Puppeteer for its Chrome automation. An assistant can inspect the current page, choose a tool, check the result and decide what to do next. You can ask it to collect the ready orders from the demo instead of writing the selectors and extraction code yourself.

The MCP server exposes its own tools, not every method in Puppeteer's API. The assistant also needs to be connected to that server. Installing puppeteer in a project doesn't automatically give your assistant browser access.

This works well for exploring an unfamiliar page or investigating a failing workflow. For a job that needs to run every morning, keep the finished Puppeteer script so the steps and expected output are explicit.

Our Puppeteer MCP tutorial walks through the server setup and the same order dashboard. The MCP architecture overview explains the protocol separately.

What Does Puppeteer Wait For?

A browser can finish loading a page before the content you need has appeared. A report might still be waiting for account data. A chart might exist in the document but have nothing drawn in it yet.

Puppeteer's locators automatically wait for conditions such as an element being visible and enabled before interacting with it. Older examples often use explicit selector waits instead. Both styles still appear in real projects.

Neither can infer that your application's report is complete. You have to choose a condition that means something for the job, such as the populated report or an application-ready marker.

In our example, the page marks the completed filter with data-filter="ready". A real dashboard might instead expose a populated results table or a loading indicator that disappears. For capture jobs that also need fonts, images and charts, see how to wait for a page before taking a screenshot.

Puppeteer, Playwright and Selenium

All three can automate browsers, but they come with different tooling and language support.

Playwright supports Chromium, Firefox and WebKit, with official APIs for JavaScript/TypeScript, Python, Java and .NET. Its Node.js test framework also includes assertions, reports and tracing. Puppeteer is a Node.js library that you can use with your own test runner.

Selenium has a broader language ecosystem and tools such as Selenium Grid for running browser sessions across machines. Puppeteer's FAQ compares their scope. You don't have to replace a working Selenium setup to generate a few screenshots.

For a Chrome-based Node.js script, Puppeteer is a reasonable choice. For a new cross-browser test suite, I'd usually start with Playwright. The full comparison covers the decisions that can change that recommendation.

Using Puppeteer in Production

The script above is small. Running the same job for many customers brings a few additional responsibilities:

  • Keep the browser installed and compatible with the library.
  • Limit how many pages run at once so the worker doesn't run out of memory.
  • Set job timeouts and clean up pages after failures.
  • Keep fonts and viewport settings consistent across workers.
  • Isolate untrusted HTML and URLs from credentials and private network services.

If you're here for screenshots or PDFs, our JavaScript HTML-to-image tutorial and print-layout guide cover those workflows. The HTML/CSS to Image API is an option when you want a rendered image without operating the browser workers. It doesn't provide the general page interaction used in this example.

Frequently Asked Questions

Is Puppeteer Free?

Yes. Puppeteer is open source under the Apache 2.0 license. There's no per-screenshot library fee. You still pay for the infrastructure where the browser runs, or for a hosted service if you use one.

Does Puppeteer Only Work with Chrome?

No. Puppeteer supports Chrome and Firefox. Firefox support has been production-ready since Puppeteer 23. It doesn't support WebKit, and some methods differ between Chrome's default protocol and Firefox's. Check the WebDriver BiDi support guide for feature-specific limits.

What Is the Difference Between Puppeteer and puppeteer-core?

puppeteer includes browser download and configuration defaults. puppeteer-core doesn't download a browser. Use it when you manage the browser yourself or connect to a remote browser, and supply the connection or executable configuration.

Can I Use Puppeteer from C# or Python?

The official Puppeteer library is for Node.js. PuppeteerSharp is a separate .NET project with a similar API. For Python, Playwright has an official API. Our C# and Python rendering tutorials show those approaches.

Can I Generate an Image Without Installing a Browser?

Yes, if you use a remote browser or a rendering API. Connecting Puppeteer to a remote browser moves the browser process elsewhere. A rendering API handles the render request for you. In both cases, a browser can still do the rendering, but it isn't installed on your application server.

Loading newsletter signup…

Please wait a moment.

Have a question?

We'd love to hear about what you're building.

Contact us

Get Started

You'll be up and running in 5 minutes.

Grab an API Key

Keep reading

More posts

View all posts
Get Started Now

NO CREDIT CARD NEEDED. 50 FREE IMAGES EVERY MONTH.