ScreenshotNeo

BlogHow-to

How to Set a Browser User Data Directory in Puppeteer

Set Puppeteer’s userDataDir launch option to choose a writable Chrome profile directory, retain the state your environment preserves, and avoid common setup errors.

By the ScreenshotNeo team4 October 20266 min read

Set Puppeteer’s browser user data directory with the userDataDir string option passed to puppeteer.launch(). Choose a path that the operating-system account running Chrome can write to. Chrome writes profile data during startup, so an unwritable path can prevent the browser from launching.

1. Set the directory in Puppeteer

Install Puppeteer if it is not already in the project:

npm install puppeteer

The puppeteer package downloads a compatible Chrome for Testing browser. Here is a runnable ES module example:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  userDataDir: '/tmp/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();
}

Replace /tmp/puppeteer-profile with the path you want Chrome to use. The option belongs in the launch options object, alongside other browser launch settings. In TypeScript or CommonJS, the same option is used; only the import syntax changes.

// CommonJS
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    userDataDir: '/tmp/puppeteer-profile',
  });
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com');
  } finally {
    await browser.close();
  }
})();

userDataDir is an optional string path in Puppeteer’s LaunchOptions API. Without an explicit path, Puppeteer creates a temporary profile under the operating system’s temporary directory. See the Puppeteer troubleshooting guide and ScreenshotNeo API documentation for the corresponding browser and screenshot setup references.

2. Choose a path that matches the deployment

The directory is used by the launched Chrome process, so its operating-system user needs permission to create and update files there. On a local machine, use a directory intended for browser data. In a container, verify that the profile path and the browser’s configuration and cache locations are writable too. A read-only filesystem can cause Chrome to fail before Puppeteer connects.

If the profile must remain available across process restarts or container replacement, place it on a volume whose lifecycle preserves it. Merely choosing a path does not guarantee that data survives cleanup, container replacement, or a hosting environment reset. Confirm the behavior of the actual deployment and its mounted volumes.

For an explicit temporary location, Puppeteer’s troubleshooting documentation uses /tmp/.puppeteer-profile as an example. A temporary directory may be cleared by the operating system or deployment, so do not treat it as durable storage without verifying that environment.

3. Understand profiles and browser contexts

userDataDir selects the user data directory for the launched browser. A BrowserContext is a separate way to isolate browser storage while the browser is running. Puppeteer documents that cookies and local storage are not shared between browser contexts, and that non-default Chrome contexts are incognito.

Need Use
Choose the profile directory Chrome uses for a browser launch puppeteer.launch({ userDataDir: '/path/to/profile' })
Keep task storage isolated within a running browser Create and use separate browser contexts
Preserve profile files through a deployment lifecycle Use a volume with the required lifecycle and verify its cleanup behavior

These mechanisms solve different scope and storage needs. A browser context does not select the filesystem directory used for the launched browser.

4. Configure a manually managed Chrome

The puppeteer package downloads a compatible Chrome for Testing browser. puppeteer-core does not download Chrome. If using puppeteer-core or a separately installed browser, configure the executable path or a browser channel for the installation, while keeping userDataDir as the profile setting:

import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  executablePath: '/path/to/chrome',
  userDataDir: '/path/to/writable/profile',
});

try {
  const page = await browser.newPage();
  await page.goto('https://example.com');
} finally {
  await browser.close();
}

Replace the example executable path with the browser binary installed in your environment. Puppeteer’s installation guide describes browser management and the executablePath and channel launch settings.

5. Troubleshoot launch and profile problems

Symptom Likely cause Fix
Chrome fails before Puppeteer connects The profile directory, configuration directory, or cache location is not writable by the Chrome process user. Choose a writable path, check directory ownership and permissions, and in containers mount writable storage for locations Chrome uses at startup.
The browser starts with a fresh profile The configured path differs between runs, or the environment cleared or replaced the directory. Use the same intended path and check the deployment’s volume and cleanup lifecycle. A path alone does not ensure persistence.
The option appears to have no effect userDataDir was placed outside the options object passed to puppeteer.launch(), or the running code uses a different launch call. Pass it directly as a property of the launch options object and inspect the code path that actually starts Chrome.
puppeteer-core cannot find or start Chrome puppeteer-core does not download a browser, and no usable browser executable or channel was configured. Install or provide a compatible browser and set executablePath or channel as appropriate.
Automation ends but Chrome remains running The browser was not closed after the task, including when navigation or another operation threw an error. Put await browser.close() in a finally block so cleanup runs on success and failure.

When diagnosing an issue, check the launch options, the exact operating-system user running Chrome, and write access to the profile and startup directories. Then verify whether the deployment retains the chosen path between runs.

6. Performance, reliability, and cost considerations

A user data directory is a storage and state choice; the cited Puppeteer documentation does not establish a performance benchmark or a universal startup-time effect for choosing a particular path. Keep the profile on storage that is available and writable when Chrome starts, and account for the behavior of temporary directories and mounted volumes.

For reliability, close the browser in a finally block and ensure the profile path remains usable by the Chrome process. If several automation tasks need separate cookies and local storage, use browser contexts for that isolation. If they need different launch-level profile directories, choose the launch configuration and storage lifecycle deliberately.

Puppeteer itself is an open-source browser automation library; this setup may also involve the runtime and infrastructure used to run Chrome. The research sources provide no pricing figure for a particular deployment, so estimate costs from your own hosting and storage configuration.

7. Or skip the browser setup

If the goal is a website screenshot rather than browser automation, ScreenshotNeo returns an image or PDF from one API request. The full options and setup are in 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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

Cookie banners, popups, and chat widgets are removed 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. An MCP server lets AI agents, including Claude and Cursor, take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Every feature is available on every plan.

Sign up for 1,000 free screenshots a month, with no card required.

8. FAQ

Does Puppeteer require me to set userDataDir?

No. It is optional. Puppeteer creates a temporary profile under the operating system’s temporary directory by default.

Will a profile survive closing Chrome?

That depends on the chosen path and the environment’s cleanup and volume lifecycle. Verify the behavior in your deployment.

Should I use a browser context or a user data directory?

Use a context for isolated cookies and local storage within a running browser. Use userDataDir to select the launched browser’s profile directory.

Does puppeteer-core include Chrome?

No. Supply an installed browser and configure its executable path or channel as appropriate.