playwright vs puppeteer vs puppeteer-core
Browser Automation and End-to-End Testing Strategies
playwrightpuppeteerpuppeteer-coreSimilar Packages:

Browser Automation and End-to-End Testing Strategies

playwright, puppeteer, and puppeteer-core are Node.js libraries used for controlling headless browsers. They enable automated testing, scraping, and generating screenshots of web applications. puppeteer is the original library focused on Chrome/Chromium, while puppeteer-core is a lightweight variant that requires an existing browser installation. playwright is a newer cross-browser solution supporting Chromium, Firefox, and WebKit with built-in auto-waiting features.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
playwright088,4614.91 MB2882 hours agoApache-2.0
puppeteer094,29863.1 kB26310 hours agoApache-2.0
puppeteer-core094,2988.89 MB26310 hours agoApache-2.0

Playwright vs Puppeteer vs Puppeteer-Core: Architecture and Use Cases

When automating browsers in Node.js, playwright, puppeteer, and puppeteer-core are the top contenders. While they share similar goals — controlling browsers to test or scrape web content — they differ significantly in browser support, installation behavior, and stability features. Let's break down how they handle real-world engineering tasks.

🌐 Browser Support: Single vs Multi-Browser

playwright supports three major browser engines out of the box: Chromium, Firefox, and WebKit (Safari).

  • You install all browsers with one command.
  • Switching browsers requires changing only the launch configuration.
// playwright: Launch Firefox
const { firefox } = require('playwright');

(async () => {
  const browser = await firefox.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await browser.close();
})();

puppeteer focuses primarily on Chromium and Chrome.

  • Firefox support exists but is experimental and not the default.
  • Best for environments where Chrome is the standard.
// puppeteer: Launch Chrome
const puppeteer = require('puppeteer');

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

puppeteer-core has the same browser support as puppeteer (mostly Chromium).

  • It does not download any browser automatically.
  • You must provide the path to an existing browser executable.
// puppeteer-core: Launch with existing binary
const puppeteer = require('puppeteer-core');

(async () => {
  const browser = await puppeteer.launch({
    executablePath: '/usr/bin/google-chrome'
  });
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await browser.close();
})();

📦 Installation and Setup: Bundled vs External

playwright downloads browser binaries during installation or via a CLI command.

  • Ensures the library version matches the browser version.
  • Reduces "it works on my machine" issues.
# playwright: Install browsers
npx playwright install
// playwright: Import specific browser
const { chromium } = require('playwright');

puppeteer downloads a compatible Chromium version by default when you install the package.

  • Increases node_modules size significantly.
  • Guarantees compatibility without extra setup.
# puppeteer: Install (downloads Chromium)
npm install puppeteer
// puppeteer: Import main package
const puppeteer = require('puppeteer');

puppeteer-core does not download any browser.

  • Keeps node_modules small.
  • Requires you to manage browser paths manually in code or environment variables.
# puppeteer-core: Install (no browser download)
npm install puppeteer-core
// puppeteer-core: Must specify executablePath
const puppeteer = require('puppeteer-core');
// const browser = await puppeteer.launch({ executablePath: '...' });

⏳ Stability: Auto-Waiting vs Manual Waits

playwright performs auto-waiting before actions like clicks or typing.

  • Checks if the element is visible, stable, and actionable.
  • Reduces flaky tests caused by timing issues.
// playwright: Auto-waits before click
await page.click('#submit-button'); 
// Waits for element to be ready automatically

puppeteer requires manual waiting for elements to be ready.

  • You must explicitly wait for selectors or timeouts.
  • More control but higher risk of flakiness if missed.
// puppeteer: Manual wait required
await page.waitForSelector('#submit-button');
await page.click('#submit-button');

puppeteer-core behaves exactly like puppeteer regarding waits.

  • No built-in auto-waiting logic.
  • Relies on the same API for visibility checks.
// puppeteer-core: Manual wait required
await page.waitForSelector('#submit-button');
await page.click('#submit-button');

🔌 Connection Architecture: WebSocket vs CDP

playwright connects to browsers via WebSocket using its own protocol.

  • Works across different browser engines uniformly.
  • Enables features like context isolation and network interception easily.
// playwright: Connect to remote browser
const browser = await playwright.chromium.connect({
  wsEndpoint: 'ws://localhost:3000/browser'
});

puppeteer uses the Chrome DevTools Protocol (CDP) directly.

  • Tightly coupled with Chrome/Chromium internals.
  • Provides deep access to Chrome-specific features.
// puppeteer: Connect via CDP
const browser = await puppeteer.connect({
  browserURL: 'http://localhost:9222'
});

