ScreenshotNeo

BlogEngineering

How Puppeteer Detects the Browser Platform

Puppeteer reads Node.js platform and architecture values to choose a browser download target. Here are the mappings, overrides, and ways to debug platform mismatches.

By the ScreenshotNeo team4 October 20266 min read

Puppeteer detects the host platform from Node.js, not from a web page. Its browser-management code reads os.platform() and os.arch(), then maps those values to a BrowserPlatform used to select a compatible browser download. This is separate from the browser’s user-agent and from the executable Puppeteer ultimately launches. The mapping described below reflects the Puppeteer source checked on 2026-10-03; it may change in other versions.

1. What Puppeteer detects

The detector is in @puppeteer/browsers. It inspects the Node.js process host environment using the built-in os module. In current source, the relevant inputs are:

  • os.platform(): an OS identifier such as darwin, linux, or win32.
  • os.arch(): an architecture such as arm64 or x64.
  • os.release(): additionally consulted for Windows ARM64 to determine whether the Windows 11 threshold is met.

The result describes a browser download target. It does not inspect the requested website, the page’s user-agent string, or a browser’s JavaScript-reported platform. Puppeteer documents the install platform as “Auto-detected” by default. Puppeteer browsers API; current detector source.

2. Current platform mapping

Node OS Node architecture Mapped BrowserPlatform Notes
darwin arm64 MAC_ARM Apple Silicon target
darwin Other MAC The fallback describes this mapping, not universal support for every architecture
linux arm64 LINUX_ARM Linux ARM target
linux Other LINUX Fallback mapping
win32 x64 WIN64 64-bit Windows target
win32 arm64 WIN64 on Windows 11 release 10.0.22000 or later; otherwise WIN32 The source notes Windows 11 ARM supports x64 emulation
Other OS value Any No value (undefined) No inferred platform

Do not treat the “other architecture” macOS and Linux cases as a promise that every CPU architecture will run every downloaded browser. The mapping chooses a target label; the archive and runtime still need to be compatible. The Windows ARM decision uses the OS release threshold in the current detector, not a general check of the Windows marketing name.

3. Inspect the inputs and reproduce the mapping

Run these commands in the same Node.js runtime and container where Puppeteer installation occurs. This small script prints the raw values and the detector result exposed by @puppeteer/browsers.

npm install @puppeteer/browsers
node --input-type=module -e 'import os from "node:os"; import { detectBrowserPlatform } from "@puppeteer/browsers"; console.log({ platform: os.platform(), arch: os.arch(), release: os.release(), browserPlatform: detectBrowserPlatform() });'

The detector can return undefined for an OS platform it does not recognize. Compare its result with the platform of the binary you are installing, and record the exact package version: source behavior can evolve.

4. Install a browser for a selected platform

The browsers installation API infers the platform by default and accepts an explicit platform when the caller needs to select one. This runnable example installs a Chrome for Testing build for the detected platform using the browsers package API:

import { install, detectBrowserPlatform } from '@puppeteer/browsers';

const platform = detectBrowserPlatform();
if (!platform) {
  throw new Error('Puppeteer could not infer a supported browser platform');
}

const installed = await install({
  browser: 'chrome',
  buildId: 'stable',
  platform,
  cacheDir: './.cache/puppeteer',
});
console.log(installed.executablePath);

For a deliberate cross-target or controlled build environment, replace platform with a supported BrowserPlatform value from the package. Choose an archive that your deployment runtime can actually execute; an override does not translate binaries or guarantee compatibility. Refer to the browsers API documentation for the current accepted options and platform enum.

5. Download selection and launch selection are separate

Platform detection helps determine which browser archive to install. It does not alone determine which executable is launched in every setup.

  • The standard puppeteer package downloads a compatible Chrome for Testing build and a separate chrome-headless-shell binary.
  • Configuration can skip downloads or set an executable path.
  • Launch options can specify an executable path or a Chrome release channel available at a standard system location.
  • With puppeteer-core, you manage browser installation and supply an executable path or channel.

Check the installation guide, configuration interface, and launch options for version-specific details. A correct detected platform can coexist with a manually configured executable from another location, and an explicit launch path can bypass the expected downloaded binary.

6. Debug a platform mismatch

  1. Print the runtime inputs. Capture os.platform(), os.arch(), and, for Windows ARM64, os.release() in the install environment.
  2. Check the Node process environment. A local shell, CI runner, container, and production host can report different values or use different CPU emulation.
  3. Inspect the selected target. Log the inferred or explicitly configured BrowserPlatform alongside the browser name and build ID.
  4. Inspect download and launch configuration. Look for a platform override, skipped download, custom cache directory, executable path, or channel.
  5. Verify binary compatibility at runtime. The download target label alone does not establish that the host can execute the archive.
  6. Compare package versions. The cited detector source is mutable; check the source and docs matching the version actually installed.

7. Common errors and fixes

Symptom Likely cause What to do
Platform cannot be determined The host OS string is not handled by the detector Print the Node OS values; if the API accepts it, pass an explicit supported platform and confirm the archive is compatible
Browser download succeeds but launch fails The selected archive does not match the actual runtime, or launch points elsewhere Check architecture, OS, executable path, and whether the process runs under emulation
ARM host gets an unexpected Windows target The current mapping checks the release threshold 10.0.22000 Log os.release() in the install process and compare with the detector source for the installed version
Expected downloaded Chrome is missing Downloads may be skipped or managed separately, especially with puppeteer-core Review installation configuration and provide a valid executable path or channel
Local works, CI fails CI may use a different OS, architecture, container base, or cache Print platform inputs and resolved executable path in both environments; install for the actual deployment target
Wrong browser launches despite a correct detector result Launch configuration selects a custom executable or channel Inspect launch options independently of installation platform selection

8. Performance, reliability, and cost considerations

The platform check reads local Node.js OS metadata; the practical operational work is browser download, cache management, and process launch. Reuse a browser cache where appropriate and avoid downloading during every application start. In CI or container builds, make the target environment explicit and ensure the cached archive matches it. Pin and review the Puppeteer package version when relying on implementation details, since the cited source is on the mutable main branch.

Puppeteer itself does not assign a per-screenshot API charge in this platform-detection flow. Your operational costs depend on where you run Node.js and how you provision browser binaries and compute; no performance benchmark or compatibility percentage is established by the cited sources.

9. Capture a page without managing browser binaries

If your goal is a rendered page image rather than control over a local Puppeteer browser, ScreenshotNeo is a website screenshot API and MCP server. A single GET request returns a PNG, JPEG, WebP, or PDF, so you do not need to install and select a browser binary in your application.

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,
)
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 Bun.write('shot.webp', res);

In Node.js, save the response body using your runtime’s file API; for Node’s built-in filesystem API, use await import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', Buffer.from(await res.arrayBuffer()))) after checking res.ok. See the ScreenshotNeo API documentation for request options and response details.

Or skip the browser setup

ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed, and 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 shots. Every feature is on every plan. Read the docs and sign up for 1,000 free screenshots a month, no card required.

10. FAQ

Does Puppeteer detect the website’s operating system?

No. This detector reads the host running Node.js to choose browser download targets. Website-facing browser identity is a separate concern.

Can I force a platform?

The browser install API accepts a platform option. Use it only when the selected archive suits the machine where it will run.

Does a detected platform guarantee Puppeteer launches that downloaded browser?

No. Executable paths, release channels, skipped downloads, and puppeteer-core change how the browser is supplied or selected.

Will the mapping stay the same?

Not necessarily. Treat these mappings as the behavior of the checked implementation and verify the source for your installed version.

Sources