ScreenshotNeo

BlogHow-to

How Puppeteer Reads Installed Browser Metadata

Learn how Puppeteer lists browsers in its cache, resolves system Chrome by channel, and uses an explicit executable path—with runnable code and fixes for common errors.

By the ScreenshotNeo team4 October 20268 min read

Puppeteer does not use one general-purpose API to scan every browser installed on a computer. To list browsers Puppeteer manages in its cache, use getInstalledBrowsers() from @puppeteer/browsers. To select system Chrome, use a supported channel; to select a browser at an arbitrary location, pass executablePath.

Those are separate paths with different scopes. The cache listing reports Puppeteer-managed installations and their recorded metadata. A channel lookup resolves Chrome at known system locations. An explicit path uses the binary you name. None should be mistaken for a host-wide scan of arbitrary browser installations.

1. List browsers in Puppeteer’s cache

Install the browser-management package if it is not already available in your project:

npm install @puppeteer/browsers

This runnable Node.js example prints the browser identity, build ID, platform, executable path, and installation root for cached entries:

import { getInstalledBrowsers } from '@puppeteer/browsers';

const browsers = await getInstalledBrowsers({
  cacheDir: '/home/me/.cache/puppeteer',
});

for (const browser of browsers) {
  console.log({
    browser: browser.browser,
    buildId: browser.buildId,
    platform: browser.platform,
    executablePath: browser.executablePath,
    installDir: browser.path,
  });
}

Replace cacheDir with the cache directory for the environment you are inspecting. Puppeteer’s default cache is based on the home directory and has been ~/.cache/puppeteer on Linux since v19. The exact directory can be changed in configuration or with PUPPETEER_CACHE_DIR. In containers, CI, and services, the process home directory may differ from the home directory you use interactively.

The returned InstalledBrowser model documents browser, build ID, platform, executable path, installation root, and metadata read/write methods. Use the supported listing API to obtain these objects; the class constructor is documented as internal. The API lists installations in the selected cache, not every Chrome, Chromium, or Firefox installation elsewhere on the host.

The model exposes readMetadata() and writeMetadata(metadata). Treat these as cache metadata operations. Do not assume that readMetadata() is a live query of the browser process or that it returns a runtime version in a particular schema unless the API documentation for your installed package version specifies that.

2. Find and launch system Chrome by channel

If you mean Chrome installed by the operating system or another installer, use Puppeteer’s Chrome channel selection. Puppeteer checks known locations for the requested channel; it does not use the cache listing for this lookup.

import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  channel: 'chrome',
  headless: true,
});

console.log('Launched system Chrome');
await browser.close();

The channel identifies a release channel such as chrome or chrome-beta. The exact supported channel values and platform behavior are defined by the Puppeteer version in use. If the expected executable is not in a known location, resolution fails; install that channel or use an explicit path.

For lower-level resolution, computeSystemExecutablePath from @puppeteer/browsers computes the expected system executable path for a browser, build ID/channel, and platform. It can throw if the expected executable is missing. Consult its API reference for the argument types required by your package version rather than building paths by hand.

3. Launch a browser at an explicit path

When a browser lives at a custom path, pass that path directly. This is useful for managed images, custom installations, or a browser supplied by another tool.

import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  executablePath: '/opt/chrome/chrome',
  headless: true,
});

console.log('Launched the requested executable');
await browser.close();

The path must exist and be executable by the current user. Puppeteer does not guarantee compatibility with every externally installed Chrome version; its downloaded browser is the best-supported pairing. Check the supported browser matrix for the Puppeteer version you deploy.

4. Choose the right package and discovery method

Goal Use Scope and caveat
Enumerate Puppeteer-managed downloads getInstalledBrowsers({ cacheDir }) Only entries in that cache directory
Launch system Chrome in a known location launch({ channel }) Chrome channel and known locations; can fail if absent
Launch a custom browser binary launch({ executablePath }) Caller provides the path and owns compatibility checks
Use Puppeteer’s managed browser install puppeteer Downloads Chrome for Testing by default, subject to install configuration
Use a browser managed elsewhere puppeteer-core Does not download Chrome; provide a channel or executable path

The standard puppeteer package downloads Chrome for Testing by default. puppeteer-core is intended for cases such as remote or separately managed browsers and does not download Chrome. With puppeteer-core, choose channel or executablePath when launching.

5. Configure the cache and browser download behavior

Configuration determines where Puppeteer stores and looks for its managed browser. The documented configuration includes a cacheDirectory setting and the PUPPETEER_CACHE_DIR environment override. Keep the directory consistent between installation and runtime, especially in CI or containers.

