ScreenshotNeo

BlogHow-to

How to Configure Puppeteer’s Download Base URL

Set Puppeteer’s Chrome download host with project config, environment variables, or the Browsers API—and fix common mirror and cache issues.

By the ScreenshotNeo team1 October 20266 min read

How to Configure Puppeteer's Download Base URL

Use chrome.downloadBaseUrl in a Puppeteer configuration file for a persistent project setting. Set the URL to an explicit protocol such as https://, omit the trailing slash, then run npx puppeteer browsers install so Puppeteer applies the new download host.

/** @type {import('puppeteer').Configuration} */
export default {
  chrome: {
    downloadBaseUrl: 'https://mirror.example.com/chrome-for-testing-public',
  },
};

Puppeteer appends the browser, platform, and build-specific path when it constructs the archive URL. The base URL is therefore the mirror host and path, not the complete archive URL.

1. Choose the configuration method

Method Best for Scope
chrome.downloadBaseUrl Committed project configuration All Puppeteer installs that read the project config
PUPPETEER_CHROME_DOWNLOAD_BASE_URL CI, containers, or environment-specific mirrors One shell environment or install
InstallOptions.baseUrl Direct use of @puppeteer/browsers One installer call

Environment variables override configuration-file options when the variable applies to the Puppeteer version in use. Keep a mirror URL in configuration when reproducibility matters; use an environment variable when the host differs between local development, CI, and private networks.

2. Configure a project with a Puppeteer config file

Puppeteer searches up the directory tree for supported configuration names, including:

A download base URL changes the archive host while Puppeteer still builds the browser, platform, and build path.
A download base URL changes the archive host while Puppeteer still builds the browser, platform, and build path.
  • .config/puppeteer.config.cjs
  • .config/puppeteer.config.js
  • .config/puppeteerrc.cjs
  • .config/puppeteerrc.js
  • .config/puppeteerrc.json
  • .config/puppeteerrc
  • puppeteer.config.cjs
  • puppeteer.config.js
  • package.json

ESM configuration

/** @type {import('puppeteer').Configuration} */
export default {
  chrome: {
    downloadBaseUrl: 'https://mirror.example.com/chrome-for-testing-public',
  },
};

CommonJS configuration

/** @type {import('puppeteer').Configuration} */
module.exports = {
  chrome: {
    downloadBaseUrl: 'https://mirror.example.com/chrome-for-testing-public',
  },
};

JSON configuration

{
  "chrome": {
    "downloadBaseUrl": "https://mirror.example.com/chrome-for-testing-public"
  }
}

Put the file in the project before installing Puppeteer or before the browser installation step. Download-related settings are read during browser acquisition.

3. Apply the change after editing configuration

Changing the URL does not move a browser that is already in Puppeteer’s cache. Re-run the browser installer so the next required archive is fetched using the new host:

npx puppeteer browsers install

If your package manager blocked install scripts, this manual command is also the recovery path. The configuration guide specifically requires rerunning the postinstall process when download options change.

4. Set the URL with an environment variable

Set the Chrome-specific variable before installing Puppeteer:

PUPPETEER_CHROME_DOWNLOAD_BASE_URL=https://mirror.example.com/chrome-for-testing-public npm install puppeteer
npx puppeteer browsers install

For a separate install step:

export PUPPETEER_CHROME_DOWNLOAD_BASE_URL=https://mirror.example.com/chrome-for-testing-public
npm install puppeteer
npx puppeteer browsers install

Current Puppeteer configuration uses the browser-specific name PUPPETEER_CHROME_DOWNLOAD_BASE_URL. Older examples may show the general PUPPETEER_DOWNLOAD_BASE_URL; use the variable documented for the major version installed in your project.

5. Use a base URL with @puppeteer/browsers

If you call the Browsers API directly, pass baseUrl in the install options. This setting is independent of puppeteer.launch().

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

await install({
  browser: Browser.CHROME,
  buildId: 'YOUR_BUILD_ID',
  cacheDir: './.cache/puppeteer',
  baseUrl: 'https://mirror.example.com/chrome-for-testing-public',
});

