Puppeteer setFollowSymlinks(): Configure Browser Cache Symlinks
Learn what Puppeteer's setFollowSymlinks() controls, how it differs from the browser cache path, and how to diagnose a missing browser.
setFollowSymlinks() controls whether Puppeteer follows symlinks for file operations. It does not choose or relocate the browser cache. To change the cache location, use the cacheDirectory configuration property or the PUPPETEER_CACHE_DIR environment variable. If Puppeteer cannot find a browser, verify which package you installed and that installation and runtime use the same cache path.
What setFollowSymlinks() does
The PuppeteerNode API describes setFollowSymlinks(followSymlinks) as defining whether Puppeteer should follow symlinks for file operations. The reference does not identify each affected operation or path, so avoid assuming it changes how the browser cache is located or fixes a particular cache problem. Check the documentation for the Puppeteer version in your project before relying on version-specific behavior.
It is a method on PuppeteerNode, not a cache-directory configuration property. The available reference does not establish a default value, so this guide does not prescribe one.
Symlink behavior and browser cache location are separate
| Control | Purpose | Where to set it |
|---|---|---|
setFollowSymlinks(followSymlinks) |
Whether Puppeteer follows symlinks for file operations | PuppeteerNode method |
cacheDirectory |
Directory Puppeteer uses for caching | Puppeteer configuration file |
PUPPETEER_CACHE_DIR |
Overrides the browser cache directory | Environment variable in the applicable install/runtime context |
The current Configuration interface lists the default cache directory as path.join(os.homedir(), '.cache', 'puppeteer'). Puppeteer’s guide notes that browser storage moved to ~/.cache/puppeteer starting with version 19.0.0. Confirm the behavior against your installed Puppeteer version and operating system.
Configure a project-local browser cache
Use this when you want the standard puppeteer package to keep its downloaded browser under your project directory. Puppeteer recommends configuration files for persistent settings.
-
Create a configuration file at the project root. For example,
puppeteer.config.js:import {join} from 'path'; export default { cacheDirectory: join(import.meta.dirname, '.cache', 'puppeteer'), };This is the ES module form shown in Puppeteer’s guide. Ensure your Node.js runtime supports
import.meta.dirname; otherwise use an absolute path constructed in a way supported by your runtime. -
Install or reinstall Puppeteer so its browser installation uses the configured cache. Puppeteer’s troubleshooting guide specifically recommends reinstalling for its cache-directory configuration example to take effect.
-
Run your application in an environment where the configured directory exists and is accessible. If installation and runtime happen in separate containers, CI jobs, users, or build stages, make the browser cache available at the same path in both.
Set the cache path with an environment variable
You can set PUPPETEER_CACHE_DIR for the installation and runtime contexts that need to agree on the browser location. For example, on a POSIX shell:
export PUPPETEER_CACHE_DIR="$PWD/.cache/puppeteer"
npm install puppeteer
Then launch your Node.js application from an environment with that variable set:
export PUPPETEER_CACHE_DIR="$PWD/.cache/puppeteer"
node app.js
Adapt shell syntax and path handling to your operating system and deployment environment. Do not assume a variable set only during application runtime can retroactively move a browser downloaded to another directory during installation.
Runnable Node.js example
Once Puppeteer and its browser are installed and the cache is available, a basic launch check is:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com', {waitUntil: 'domcontentloaded'});
console.log(await page.title());
} finally {
await browser.close();
}
Save as an ES module file such as app.js in a project configured for ES modules, or adapt the import to your project’s module format. This example checks that Puppeteer can launch its installed browser; it does not configure symlink-following behavior.
Choose the right package
The standard puppeteer package downloads a compatible browser by default. puppeteer-core does not download Chrome; use it when you manage the browser yourself or connect to a remote browser. Puppeteer configuration files and environment variables do not apply to puppeteer-core.
For puppeteer-core, provide the executable or connection details for the browser you manage, following the API for your Puppeteer version. Changing PUPPETEER_CACHE_DIR will not make puppeteer-core download a browser.
Installation and deployment details
- After changing cache configuration: reinstall Puppeteer as directed by the troubleshooting guide so the configured cache path takes effect.
- After changing browser download options: rerun the browser installation or postinstall behavior. The configuration guide calls out this follow-up for download-option changes.
- If install scripts were blocked: the installation guide says automatic browser download can be skipped. Allow Puppeteer’s install script or run
npx puppeteer browsers installmanually. - In containers and CI: ensure the browser installed during build is present at the cache path used at runtime, with filesystem permissions that let the runtime user access it.
- With a shared or symlinked directory: distinguish the physical cache location from symlink-following behavior. The API description does not identify which cache operations are affected by
setFollowSymlinks(); verify the exact behavior for your version rather than treating the method as a cache-path switch.
Troubleshooting
| Symptom | Likely cause | What to check or do |
|---|---|---|
| Puppeteer says the browser executable is missing | Install and runtime used different cache paths, or browser download did not run | Check whether you use puppeteer or puppeteer-core, inspect cacheDirectory or PUPPETEER_CACHE_DIR in both contexts, then reinstall or run npx puppeteer browsers install. |
Changing PUPPETEER_CACHE_DIR did not move an existing browser |
The browser was installed before the new setting was applied | Set the variable for installation and runtime, then reinstall Puppeteer or install the browser again. |
| A configuration file appears to be ignored | You are using puppeteer-core, the file is not in the expected project context, or the relevant installation was not repeated |
Use the standard puppeteer package if you want Puppeteer-managed downloads and configuration, confirm the config file is in the project root, and reinstall after changing the cache setting. |
| No browser is downloaded during package installation | Your package manager may have blocked install scripts | Allow Puppeteer’s install script or run npx puppeteer browsers install manually. |
| A symlink-related file operation behaves unexpectedly | The method’s detailed operation-level behavior is not established by the broad API description alone | Check the setFollowSymlinks() reference for your exact Puppeteer version and verify which file operation is involved. Do not infer that changing the cache directory or this method necessarily resolves it. |
| The application works locally but not in deployment | The deployed user, container, or build stage cannot access the cache path used for installation | Make the installed browser available at the configured path in the runtime environment, and check directory permissions and environment-variable propagation. |
Performance, reliability, and cost
The cache setting determines where Puppeteer stores browser files; it does not by itself make browser startup faster or alter screenshot cost. A project-local cache can make the expected location explicit for a build, but your deployment must preserve or recreate those browser files. Reinstalling browser binaries on every run adds installation work; sharing or caching them can avoid repeated downloads when your environment supports it. Keep installation and runtime paths aligned to reduce missing-browser failures.
setFollowSymlinks() should be treated as a file-operation behavior switch, not a general reliability fix. The available reference does not support claims about its default, performance impact, or precise cache effects.
Or skip the browser setup
If your goal is to capture a website rather than manage a local Puppeteer browser, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns an image or PDF, and its parameter names support those used by other screenshot APIs. See the ScreenshotNeo API documentation for the current request 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);
- Cookie and consent banners are accepted like a visitor; more than 60 known consent platforms, newsletter popups, and chat widgets are removed before the shot. Each step can be turned off.
- Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Responses identify page verdict and billing status in
X-Page-VerdictandX-Billedheaders. - An MCP server lets AI agents use
take_screenshot,get_page_info, andcapture_pdf. - The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
FAQ
Does setFollowSymlinks() configure Puppeteer’s browser-cache directory?
No. Use cacheDirectory or PUPPETEER_CACHE_DIR to select the cache location.
Does puppeteer-core use Puppeteer configuration files?
No. Puppeteer configuration files and environment variables do not apply to puppeteer-core.
When did the default browser cache location change?
Puppeteer’s troubleshooting guide says browser storage moved to ~/.cache/puppeteer starting with v19.0.0. The current interface derives the default from the home directory.
Where can I verify the exact symlink behavior?
Use the PuppeteerNode API reference for the version you have installed. The broad description confirms symlink-following control for file operations but does not specify every operation or path affected.