puppeteer-core also uses CDP, identical to puppeteer.

  • Difference is only in how the browser binary is located.
  • Connection logic remains the same.
// puppeteer-core: Connect via CDP
const browser = await puppeteer.connect({
  browserURL: 'http://localhost:9222'
});

📊 Summary: Key Differences

Featureplaywrightpuppeteerpuppeteer-core
Browsers🌐 Chromium, Firefox, WebKit🟢 Chromium/Chrome (mostly)🟢 Chromium/Chrome (mostly)
Install Size📦 Large (downloads browsers)📦 Large (downloads Chromium)📄 Small (no browser)
Auto-Waiting✅ Built-in❌ Manual❌ Manual
Binary Mgmt🔧 Managed by library🔧 Managed by library🛠️ Manual (executablePath)
Protocol🔌 WebSocket (Unified)🔌 CDP (Chrome specific)🔌 CDP (Chrome specific)

🤝 Similarities: Shared Ground

Despite their differences, all three libraries share core concepts and APIs.

1. 📄 Page and Context Model

  • All use a Browser -> Context -> Page hierarchy.
  • Allows isolating sessions within a single browser instance.
// All three support contexts
const context = await browser.newContext();
const page = await context.newPage();

2. 📸 Screenshot and PDF

  • All provide built-in methods for capturing page state.
  • Useful for visual regression or reporting.
// All three support screenshots
await page.screenshot({ path: 'image.png' });

3. 🕵️ Selector Engine

  • All support CSS selectors and XPath.
  • Playwright adds text-based and role-based selectors.
// CSS Selectors work in all
await page.$('.class-name');

💡 The Big Picture

playwright is the modern choice for end-to-end testing — especially when you need to verify your app works on Safari or Firefox. Its auto-waiting features save hours of debugging flaky tests.

puppeteer remains a solid standard for Chrome-specific automation. If you are scraping sites or generating PDFs where Chrome fidelity is key, it is a reliable workhorse.

puppeteer-core is a specialized tool for infrastructure engineers. Use it when you control the runtime environment and want to skip browser downloads to speed up CI/CD pipelines.

Final Thought: For new test automation projects, playwright offers the most robust feature set. For lightweight Chrome scripting or legacy maintenance, puppeteer (or puppeteer-core in containers) remains highly effective.

How to Choose: playwright vs puppeteer vs puppeteer-core

  • playwright:

    Choose playwright if you need to test across multiple browsers like Firefox, WebKit, and Chromium without managing separate configurations. It is ideal for teams building comprehensive end-to-end test suites that require high reliability and modern debugging tools like trace viewers.

  • puppeteer:

    Choose puppeteer if your project targets only Chrome or Chromium and you value a mature ecosystem with extensive community plugins. It works well for web scraping, PDF generation, or simple automation tasks where cross-browser support is not a priority.

  • puppeteer-core:

    Choose puppeteer-core if you manage browser binaries separately, such as in a Docker container with a pre-installed Chrome version. This avoids downloading Chromium during deployment, reducing install time and image size in controlled environments.

README for playwright

🎭 Playwright

npm version Chromium version Firefox version WebKit version Join Discord

Documentation | API reference

Playwright is a framework for web automation and testing. It drives Chromium, Firefox, and WebKit with a single API — in your tests, in your scripts, and as a tool for AI agents.

Get Started

Choose the path that fits your workflow:

Best forInstall
Playwright TestEnd-to-end testingnpm init playwright@latest
Playwright CLICoding agents (Claude Code, Copilot)npm i -g @playwright/cli@latest
Playwright MCPAI agents and LLM-driven automationnpx @playwright/mcp@latest
Playwright LibraryBrowser automation scriptsnpm i playwright
VS Code ExtensionTest authoring and debugging in VS CodeInstall from Marketplace

Playwright Test

Playwright Test is a full-featured test runner built for end-to-end testing. It runs tests across Chromium, Firefox, and WebKit with full browser isolation, auto-waiting, and web-first assertions.

Install

npm init playwright@latest

Or add manually:

npm i -D @playwright/test
npx playwright install

Write a test

import { test, expect } from '@playwright/test';

test('has title', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  await expect(page).toHaveTitle(/Playwright/);
});

test('get started link', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  await page.getByRole('link', { name: 'Get started' }).click();
  await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
});

Run tests

npx playwright test

Tests run in parallel across all configured browsers, in headless mode by default. Each test gets a fresh browser context — full isolation with near-zero overhead.

Key capabilities

Auto-wait and web-first assertions. No artificial timeouts. Playwright waits for elements to be actionable, and assertions automatically retry until conditions are met.

Locators. Find elements with resilient locators that mirror how users see the page:

