Puppeteer Launch Options: A Practical Guide
Choose Puppeteer launch options for headless mode, browser selection, Chrome arguments, and reliable startup, with runnable examples and troubleshooting.
puppeteer.launch(options) starts a browser process and returns a browser you can use to open pages, automate workflows, or capture screenshots. For most automation, start with the default headless: true and Puppeteer’s bundled Chrome for Testing. Set headless: false when you need to watch the browser, and add only the Chrome arguments your environment actually requires.
This guide targets Puppeteer 25.12.0. Launch option names and defaults can change between releases, so check the API reference for the version installed in your project.
1. Install Puppeteer and launch a browser
The puppeteer package downloads a compatible Chrome for Testing browser. This is the simplest setup and the browser choice Puppeteer supports best.
npm install puppeteer
Save this as launch.mjs and run it with Node.js:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log(await page.title());
} finally {
await browser.close();
}
Passing no options is equivalent to using the defaults. In this version, the default is new headless Chrome, with a 30-second startup timeout.
2. Choose a headless mode
| Option | What it does | When to choose it |
|---|---|---|
headless: true |
Runs new headless Chrome without showing a window. This is the default. | Unattended automation, CI jobs, and server-side capture. |
headless: false |
Shows a regular browser window. | Debugging launch problems or watching page behavior. |
headless: 'shell' |
Uses the separate chrome-headless-shell binary. |
Automation where its performance tradeoff is useful and its behavior differences are acceptable. |
The shell binary does not reproduce all regular Chrome behavior. Compare results against full Chrome if a page behaves differently. Advice that assumes old headless Chrome was the default may also be outdated: Puppeteer changed its default before version 22.
Launch visibly to debug
const browser = await puppeteer.launch({
headless: false,
slowMo: 50,
});
slowMo is not listed among the version’s launch options in the research used for this guide, so do not include it in a production launch configuration. To show the browser, use headless: false; to diagnose startup, use dumpio: true as described below.
3. Select a browser binary
Puppeteer works best with the Chrome for Testing version it downloads. Compatibility with other browser versions is not guaranteed. Use channel to select an installed Chrome release channel, or executablePath to point at a specific browser executable. When using executablePath, specify browser as well if the executable is not Chrome; the launch reference says Chrome is otherwise assumed.
// Use an installed Chrome channel
const browser = await puppeteer.launch({
channel: 'chrome',
});
// Use an explicit Chrome executable path
const browser = await puppeteer.launch({
executablePath: '/path/to/chrome',
});
Replace the example path with a real executable path for the host. A path that exists on a developer laptop may not exist inside a container or CI worker.
Using puppeteer-core
puppeteer-core does not download a browser. Provide either executablePath or channel when launching it.
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.launch({
executablePath: '/path/to/chrome',
headless: true,
});
4. Add Chrome command-line arguments safely
Use args to append browser command-line switches that a particular environment or task requires. There is no universal set of flags that every Puppeteer deployment needs; determine what your environment requires and add those specific arguments.
const browser = await puppeteer.launch({
args: ['--lang=en-US'],
});
Puppeteer supplies default arguments of its own. The API warns that you probably want to keep them. If one default argument causes a specific problem, use ignoreDefaultArgs with an array to filter only that argument:
const browser = await puppeteer.launch({
ignoreDefaultArgs: ['--mute-audio'],
});
Setting ignoreDefaultArgs: true removes the entire default argument list. This can change browser startup behavior in ways your script depends on, so use it only when you understand the effects and have supplied what your setup needs.
5. Set startup, logging, and process behavior
| Option | Purpose | Practical guidance |
|---|---|---|
timeout |
Maximum wait for the browser to start; default is 30,000 milliseconds. | Raise it if startup is legitimately slow. Set it to 0 to disable the launch timeout. |
dumpio |
Forwards browser stdout and stderr to the corresponding Node.js streams. | Turn it on when investigating browser startup failures or process output. |
handleSIGHUP, handleSIGINT, handleSIGTERM |
Control whether Puppeteer closes the browser when Node receives those signals. | These options default to true. Change them only if your process manager needs different shutdown handling. |
const browser = await puppeteer.launch({
timeout: 60_000,
dumpio: true,
});
Disabling the timeout with timeout: 0 can leave a process waiting indefinitely if startup stalls. Prefer a longer finite value when you know startup can take more than 30 seconds.
6. Use specialized launch controls when needed
userDataDirsets the browser profile directory. Use a suitable profile path when you need a persistent profile; avoid having concurrent browser processes write to the same profile directory.devtools: trueopens DevTools and forces headful mode. It is useful for interactive debugging, not typical unattended jobs.pipe: truerequests pipe communication instead of WebSocket. The documented option is for Chrome only.waitForInitialPagecontrols whether Puppeteer waits for the initial page. It can matter when startup has been changed, for example by using--no-startup-window.
These are targeted controls. Start with the defaults and introduce them only to address a concrete need.
7. Configure launches by task
Unattended automation
const browser = await puppeteer.launch({
headless: true,
timeout: 30_000,
});
This makes the default headless behavior and timeout explicit. The bundled Chrome for Testing browser remains the preferred compatibility choice.
Debug a startup failure
const browser = await puppeteer.launch({
headless: false,
dumpio: true,
timeout: 60_000,
});
A visible window helps inspect launch and page behavior; forwarded browser output can reveal process errors. If the failure occurs before a window appears, inspect the Node process output as well.
Use an installed browser with puppeteer-core
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.launch({
executablePath: process.env.CHROME_PATH,
headless: true,
timeout: 45_000,
});
Set CHROME_PATH to an actual executable path in the runtime environment before starting the script.
8. Take a screenshot with Puppeteer
Launch options control the browser process. Page-level choices such as the target URL, viewport, and screenshot format are configured separately after launch.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900 });
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
await browser.close();
}
Use a wait condition that matches the page. A page with continuing network activity may never become network idle; use domcontentloaded or wait for a specific selector when that better represents readiness.
9. Troubleshoot common launch problems
| Symptom | Likely cause | What to try |
|---|---|---|
| Launch fails because no executable is found | puppeteer-core has no bundled browser, or executablePath points to the wrong location. |
Provide a valid executablePath or channel; confirm that the path exists in the same environment running Node. |
| An installed Chrome version behaves unexpectedly | The browser version may not match the one Puppeteer supports. | Prefer Puppeteer’s bundled Chrome for Testing, or verify compatibility for the installed browser and Puppeteer release. |
| Startup times out | The browser takes longer than the configured timeout to start. | Enable dumpio: true to inspect browser output and raise timeout if startup is simply slow. |
| Browser starts but the expected window is hidden | headless is true, which is the default. |
Set headless: false to show a window. |
| Page behavior differs in headless shell | headless: 'shell' uses a separate binary that does not match all regular Chrome behavior. |
Try headless: true or headless: false to compare against full Chrome. |
| A launch change causes unrelated browser behavior to break | All default arguments may have been removed. | Restore defaults and filter only the single problematic argument using an array for ignoreDefaultArgs. |
| DevTools appears even though headless was requested | devtools: true forces headful mode. |
Disable devtools for unattended headless runs. |
| Script exits while the browser remains running | Process signal handling may have been changed, or the browser is not closed in the script. | Keep the signal handling defaults unless needed and close the browser in a finally block. |
10. Performance, reliability, and cost
headless: 'shell' may be faster for some automation, but it uses a different binary and can behave differently. Measure it against your task before adopting it. The dossier provides no universal performance benchmark, so the best mode depends on the pages and checks you run.
For reliability, prefer Puppeteer’s bundled Chrome for Testing when possible, set a finite startup timeout appropriate to the runtime, capture browser output while diagnosing failures, and close the browser even when page work throws an error. Treat external browser paths and versions as deployment dependencies that must exist wherever the script runs.
Puppeteer itself is a library; browser execution consumes the compute resources of the machine or service running it. This research does not establish infrastructure prices or per-capture costs. Account for the runtime and browser infrastructure you choose when estimating cost.
11. Or skip the browser setup
If your task is to capture a website, ScreenshotNeo offers a screenshot API and MCP server. It returns a PNG, JPEG, WebP, or PDF from one GET request. See the ScreenshotNeo API documentation for the available options.
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
The Node.js snippet uses Bun’s file-writing helper to save the response. In plain Node.js, use writeFile from node:fs/promises with Buffer.from(await res.arrayBuffer()).
import { writeFile } from 'node:fs/promises';
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed; response headers identify the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card required.
12. Frequently asked questions
What is the minimum launch call?
await puppeteer.launch() uses the defaults, including headless mode and Puppeteer’s default startup timeout.
Does timeout limit page loading?
No. It is the browser startup wait. Page navigation and page readiness are handled separately.
Can I pass a browser argument as an option?
Use the args array to pass Chrome command-line arguments. Keep Puppeteer’s default arguments unless you have a specific reason to filter one.
Which browser is safest for compatibility?
Puppeteer’s bundled Chrome for Testing is the supported starting point. Compatibility with other browser versions is not guaranteed.