# Example: point Puppeteer at a project-managed cache for this process
PUPPETEER_CACHE_DIR=/workspace/.puppeteer-cache node app.js

Downloads can also be skipped through configuration or PUPPETEER_SKIP_DOWNLOAD. Package managers may block install scripts, which can leave the expected browser absent. In that situation, allow the install script or install the browser explicitly with Puppeteer’s browser command, following the installation guide for your version.

PUPPETEER_EXECUTABLE_PATH is a configuration override relevant to executable selection. If using it, verify the actual environment and package version rather than assuming it changes the cache listing: cache enumeration and launch executable selection answer different questions.

6. Other ways to inspect browser metadata

For a browser object you have already launched, you can ask the browser process for its reported version and inspect the resolved executable path. This reports the running browser, unlike enumerating cached installations.

const version = await browser.version();
console.log({ version, executablePath: browser.process()?.spawnfile });

This is useful when the practical question is “what did this launch actually start?” It does not enumerate other cached installations. The version string is runtime information from the launched browser, while getInstalledBrowsers() describes entries in a cache.

7. cURL, Python, and Node.js examples for a screenshot

Puppeteer itself is a Node.js browser automation library, so its cache and launch APIs are used from JavaScript. If the goal is to obtain a website screenshot rather than manage a local browser installation, these examples call ScreenshotNeo’s screenshot API directly. See the ScreenshotNeo API documentation for request options.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

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 import('node:fs/promises').then(({ writeFile }) =>
  writeFile('shot.webp', Buffer.from(await res.arrayBuffer()))
);

8. Troubleshooting

Symptom Likely cause Fix
getInstalledBrowsers() returns an empty list The selected cache directory is empty, wrong, or different from the install-time directory Check cacheDir, PUPPETEER_CACHE_DIR, process home, and whether a browser download completed
“Could not find Chrome” Install scripts were blocked, download was skipped, or the expected browser was not installed Allow the package install script or install the browser with Puppeteer’s browser command; confirm the configured cache
Channel launch cannot find Chrome No matching Chrome channel exists at a location Puppeteer checks Install the requested channel at a known location, choose another available channel, or pass executablePath
Explicit path launch fails Path is wrong, binary lacks execute permission, or runtime dependencies are missing Check the path and permissions in the same container/user context; verify the OS can start that binary
Browser launches but behaves unexpectedly External browser version may not match Puppeteer’s supported browser pairing Use the Chrome for Testing version managed by the matching Puppeteer release, or verify the version matrix
Works locally but not in CI Different home, cache environment, install-script policy, or filesystem between build and runtime Set one explicit cache directory in both stages and ensure the downloaded browser is present in the runtime image

9. Performance, reliability, and cost

Enumerating cache metadata avoids launching every browser just to learn which managed builds are present. It is the appropriate inventory step when inspecting Puppeteer’s cache, but it does not prove a binary can launch successfully. For reliability, validate the chosen executable in the same operating system image, user context, and container where the application will run.

Keeping Puppeteer’s downloaded browser alongside the matching package version reduces compatibility uncertainty. A system channel or arbitrary executable can be useful when the environment manages Chrome separately, but browser updates can change independently of the application. Pin and review the browser/Puppeteer pairing using the official support matrix.

With a local Puppeteer setup, account for browser installation and storage in your build or deployment process. If your task is simply to capture pages, ScreenshotNeo removes the need to install and maintain a local browser for that request. Its API pricing is 1,000 shots per month free with no card, then $5 for 3,000 on Starter; yearly billing gives two months free. Every feature is available on every plan.

10. Or skip the browser setup

One GET request returns a screenshot image or PDF. Cookie and consent banners are accepted like a visitor and removed along with 60+ known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers say the page verdict and whether it was billed.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp

ScreenshotNeo also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Learn more at ScreenshotNeo and read the API docs.

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

11. FAQ

Does Puppeteer automatically find system Chrome?

It can resolve a Chrome release channel at known system locations when you request that channel. It does not make getInstalledBrowsers() a scan of all host browsers.

Does the cache listing include browsers installed by apt, Homebrew, or another package manager?

Only if an installation is also present in the cache directory being listed. Use a channel or explicit executable path for system-managed Chrome.

Can I use cached-browser metadata as proof that the browser works?

No. The listing identifies cache entries and paths; launch the browser in its target environment to confirm it starts.

Should I use puppeteer or puppeteer-core?

Use puppeteer when you want its managed Chrome for Testing download. Use puppeteer-core when another system manages the browser, and supply a channel or executable path.

Official references