ScreenshotNeo

BlogGuides

Puppeteer Browser Profile Options Explained

Use `userDataDir` to choose a browser profile at launch, or a `BrowserContext` to isolate storage between tasks. Here’s how to choose and configure each.

By the ScreenshotNeo team4 October 20267 min read

In Puppeteer, set userDataDir in puppeteer.launch() to choose a user data directory for a browser process. Use a BrowserContext when separate automation tasks need isolated cookies and local storage within the same browser. These options operate at different scopes: one selects data for the launched browser; the other separates sessions inside it.

Use userDataDir when a run should use a particular data directory. Use a context when tasks should not share browser storage and you want to close each isolated session independently. The examples below use Puppeteer’s current documented APIs; check the documentation for the version installed in your project.

Choose between a user data directory and a browser context

Option Scope Use it when Lifecycle
userDataDir Browser launch The browser should use a selected user data directory. It is configured when launching the browser; close the browser process when the run is done.
BrowserContext Within a browser Pages or tasks need storage isolation from other contexts. Close the context when the isolated task is done; its pages close with it.
args Browser process You need to pass an additional browser command-line argument. Configured at launch.

Puppeteer documents that contexts isolate storage, including cookies and local storage. Chrome’s non-default contexts are incognito contexts. A context is not a second name for a user data directory: choose based on whether you need browser-launch data selection or task-level isolation.

Set a user data directory with userDataDir

Pass a writable directory path in the launch options. This runnable Node.js example creates a browser, visits a page, reads the page title, and closes the browser:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    userDataDir: './puppeteer-profile'
  });

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

Run it with Node.js in a project where Puppeteer is installed. The relative path is resolved by the process working directory, so choose a location your application can write to. A custom profile directory is useful when you want a run to use a designated directory; it does not, by itself, make separate tasks within one browser isolated from one another.

What else belongs in launch options?

  • headless controls headless behavior. The current launch API documents true as the default, using new headless mode; 'shell' selects the old headless shell. This does not change the scope distinction between a profile directory and a context.
  • args supplies additional command-line arguments to the browser process. Keep Puppeteer’s default arguments unless you have a demonstrated reason to change them; the API cautions that users probably want those defaults.
  • executablePath selects a browser executable. Puppeteer says using a custom executable path is at your own risk because compatibility is only guaranteed with its bundled browser.
  • userDataDir must point to a writable directory. In restricted environments, use a writable location available to the process. Puppeteer’s troubleshooting guide gives /tmp/.puppeteer-profile as an example for environments that need a writable temporary location; it is not a universal path requirement.

See the Puppeteer LaunchOptions API for the available launch settings and version-specific details.

Isolate tasks with a BrowserContext

Create a context for each task that needs separate cookies or local storage. Open pages from that context, then close the context in a finally block so its pages are cleaned up even if navigation or processing fails.

const puppeteer = require('puppeteer');

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

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

To run multiple independent tasks in one browser, create a separate context for each task and create each task’s pages through its own context. Do not create all pages with browser.newPage() and assume they are isolated: that method uses the browser’s default context. Close each non-default context when its work is complete.

The browser starts with at least one default context, and Puppeteer supports creating additional contexts. In Chrome, those additional contexts are incognito. The context API and browser management guide document context creation, page creation, and cleanup: BrowserContext API and Browser management guide.

Keep state across runs or separate it between tasks?

Choose based on the lifetime and boundary you need:

  1. One selected directory for a launched browser: pass userDataDir to puppeteer.launch().
  2. Independent sessions inside a browser: create a BrowserContext per task, create pages from that context, and close it after the task.
  3. Both requirements: launch with the intended userDataDir, then use contexts to isolate tasks within that browser. Verify the behavior in your deployed setup.

The reviewed Puppeteer documentation does not provide a general recipe for reusing a person’s everyday Chrome profile or document platform-specific default profile paths. Avoid relying on guessed paths. It also does not describe safe concurrent processes sharing one user data directory; use separate directories for concurrent launches unless you have verified your browser setup supports the arrangement.

Or skip the browser setup

If the job is to capture a webpage as an image or PDF rather than automate a browser session, ScreenshotNeo provides a screenshot API and MCP server. A single 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://example.com \
  -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers say whether the page was clean and billed. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.

Troubleshooting

Symptom Likely cause Fix
Browser launch fails when using userDataDir. The process cannot write to the selected directory, or the path is invalid. Check that the path exists or can be created and is writable by the process. In a restricted environment, configure a writable location; Puppeteer’s troubleshooting guide shows /tmp/.puppeteer-profile as an example.
Two tasks see the same cookies or local storage. Both pages were created in the same context, commonly the default context. Create a separate context for each isolated task, open pages with context.newPage(), and close each context afterward.
Task pages remain open after processing. The context or browser is not closed on an error path. Put context.close() and browser.close() in finally blocks as shown above.
A custom browser executable behaves differently or fails. The executable is outside Puppeteer’s bundled-browser compatibility guarantee. Use Puppeteer’s bundled browser when possible, or validate the custom executable against your Puppeteer version and environment.
Concurrent launches interfere with each other. The launches may be using the same profile directory. Use distinct directories for concurrent processes unless the deployed browser setup has been verified for shared-directory use.
Launch behavior changes after switching headless mode. headless: 'shell' selects the old headless shell, whereas true uses new headless mode. Choose the mode intentionally and consult the launch API for the installed Puppeteer version. Headless mode does not replace context-based storage isolation.

Performance, reliability, and cost

A context lets multiple isolated tasks use one launched browser process, while a separate launch creates another browser process. The exact performance impact depends on the workload and deployment; the reviewed Puppeteer documentation provides no benchmark figures. Reuse a browser process when that fits your workload, close task contexts promptly, and measure your own navigation and resource use.

For reliability, ensure the profile directory is writable, use cleanup in finally blocks, and verify custom executables in the target environment. Keep concurrent launches on distinct profile directories unless shared use has been validated. Puppeteer itself has no per-screenshot price in the cited profile and context documentation; operational cost depends on where and how you run the browser.

FAQ

How do I keep cookies between Puppeteer runs?

Use a selected user data directory with userDataDir when a browser run needs that directory’s data. The reviewed API material does not establish a general procedure for attaching Puppeteer to a person’s everyday Chrome profile, so verify any such setup for your environment.

Does userDataDir make pages in the browser isolated from each other?

No. It is a launch option for choosing a user data directory. Use separate BrowserContext instances to isolate task storage within a browser.

Are additional Chrome browser contexts incognito?

Yes. Puppeteer documents that non-default contexts are incognito in Chrome.

Can I share one profile directory across concurrent browser processes?

The reviewed documentation does not provide a safe shared-directory concurrency recipe. Use distinct directories unless you have verified your specific browser setup.