page.getByRole('button', { name: 'Submit' })
page.getByLabel('Email')
page.getByPlaceholder('Search...')
page.getByTestId('login-form')

Test isolation. Each test runs in its own browser context — equivalent to a fresh browser profile. Save authentication state once and reuse it across tests:

// Save state after login
await page.context().storageState({ path: 'auth.json' });

// Reuse in other tests
test.use({ storageState: 'auth.json' });

Tracing. Capture execution traces, screenshots, and videos on failure. Inspect every action, DOM snapshot, network request, and console message in the Trace Viewer:

// playwright.config.ts
export default defineConfig({
  use: {
    trace: 'on-first-retry',
  },
});
npx playwright show-trace trace.zip

Parallelism. Tests run in parallel by default across all configured browsers.

Full testing documentation


Playwright CLI

Playwright CLI is a command-line interface for browser automation designed for coding agents. It's more token-efficient than MCP — commands avoid loading large tool schemas and accessibility trees into the model context.

Install

npm install -g @playwright/cli@latest

Optionally install skills for richer agent integration:

playwright-cli install --skills

Usage

Point your coding agent at a task:

Test the "add todo" flow on https://demo.playwright.dev/todomvc using playwright-cli.
Take screenshots for all successful and failing scenarios.

Or run commands directly:

playwright-cli open https://demo.playwright.dev/todomvc/ --headed
playwright-cli type "Buy groceries"
playwright-cli press Enter
playwright-cli screenshot

Session monitoring

Use playwright-cli show to open a visual dashboard with live screencast previews of all running browser sessions. Click any session to zoom in and take remote control.

playwright-cli show

Full CLI documentation | GitHub


Playwright MCP

The Playwright MCP server gives AI agents full browser control through the Model Context Protocol. Agents interact with pages using structured accessibility snapshots — no vision models or screenshots required.

Setup

Add to your MCP client (VS Code, Cursor, Claude Desktop, Windsurf, etc.):

{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest"]
    }
  }
}

One-click install for VS Code:

Install in VS Code

For Claude Code:

claude mcp add playwright npx @playwright/mcp@latest

How it works

Ask your AI assistant to interact with any web page:

Navigate to https://demo.playwright.dev/todomvc and add a few todo items.

The agent sees the page as a structured accessibility tree:

- heading "todos" [level=1]
- textbox "What needs to be done?" [ref=e5]
- listitem:
  - checkbox "Toggle Todo" [ref=e10]
  - text: "Buy groceries"

It uses element refs like e5 and e10 to click, type, and interact — deterministically and without visual ambiguity. Tools cover navigation, form filling, screenshots, network mocking, storage management, and more.

Full MCP documentation | GitHub


Playwright Library

Use playwright as a library for browser automation scripts — web scraping, PDF generation, screenshot capture, and any workflow that needs programmatic browser control without a test runner.

Install

npm i playwright

Examples

Take a screenshot:

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev/');
await page.screenshot({ path: 'screenshot.png' });
await browser.close();

Generate a PDF:

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev/');
await page.pdf({ path: 'page.pdf', format: 'A4' });
await browser.close();

Emulate a mobile device:

import { chromium, devices } from 'playwright';

const browser = await chromium.launch();
const context = await browser.newContext(devices['iPhone 15']);
const page = await context.newPage();
await page.goto('https://playwright.dev/');
await page.screenshot({ path: 'mobile.png' });
await browser.close();

Intercept network requests:

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
await page.goto('https://playwright.dev/');
await browser.close();

Library documentation | API reference


VS Code Extension

The Playwright VS Code extension brings test running, debugging, and code generation directly into your editor.

Run and debug tests from the editor with a single click. Set breakpoints, inspect variables, and step through test execution with a live browser view.

Generate tests with CodeGen. Click "Record new" to open a browser — navigate and interact with your app while Playwright writes the test code for you.

Pick locators. Hover over any element in the browser to see the best available locator, then click to copy it to your clipboard.

Trace Viewer integration. Enable "Show Trace Viewer" in the sidebar to get a full execution trace after each test run — DOM snapshots, network requests, console logs, and screenshots at every step.

Install the extension | VS Code guide


Cross-Browser Support

LinuxmacOSWindows
Chromium1 148.0.7778.96:white_check_mark::white_check_mark::white_check_mark:
WebKit 26.4:white_check_mark::white_check_mark::white_check_mark:
Firefox 150.0.2:white_check_mark::white_check_mark::white_check_mark:

Headless and headed execution on all platforms. 1 Uses Chrome for Testing by default.

Other Languages

Playwright is also available for Python, .NET, and Java.

Resources