The installer combines the selected browser, platform, and build ID with the base URL. The documented default hosts are Chrome for Testing’s Google Cloud Storage host and Mozilla’s Firefox nightly host.

6. Mirror requirements and URL rules

  • Include an explicit protocol, normally https://.
  • Do not add a trailing slash.
  • Preserve the archive layout expected by Puppeteer.
  • Keep browser build IDs and platform paths available at the locations Puppeteer constructs.
  • Make the mirror reachable from every machine that performs installation.

For example, Puppeteer may construct a path beneath your host using the browser, operating-system platform, and requested build. Supplying a URL to one individual ZIP file will not work as a base URL.

7. Puppeteer versus puppeteer-core

Configuration files and Puppeteer download environment variables apply to the puppeteer package. puppeteer-core ignores these defaults and does not download Chrome during installation.

Puppeteer manages downloads; puppeteer-core expects the browser to be managed separately.
Puppeteer manages downloads; puppeteer-core expects the browser to be managed separately.

With puppeteer-core, manage the browser yourself and provide either an executable path or a standard browser channel:

import puppeteer from 'puppeteer-core';

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

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

8. Troubleshooting

Symptom Likely cause Fix
Puppeteer still contacts Google The config was created after installation, the variable was not present, or the cached browser already satisfies the install. Place the setting before installation, verify the variable name, and run npx puppeteer browsers install.
404 from the mirror The mirror does not preserve Puppeteer’s expected browser, platform, or build-ID layout. Mirror the expected directory structure and confirm the requested build exists.
Invalid URL or malformed request The base URL has no protocol or has an incorrectly assembled path. Use an explicit protocol and a host/path without a trailing slash.
Setting has no effect with puppeteer-core puppeteer-core does not read Puppeteer download defaults. Install/manage Chrome separately and pass executablePath or channel.
No browser was downloaded The package manager skipped Puppeteer install scripts. Allow the install script or run npx puppeteer browsers install manually.
Local runs work but CI fails The CI job cannot resolve or authenticate to the private mirror, or the variable is not exported in that job. Expose the variable in the install step and check network access, credentials, and archive permissions.
Changing the URL appears to do nothing An existing cached browser is being reused. Understand that the setting controls the next required download; inspect the cache or request a build that is not present.

9. Reproducibility, performance, and cost

Reproducibility

Commit a configuration file when every developer and CI runner should use the same mirror. Pin the Puppeteer version and ensure the mirror retains the build IDs that version requests.

Performance

A nearby mirror can reduce download latency and avoid repeated transfers across a private network. Puppeteer still needs the archive paths and files required for the selected platform and build.

Reliability

Keep the mirror available during fresh installs and cache restores. A fallback host is not created automatically by setting one base URL, so your deployment process should provide its own fallback or prepopulate the browser cache.

Cost

A download base URL changes where browser archives are fetched; it does not change Puppeteer licensing or browser behavior. Account for mirror storage, bandwidth, retention, and access-control costs separately.

10. Verify the effective setup

  1. Confirm the configuration file is in one of Puppeteer’s searched locations.
  2. Confirm the URL has a protocol and no trailing slash.
  3. Check that the environment variable is set in the same shell or CI step that runs installation.
  4. Run npx puppeteer browsers install.
  5. Check the mirror access logs for the browser, platform, and build-specific path requested by the installer.
  6. Launch Puppeteer and verify it can find the installed browser.

Or skip the browser setup

If your goal is simply to produce website screenshots, ScreenshotNeo provides a hosted API instead of requiring Puppeteer, Chrome downloads, and mirror maintenance.

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}`);

See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

FAQ

Does the base URL include the Chrome version?

No. Provide the mirror host and base path. Puppeteer adds the browser, platform, and build-specific path.

Can I set this in puppeteer.launch()?

No. Download hosts are installation settings. Launch options select or locate an already managed browser.

Which setting should a CI pipeline use?

Use PUPPETEER_CHROME_DOWNLOAD_BASE_URL when the host is supplied by the CI environment; commit a config file when the mirror is part of the project’s standard setup.

Will a new mirror relocate every cached browser?

No. The new host is used when Puppeteer needs to fetch an archive; existing cache entries are not retroactively moved.