ScreenshotNeo

BlogEngineering

Puppeteer Browser Process API: Overview

Learn what Puppeteer’s Browser.process() returns, why it can be null, and when to close or disconnect a browser safely.

By the ScreenshotNeo team4 October 20267 min read

browser.process() returns the Node.js ChildProcess for a browser that Puppeteer launched. It returns null when Puppeteer connected to an existing browser with Puppeteer.connect(). A null result is expected in that case; it does not by itself mean launch failed.

Use await browser.close() to close the browser and its pages. Use await browser.disconnect() to stop controlling the browser while leaving its process running. The right choice depends on who owns the browser lifecycle.

1. What Browser.process() returns

Puppeteer’s Browser represents a browser instance that was either launched by Puppeteer or reached through a connection. For a launched browser, browser.process() exposes the associated Node.js child process. Its return type is ChildProcess | null. See the official Browser.process() reference.

const process = browser.process();

if (process === null) {
  console.log('No local child process is associated with this browser connection.');
} else {
  console.log('Browser PID:', process.pid);
}

The method is useful for inspecting the process Puppeteer launched, such as reading its PID or checking whether a local process handle is available. It is not a general way to discover the process behind every remote or connected browser.

2. Complete runnable example

This example launches Chromium, reads the process handle, opens a page, and closes the browser in a finally block so cleanup still runs if navigation or another operation throws.

// Save as browser-process.js
// Install with: npm install puppeteer
const puppeteer = require('puppeteer');

async function main() {
  const browser = await puppeteer.launch({ headless: true });

  try {
    const child = browser.process();
    console.log(child ? `Browser PID: ${child.pid}` : 'No local child process');

    const page = await browser.newPage();
    await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
    console.log('Page title:', await page.title());
  } finally {
    await browser.close();
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

For the current API shape and version-specific details, consult the Browser.process() API reference and the browser management guide.

3. Why the result can be null

A browser connected through Puppeteer.connect() was not launched by that Puppeteer connection. Puppeteer therefore may not have a locally owned child process to return.

// Connect to a browser endpoint supplied by your environment.
const browser = await puppeteer.connect({ browserWSEndpoint });

try {
  console.log(browser.process()); // May be null for a connected browser.
  const pages = await browser.pages();
  console.log(`Connected browser has ${pages.length} page(s).`);
} finally {
  await browser.disconnect(); // Detach; keep the browser running.
}

Do not treat null as a launch error without checking how the browser was obtained. If your code needs the PID, it must launch and own the browser process or get process information from the system or service that owns the remote browser.

4. Close versus disconnect

Intent Call Effect
Shut down a Puppeteer-managed browser await browser.close() Closes the browser and its associated pages.
Stop controlling a browser but leave it alive await browser.disconnect() Disconnects Puppeteer while leaving the browser process running; pages remain open.
Inspect the process for a launched browser browser.process() Returns the associated child process, or null when none is associated with the connection.

These are different lifecycle operations. For a browser you launched for a one-off job, close it when the job ends. For a browser managed by another service or shared across tasks, disconnect when your client is done and let its owner decide when to stop it. Puppeteer documents these behaviors in its browser management guide and the Browser.disconnect() reference.

Puppeteer’s launch options include controls that affect process startup, output, signal handling, and shutdown. Names and defaults can change between releases, so check the documentation matching your installed version.

Option What it controls When to consider it
handleSIGHUP, handleSIGINT, handleSIGTERM Whether Puppeteer installs handlers for these signals. Review when integrating Puppeteer into a service with its own process and signal management.
signal An AbortSignal associated with the browser process; aborting it kills the process. Use when cancellation should terminate a launched browser.
dumpio Forwards browser process stdout and stderr to the Node.js process streams. Enable when browser startup or runtime logs are needed for diagnosis.
executablePath Selects the browser executable to launch. Use when the installed browser location differs from Puppeteer’s default.
onExit A callback that runs once after process exit or before Process.close() closes it. Use only with the semantics documented for the installed Puppeteer version.

See the official LaunchOptions reference. Avoid depending on a default copied from a different Puppeteer release.

6. Reliable cleanup and task isolation

Use finally for owned browsers

Place browser.close() in a finally block when your code launched the browser and should own its shutdown. This covers normal errors during page creation, navigation, and extraction. Do not close a browser that your application does not own simply because your client has finished.

Use BrowserContexts for isolated sessions

Browser contexts do not share cookies or local storage. Closing a context closes its pages, while the default context cannot be closed. A context is useful when separate tasks need isolated browser storage without launching a separate browser for each one. See the browser management guide.

Make shutdown ownership explicit

  • After puppeteer.launch(), your code typically owns the returned browser and should close it when finished.
  • After puppeteer.connect(), determine whether your code is only a client. Disconnecting is usually the operation that preserves the externally managed browser.
  • Do not use browser.process().kill() as a substitute for normal cleanup. Prefer browser.close() for graceful shutdown.
  • If you configure signal handling or cancellation, ensure your service has a clear owner for shutdown and does not leave browsers running unintentionally.

7. Troubleshooting

Symptom Likely cause What to do
browser.process() returns null The browser was connected to rather than launched by this Puppeteer instance. Check whether the code used Puppeteer.connect(). Treat null as a valid result; obtain process details from the browser owner if needed.
Browser remains running after the script The code called browser.disconnect(), which detaches without stopping the browser, or cleanup was skipped. If your code owns the browser, await browser.close() in a finally block.
Pages disappear after cleanup browser.close() closes the browser and associated pages. Use browser.disconnect() if the intent is to leave the browser and pages running.
Browser logs are missing Browser stdout and stderr are not being forwarded. Review the dumpio launch option and the installed version’s documentation.
Signal behavior differs from expectations Puppeteer version, launch options, or application-level signal handlers differ. Check handleSIGHUP, handleSIGINT, and handleSIGTERM for the installed version, and coordinate signal ownership with the service.
Code relying on an option fails after an upgrade Launch option names or defaults can be version-sensitive. Compare the installed Puppeteer version with its matching LaunchOptions reference.

8. Performance, reliability, and cost

Browser.process() is an accessor for the process associated with the browser; the important operational cost is generally the browser lifecycle and the pages your workload opens. Reusing an intentionally managed browser can avoid repeated browser startup, while isolated BrowserContexts can separate cookies and local storage between tasks. Choose based on isolation and ownership requirements.

For reliability, close browsers your code owns, disconnect from browsers owned by another service, and handle errors with guaranteed cleanup. If you use cancellation or signal handlers, verify their behavior against your exact Puppeteer version. This API reference provides no universal performance benchmark or cost figure; actual resource use depends on the browser, pages, workload, and runtime environment.

9. Or skip the browser setup

If your goal is a website screenshot rather than browser-process control, ScreenshotNeo provides a screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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}`);
  • Cookie banners are accepted and removed before the shot; newsletter popups and chat widgets are removed too. Each cleanup step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and billing status.
  • An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
  • The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free 1,000 screenshots a month, with no card.

10. FAQ

Does Browser.process() launch the browser?

No. It returns the process associated with a browser instance; browser startup is done through Puppeteer’s launch flow.

Can I use the returned value when Puppeteer connects remotely?

The result can be null for a connected browser. A remote browser service is responsible for its own process management.

Should I call close() or disconnect() in a finally block?

Use the one that matches ownership: close a browser your code should shut down; disconnect when your code should detach and leave the browser running.

Where can I check the exact options for my version?

Use Puppeteer’s official API documentation for the version installed in your project, especially the LaunchOptions reference.