puppeteer/puppeteer
github.com/puppeteer/puppeteer ↗ · 1482 files · 5.1 MB
Puppeteer Puppeteer is a JavaScript library which provides a high-level API to control Chrome or Firefox over the DevTools Protocol or WebDriver BiDi.
Overview
Puppeteer is a TypeScript-based JavaScript library for developers automating Chrome and Firefox through CDP or WebDriver BiDi. It combines browser provisioning, process management, navigation, DOM interaction, network control, and document capture behind Browser, BrowserContext, Page, and ElementHandle APIs. This brief investigates commit 2e45a3af43231cd658285e4da5e7f53e40f24edf through public source, configuration, documentation, and test reads; it establishes source behavior rather than runtime results.
System map
The runtime consists of a consumer library, a browser-management package, and external browser processes. Shared API abstractions sit above CDP and BiDi implementations, while Node-specific launch and filesystem facilities have separate entrypoints. npm workspaces and Wireit coordinate compilation, generated declarations, documentation, and tests. Distribution includes npm packages, a container image, and a separately built documentation website.
- The root build graph coordinates browsers, ng-schematics, puppeteer-core, puppeteer, testserver, integration tests, installation tests, and tooling through npm workspaces and Wireit.
- The puppeteer entrypoint re-exports puppeteer-core and constructs PuppeteerNode with isPuppeteerCore:false and asynchronous getConfiguration.
- The core Node entrypoint installs Node environment dependencies and exports launch/connect; the browser entrypoint constructs the shared Puppeteer class and exports connect.
- BrowserLauncher selects native Firefox BiDi, Chrome CDP over pipe or WebSocket, or Chrome BiDi over CDP; Firefox BiDi rejects pipe connections.
- Browser binaries persist under cacheRoot/browser/platform-buildId; per-browser .metadata stores aliases and optional custom executable paths.
- Published puppeteer and puppeteer-core packages require Node >=22.12.0 and expose compiled JavaScript plus generated declarations; core also declares a browser-specific bundle entry.
- Tag-triggered publishing builds and publishes npm workspaces with provenance; Puppeteer tags also publish a GHCR Docker image whose runtime uses a non-root pptruser.
- The documentation website uses React and Docusaurus, materializes docs before building, and conditionally deploys to GitHub Pages followed by Algolia crawler checks and reindexing.
Feature catalog
The main user surface is the JavaScript automation API, complemented by browser-management commands and Angular tooling. The inspected APIs cover browser sessions, page interaction, network behavior, captures, and browser-specific controls. CDP and BiDi have differing capabilities, so feature availability depends on browser, protocol, and sometimes browser version. This catalog groups the investigated surfaces and does not claim exhaustive enumeration of every exported method.
- launch supports Chrome and Firefox launcher selection; connect attaches through exactly one of browserWSEndpoint, browserURL, a custom transport, or a Chrome channel.
- CDP BrowserContext APIs create pages, isolate contexts, configure proxy/download behavior, and get/set cookies with partition-key conversion.
- Page.goto supports referrer settings, lifecycle wait conditions, and navigation timeouts; locator clicks automatically check viewport placement, stable geometry, and enabled state.
- Selectors dispatch to CSS, ARIA, text, XPath, shadow-piercing, composite P selectors, or registered custom handlers, with polling chosen from selector characteristics.
- Screenshots support PNG/JPEG/WebP, clipping, full-page capture, base64 or byte output, and optional file output; CDP PDF generation supports streamed output, fonts, margins, tagged PDFs, and outlines.
- Page exposes request interception, HTTP authentication, host-function bindings, coverage, tracing, accessibility, and an experimental WebMCP accessor requiring Chrome 151+ and a feature flag.
- CDP Browser APIs load/uninstall unpacked extensions, install/uninstall PWAs, and add/remove screens; PWA installation is rejected when network restrictions are configured.
- Browser-management CLI commands include install, launch, clear, list, and experimental bisect; Angular schematics provide ng-add, e2e-file generation, and configuration ejection with Node/Jest/Jasmine/Mocha runner choices.
Data flow
Consumer options and configuration feed executable selection, process launch, and protocol connection setup. Protocol messages carry command identifiers and session identifiers across the transport boundary, with callbacks and session maps owning pending state. Downloads flow through providers into filesystem caches and metadata. Capture results flow back as strings, byte arrays, streams, or caller-selected files.
- getConfiguration searches Puppeteer config locations, overlays PUPPETEER_* variables, defaults the cache to ~/.cache/puppeteer, and defaults Firefox downloads off unless overridden.
- downloadBrowser transforms a configured version or revision into a concrete buildId through resolveBuildId, then passes browser/platform/cache/baseUrl and any alias to install.
- installWithProviders filters providers through supports, asks getDownloadUrl, and attempts installUrl in order; custom baseUrl suppresses the standard-source fallback unless forceFallbackForTesting is enabled.
- installUrl computes archive and installation paths, persists custom executable layouts, unpacks the archive, writes build aliases, runs platform setup, and removes the archive in finally.
- Chrome launch options become browser flags and a profile directory; BrowserLauncher forwards the resolved executable, args, environment, signal options, and process-exit cleanup hook to the browser process launcher.
- Connection._rawSend registers a timed callback and serializes method/params/id/sessionId; onMessage routes session traffic, resolves or rejects command callbacks, and emits unsolicited events.
- NetworkManager owns HTTP credentials and sends them in Fetch.continueWithAuth; repeated challenges for an already attempted request are canceled.
- Page.screenshot receives base64 capture data, returns it directly for base64 encoding, or decodes it to Uint8Array and optionally passes the caller's path to environment.writeFile.
Behavior traces
The investigated flows follow concrete calls from consumer entrypoints to browser processes, protocol commands, and filesystem output. Launch includes browser-dependent connection branches and cleanup behavior. Navigation distinguishes document replacement from same-document changes, while capture guards shared browser-context operations. Installation has separate cache-hit, incomplete-install, download, extraction, and metadata branches.
- Startup: importing puppeteer constructs PuppeteerNode → launch selects the default/requested browser → #getLauncher returns ChromeLauncher or FirefoxLauncher → the selected launcher receives LaunchOptions.
- Chrome launch: ChromeLauncher.launch → BrowserLauncher.launch → computeLaunchArguments assembles flags, allocates a temporary profile when needed, and resolves the executable → launch spawns the browser.
- CDP connection startup: BrowserLauncher chooses pipe or socket → socket startup waits for the browser's endpoint output and creates WebSocketTransport → Connection is constructed → CdpBrowser._create initializes the browser → waitForPageTarget runs unless disabled.
- New page: CdpBrowser.newPage → defaultContext.newPage → screenshot-operation guard → _createPageInContext → Target.createTarget → waitForTarget → initialization check → target.page.
- Navigation: Page.goto → mainFrame().goto → URL restriction check → LifecycleWatcher → Page.navigate raced with termination → loaderId selects new/same-document completion → navigationResponse → watcher.dispose.
- Locator click: Locator.#click waits for a handle → checks viewport/stability/enabled conditions → emits Action → ElementHandle.click scrolls and finds a clickable point → mouse.click; errors are retried under timeout/abort control.
- Screenshot persistence: Page.screenshot obtains the context guard → validates and normalizes options → optionally changes/restores viewport → CdpPage._screenshot sends Page.captureScreenshot → byte-output branch decodes and writes the optional path.
- Browser installation: downloadBrowsers applies proxy/configuration and skip conditions → concurrent downloadBrowser jobs resolve builds → install → installWithProviders → installUrl reuses a valid installed executable or downloads/unpacks, records aliases, runs setup, and removes the archive.
Testing signals
Tests and CI were inspected, not executed; no passing result is asserted. Browser integration tests use Mocha with shared fixtures and a custom expectation-aware runner, while colocated unit tests use node:test. Inspected tests substantiate navigation, screenshot, provider, extraction, configuration, and cleanup coverage. Coverage observations are bounded: expected failures, skipped tests, weak assertions, and CI exclusions limit what test existence establishes.
- Integration tests use Mocha describe/it and expect assertions; .mocharc loads compiled fixtures, enables async-only tests, and configures three retries under CI.
- Colocated BrowserLauncher unit tests use node:test and verify synchronous profile removal, cleanup unregistration, and one shared exit listener for multiple profiles.
- The runner interprets TestSuites/TestExpectations; FAIL and TIMEOUT may be acceptable outcomes, SKIP normally marks matching tests pending unless focused .only selection bypasses that branch, and later matching expectations override earlier ones.
- Navigation tests cover anchors, redirects, about:blank, history changes, lifecycle selection, 204 responses, and recovery after a network error.
- Screenshot tests compare golden images for clipping, offscreen capture, parallel captures, and full-page captures; the viewport-changing branch checks restoration.
- Provider tests exercise fallback and aggregated errors, but the inspected fixture test accepts either success or selected failures and does not establish successful custom-browser launch.
- Archive tests exercise tar and ZIP contents, yauzl permissions, symlink preservation, and escaping-symlink rejection; symlink preservation is explicitly skipped on Windows.
- CI defines build/lint/docs/type checks, sharded Chrome/Firefox suites, installation and unit jobs; ordinary PRs narrow OS coverage and exclude some Chrome configurations, so inspecting these definitions establishes intended checks rather than executed results.
Risk map
These are security-sensitive source observations and explicitly labeled hypotheses, not confirmed vulnerabilities. The largest trust boundaries involve browser executables, downloaded archives, remote debugging endpoints, host callbacks, and filesystem paths. Platform utilities and protocol differences add compatibility and failure-path uncertainty. The bounded inspection also identified a likely extension-launch synchronization issue requiring runtime reproduction.
- BrowserLauncher inherits process.env by default and spawns a configured executable with consumer arguments; Chrome additionally honors PUPPETEER_DANGEROUS_NO_SANDBOX=true by adding --no-sandbox.
- BrowserURL connection performs a caller-directed fetch and trusts webSocketDebuggerUrl; Node channel connection reads DevToolsActivePort from the browser profile, making endpoint and profile provenance relevant trust boundaries.
- HTTP authentication sends username/password through CDP, while Connection's optional send logger records serialized protocol messages; enabling that logger can expose authentication payloads.
- exposeFunction installs browser-visible bindings backed by caller-provided host functions and new-document scripts; screenshot file output forwards caller paths directly to environment.writeFile.
- Archive integrity verification is optional through expectedHash; installUrl reuses an existing archive without calling downloadFile, and archive-only mode returns an existing file before the verification branch.
- Extraction crosses subprocess boundaries through native ZIP utilities, bzip2/xz, DMG mounting/copying, and Windows installers; escaping-symlink validation is explicit in the yauzl implementation, so that test does not establish equivalent native-tool behavior.
- Optional dependency installation runs root-only apt-get satisfy using downloaded deb.deps; experimental bisect downloads an upstream main-branch Python script into the home directory and executes python3.
- Hypothesis: extension-enabled launch can complete before extension installation settles because Promise.all receives one nested array of installation promises rather than the promises themselves; rejection propagation may also be lost. (inferred)
Extension points
The code provides explicit hooks for transports, download providers, selectors, command composition, and Angular schematics. Internal factories separate browser-specific launch and protocol behavior from shared public abstractions. These interfaces have concrete contracts and caveats rather than uniform support guarantees. API documentation and suite configuration are additional integration points for changes that introduce capabilities.
- BrowserProvider implementations supply supports, getDownloadUrl, getExecutablePath, and getName; methods may be asynchronous, and provider documentation assigns compatibility responsibility to implementers.
- InstallOptions.providers enters an ordered chain with conditional default fallback; custom executable layouts are persisted into Cache metadata.
- ConnectionTransport defines send/close/onmessage/onclose, and connect accepts a supplied transport directly instead of constructing a WebSocket transport.
- CustomQueryHandlerRegistry registers queryOne/queryAll functions under alphabetic names, creates QueryHandler adapters, and appends serialized registration scripts; unregister/clear remove injected scripts.
- getQueryHandlerAndSelector checks custom handlers before built-ins and parses P selectors before falling back to CSS; NodeLocator.create obtains the owning page's default timeout.
- BrowserLauncher subclasses implement executablePath, defaultArgs, computeLaunchArguments, and cleanUserDataDir; PuppeteerNode's #getLauncher is the Chrome/Firefox factory.
- CLI.run composes the shared yargs command table under an optional prefix; the puppeteer wrapper supplies a browsers prefix, configured cache, pinned builds, and disables cache-path override.
- Angular collection.json maps schematic names to factories and schemas, while getCommandForRunner is the runner-selection table; TestSuites.json similarly maps automation-suite parameters to environment variables.
Contributor handoff
Tests and CI were inspected, not executed; this handoff is a source-based starting point with bounded coverage. Begin in the owning package and trace the public abstraction through its protocol or Node implementation before editing. Preserve browser-runtime compatibility, asynchronous cleanup, generated documentation conventions, and expectation semantics. Future verification commands require an execution-authorized task and the repository verification skill.
- Read package.json and the owning manifest first: root test/build scripts delegate through Wireit, and workspace builds include dependency builds rather than only the named package.
- Launch changes should be reviewed across PuppeteerNode, ChromeLauncher, and BrowserLauncher; temporary profiles are cleaned separately from caller-owned Chrome profiles.
- Public API edits require TSDoc with @public/@internal tags; docs/api Markdown is generated and should not be edited manually, and CI checks regenerated-document differences.
- Preserve strict TypeScript checks and established formatting: noImplicitOverride/noUncheckedIndexedAccess are enabled; Prettier uses single quotes, no bracket spaces, trailing commas, and unparenthesized single arrow parameters.
- Before future execution, read puppeteer-verification: it prescribes temporary .only markers for focused Chrome/Firefox tests, npm run unit for units, and npm run build; its npm run format recommendation performs automatic mutations.
- Tests and CI in this investigation were only inspected: suite definitions and expected FAIL/SKIP entries must be considered before treating a future runner success as feature coverage.
- Do not assume CDP/BiDi parity: Firefox defaults to BiDi, Chrome defaults to CDP, and URL allowlist/blocklist configuration is explicitly rejected for BiDi.
- Installation edits need coordinated review of provider fallback, custom executable metadata, incomplete-install detection, extraction backends, and optional peer dependencies; browser-package tests themselves include a download script.
Languages
| Language | Files | Share of source |
|---|---|---|
| Markdown | 752 | docs/config |
| TypeScript | 402 | 81% |
| HTML | 99 | docs/config |
| JavaScript | 93 | 19% |
| JSON | 70 | docs/config |
| YAML | 22 | docs/config |
| CSS | 12 | docs/config |
| Shell | 1 | 0% |
Start reading here
Probable source entrypoint: packages/ — inferred from the directory tree and manifest, not the upstream docs.
Source roots
packages/ (356 files)
Repository structure
| Top-level path | Files |
|---|---|
docs/ | 731 |
packages/ | 356 |
test/ | 259 |
tools/ | 42 |
examples/ | 23 |
.github/ | 23 |
website/ | 16 |
test-d/ | 6 |
Docs found: README.mddocs/api/index.mddocs/api/puppeteer.accessibility.mddocs/api/puppeteer.accessibility.snapshot.mddocs/api/puppeteer.actionoptions.mddocs/api/puppeteer.actionresult.mddocs/api/puppeteer.adapterstate.mddocs/api/puppeteer.addscreenparams.mddocs/api/puppeteer.asyncdisposesymbol.mddocs/api/puppeteer.autofilladdressfield.md
Package
package.json — puppeteer-repo, 42 declared dependencies.
@actions/core@babel/core@babel/plugin-transform-class-properties@babel/plugin-transform-class-static-block@babel/plugin-transform-dynamic-import@babel/plugin-transform-modules-commonjs@babel/plugin-transform-private-methods@babel/plugin-transform-private-property-in-object@microsoft/api-extractor@rollup/plugin-babel@rollup/plugin-node-resolve@stylistic/eslint-plugin
CI & config entrypoints
README.md— Repository readme.github/workflows/publish.yml— GitHub Actions workflow.github/workflows/deflake.yml— GitHub Actions workflow.github/workflows/scorecards-analysis.yml— GitHub Actions workflow.github/workflows/stale.yml— GitHub Actions workflow.github/workflows/docs.yml— GitHub Actions workflow.github/workflows/daily.yml— GitHub Actions workflow.github/workflows/release-please.yml— GitHub Actions workflow.github/workflows/devtools.yml— GitHub Actions workflow.github/workflows/convetional-commit.yml— GitHub Actions workflow
Structural health signals
Average score 7.2/10 across 96 analyzed source files; 23 hotspots surfaced.
tools/docgen/src/custom_markdown_documenter.ts— 1737 lines, score 5 (Large file, Deep nesting)packages/puppeteer-core/src/api/locators/locators.ts— 1220 lines, score 5 (Large file, Deep nesting)packages/puppeteer-core/src/cdp/ExecutionContext.ts— 567 lines, score 5.5 (Large file, Deep nesting)
These are deterministic review leads — size, churn, and structural signals — not proof of a bug in this project.
Recent history
2e45a3af43232026-10-02 — chore(deps): bump joi from 17.13.6 to 17.13.8 in /website (#15529)bef816f1df162026-10-02 — chore(deps): bump fast-uri from 3.1.7 to 3.1.8 in /website (#15528)f3edbe288c962026-10-02 — chore(deps): bump brace-expansion from 1.1.18 to 1.1.21 in /website (#15527)82e1fee0b7402026-10-02 — feat: add page, frame and worker methods on ConsoleMessage (#15515)f891aaa1f64f2026-10-01 — feat(network): add asFetchRequest method to HTTPRequest (#15518)