How Puppeteer Writes Installed Browser Metadata
Learn which public APIs install and inspect Puppeteer browsers, how to list a cache, and what the docs do—and do not—say about metadata files.
Puppeteer exposes InstalledBrowser.readMetadata() and InstalledBrowser.writeMetadata(metadata) for installed-browser metadata. To enumerate browsers in a cache, use getInstalledBrowsers(options) or the package CLI’s list command. The public API references do not specify the metadata file’s name, location, serialized format, or exactly when writes occur, so treat those as implementation details to verify against the exact package version you use.
1. What “installed browser metadata” means
The supported API describes installed browsers at the package boundary. An installation is configured with a browser, build ID, cache directory, and platform. A successful unpacking installation resolves to an InstalledBrowser object. That object exposes properties including browser, buildId, executablePath, path, and platform, plus the metadata methods readMetadata() and writeMetadata(metadata).
The documentation identifies these methods but does not define a stable on-disk schema. Do not build tooling that assumes a particular filename, JSON shape, field set, write ordering, or atomicity based only on the public reference. If you need those details, inspect the source distributed with the precise @puppeteer/browsers version in your lockfile.
2. Install and inspect a managed browser
The following Node.js example uses the package’s documented install and enumeration APIs. Pin the package version in your project so the API and browser build behavior are reproducible.
npm install @puppeteer/browsers
// save as browsers.mjs
import { install, getInstalledBrowsers, Browser, detectBrowserPlatform } from '@puppeteer/browsers';
import { join } from 'node:path';
const cacheDir = join(process.cwd(), '.browser-cache');
const platform = detectBrowserPlatform();
if (!platform) throw new Error('Could not detect a supported browser platform');
const installed = await install({
browser: Browser.CHROME,
buildId: 'YOUR_CHROME_BUILD_ID',
cacheDir,
platform,
});
console.log({
browser: installed.browser,
buildId: installed.buildId,
path: installed.path,
executablePath: installed.executablePath,
platform: installed.platform,
});
const browsers = await getInstalledBrowsers({ cacheDir });
for (const browser of browsers) {
console.log(browser.browser, browser.buildId, browser.executablePath);
}
Replace YOUR_CHROME_BUILD_ID with the build ID appropriate to your browser version and deployment. A build ID uniquely identifies browser binaries and is used for caching. Consult the package’s API documentation for the exact accepted values and options for the version you install: InstallOptions, install(), and getInstalledBrowsers().
3. Read or write metadata through the object API
The class reference documents both methods. It does not, by itself, establish what metadata fields are valid or whether writing changes a particular file format. Use the type definitions and implementation matching your installed version to determine the metadata value accepted by writeMetadata.
// Starting from an InstalledBrowser object returned by install() or getInstalledBrowsers():
const metadata = await installed.readMetadata();
console.log(metadata);
// Only pass a value that matches the metadata type for your installed package version.
// await installed.writeMetadata(metadata);
The write line is intentionally commented out because the public reference names the method but does not describe a universal metadata schema or safe arbitrary value. Do not fabricate metadata or copy an assumed schema from another release. See the InstalledBrowser reference and inspect the version-specific package type declarations before writing.
4. List browsers without writing application code
The package CLI provides a list command to enumerate installed browsers. Check the help output for the CLI version installed in your project and pass the cache directory option supported by that version. This is useful for diagnosing a CI cache or confirming which build IDs are present.
npx @puppeteer/browsers --help
npx @puppeteer/browsers list --help
The overview documents the listing command and installed-browser enumeration: @puppeteer/browsers overview.
5. Configure the browser cache
Puppeteer configuration documents a cache directory and the PUPPETEER_CACHE_DIR environment override. It also documents an executable path and PUPPETEER_EXECUTABLE_PATH. Keep the installation cache choice and runtime launch choice aligned: inspecting one cache while launching a browser from another path can make a correct installation appear missing.
# Example shell configuration
export PUPPETEER_CACHE_DIR="$PWD/.browser-cache"
# Use only when intentionally selecting a particular executable:
export PUPPETEER_EXECUTABLE_PATH="/absolute/path/to/chrome"
Download-skipping configuration is also documented. It is useful when deployment supplies a browser separately, but then your install and launch steps must agree on where that executable lives. See Puppeteer configuration.
6. Installation metadata and runtime launch are different concerns
install() manages a browser download and unpacking and returns an InstalledBrowser. Launch configuration separately determines which executable Puppeteer starts. The launch options support the bundled browser, a Chrome channel, or an explicit executablePath. The reference says compatibility is guaranteed only with the bundled browser; an explicitly selected executable is used at your own compatibility risk.
| Choice | Browser selection | Practical consideration |
|---|---|---|
| Bundled browser | Puppeteer-managed browser | Documented compatibility-guaranteed option. |
| System channel | Use a Chrome channel found in a known system location | Convenient when the environment manages Chrome; verify availability in each deployment image. |
| Explicit executable path | Use the exact path supplied | Provides control over the binary location; compatibility with Puppeteer is not guaranteed by the reference. |
For the launch details, consult LaunchOptions. Browser installation, metadata inspection, and launch selection should be diagnosed independently.
7. What is not promised by the public documentation
- The exact metadata filename or directory layout.
- The serialized format or complete set of metadata fields.
- Whether metadata is written before, during, or after unpacking.
- Whether writes are atomic or safe when multiple processes install simultaneously.
- Compatibility of internal metadata with a different package version.
For implementation-level guarantees, check the source and declarations for the exact published package version. Record that version alongside any internal tooling that depends on observed implementation behavior, and recheck when upgrading.
8. Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
getInstalledBrowsers() returns an empty list |
The selected cache directory differs from the install location, or no browser has been installed there. | Print the resolved cacheDir; compare it with PUPPETEER_CACHE_DIR and the install options. |
| Executable path does not exist | The archive was not unpacked, the expected build is absent, or runtime configuration points elsewhere. | Confirm install() completed, inspect the returned executablePath, and check launch configuration. |
| Unsupported platform or missing platform value | Platform detection did not return a supported platform for this environment. | Check the deployment OS and the package’s supported platform definitions; do not assume a developer machine’s platform matches CI. |
| Build ID not found or download fails | The build ID is invalid for the selected browser/platform, or the environment cannot access the download source. | Verify browser and build ID pairing in the matching package documentation, then check network and proxy configuration. |
| Metadata read fails after a package upgrade | Local cache contents or assumptions may not match the new package implementation. | Use the public enumeration API and inspect the source/types for the installed version; avoid editing undocumented cache files. |
| Launch works locally but fails in deployment | The deployment image uses a different cache or executable path, or lacks required runtime dependencies. | Log the selected executable path and cache directory in deployment diagnostics; ensure installation and launch use the same environment configuration. |
9. Performance, reliability, and cost
Browser downloads and unpacking are the expensive setup steps; listing installed browsers is an inspection operation against the chosen cache. Reusing a managed cache can avoid repeatedly downloading the same build, while a build ID gives the cache a version-specific identity. In CI, persist or prepopulate the configured cache when appropriate, and ensure jobs do not mistake a partially populated cache for a completed install.
The public references reviewed here do not specify concurrent-write guarantees for cache metadata. For parallel workers, prefer a deployment pattern where installation completes before workers launch, or isolate caches per worker if concurrent installation creates a risk in your environment. This is an operational precaution, not a documented guarantee about Puppeteer’s locking behavior.
Cost depends on where browser binaries are downloaded and stored and on the compute used to run them; Puppeteer’s metadata API itself does not document a service fee. Account for network egress, storage, and browser runtime resources in the environment where you deploy.
10. Or skip the browser setup
If your goal is to get a webpage screenshot rather than manage browser binaries and metadata, ScreenshotNeo provides a screenshot API and MCP server. A single GET request returns an image or PDF, without installing Puppeteer or maintaining a browser cache.
For example, the cURL request below saves a WebP capture. See the ScreenshotNeo API documentation for the available capture 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);
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots.
Create a free ScreenshotNeo account and get 1,000 screenshots a month with no card.
11. FAQ
Can I construct an InstalledBrowser myself?
The class reference marks its constructor internal and advises third-party code not to construct or subclass it. Obtain instances through the package APIs.
Does the metadata method return JSON?
The public reference does not specify the serialization format. Inspect the matching package implementation before relying on one.
Does writeMetadata() install a browser?
No such behavior is documented. Browser installation is handled by install(); the metadata method is documented on an already represented InstalledBrowser.
Which browser choice has the documented compatibility guarantee?
The bundled browser. System channels and explicit executable paths are supported selection options, but the launch reference limits the compatibility guarantee to the bundled browser.


