ScreenshotNeo

BlogHow-to

How to Troubleshoot Playwright Screenshot Permission Errors in Docker

Trace Docker screenshot failures to the right cause: output permissions, container identity, HOME, Chromium sandboxing, browser versions, or shared memory.

By the ScreenshotNeo team4 October 20268 min read

When Playwright cannot save a screenshot in Docker, first identify whether it fails while launching Chromium or while writing the image. An error naming the output path usually points to the process user or directory permissions; a failure before the write may involve Chromium sandboxing, browser installation, version mismatch, or memory. Treat these as separate diagnostic branches.

1. Locate the failing step

Capture the complete error and the exact screenshot path. A filesystem permission error usually names a path or reports that access was denied. A browser launch error appears before Playwright can write the file. Playwright resolves relative screenshot filenames against the workspace root; if you omit a filename, the CLI or API may use an output directory depending on how you invoked it. Use an explicit absolute path while diagnosing. Playwright screenshot documentation

await page.screenshot({ path: '/out/example.png' });

Check where the process runs and where that path exists inside the container. A host path and its mounted container path are different names for the same mounted directory.

2. Inspect the effective user and output directory

Check the numeric user and group running Playwright, then inspect the output directory from inside the container. The process needs permission to create the file in the destination directory. For a bind mount, the container identity must also be compatible with the host directory’s ownership and permissions. Running as root in the container does not guarantee that files will have the ownership your host-side workflow expects.

id
printf 'HOME=%s\n' "$HOME"
ls -ld /out
ls -l /out

Confirm that the mount targets the directory your code actually uses. If the file is created in the container but is missing on the host, check the mount source and destination, then investigate ownership mapping and mount behavior. If the container cannot create the file, fix the writable directory or choose a permitted output location.

3. Check HOME and browser cache paths

A writable screenshot directory is not enough if setup or browser startup cannot write its caches or profiles. Check whether HOME points to a location writable by the effective container user. npm and browser tooling may write under HOME. Docker’s Playwright Hardened Images guide explicitly calls out both a writable mounted project/output directory and a writable HOME. Its example runs with the host uid/gid, mounts output at /out, sets HOME=/tmp, and writes a screenshot there. Adapt those paths and identity to the image and runtime you actually use. Docker Hardened Images Playwright guide

docker run --rm \
  --user "$(id -u):$(id -g)" \
  -e HOME=/tmp \
  -v "$PWD/output:/out" \
  YOUR_PLAYWRIGHT_IMAGE \
  node -e "const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({ path: '/out/example.png' }); await browser.close(); })();"

This is a diagnostic pattern, not a universal command: the image must include the matching Playwright package and browser, and its entrypoint and shell may require adjustments. Do not copy the uid/gid mechanically if your host, orchestrator, or image assigns users differently.

4. Separate Chromium sandbox errors from file permissions

Chromium’s sandbox is a browser security boundary; it does not grant permission to write a screenshot file. The official Playwright Docker image runs browsers as root by default, and Chromium’s sandbox is unavailable with root in that documented setup. For trusted end-to-end tests, the Playwright Docker documentation says root may be acceptable. For crawling or browsing untrusted pages, it recommends a separate user and a seccomp profile that permits the user-namespace operations Chromium needs. Follow the guidance for the image and runtime you use. Playwright Docker documentation

If Chromium fails at launch, inspect the launch error and container security settings; do not try to solve it by changing output-directory permissions. If the browser launches and the error names /out/example.png, investigate the file path, process identity, and mount permissions instead.

5. Align Playwright and browser versions

Use a pinned Playwright Docker image and the same Playwright version in the project or tests. A mismatch can prevent Playwright from locating the expected browser executable. Check the image tag, installed package version, and browser installation together. An executable-discovery or launch error is a browser setup issue, not evidence that the screenshot destination is unwritable. Playwright Docker documentation

6. Check shared memory and crashes

Chromium can run out of memory in Docker and crash. The Playwright Docker guide recommends --ipc=host for Chromium because limited shared memory can cause problems. A browser crash can interrupt a screenshot before any file is written, but it does not by itself show that the output directory has a permission problem. Consider the container’s memory and IPC settings when the browser exits or crashes without a path-specific write error. Playwright Docker documentation

7. Run a minimal screenshot check

Once the likely cause is fixed, reduce the reproduction to one page, one explicit output path, and one screenshot. Confirm both that the file exists at that path inside the container and that the host-side process can read it.

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await page.screenshot({ path: '/out/example.png' });
  } finally {
    await browser.close();
  }
})();

Run the script using the Playwright package and browser installed in your image. Check ls -l /out/example.png in the container, then check the corresponding host output directory. This distinguishes a failed write from an output that the host cannot access.

8. Choose a container setup that fits the target

Situation What to consider
Trusted end-to-end test targets The upstream Playwright image’s documented root default may be acceptable for this use, but ensure output and HOME paths work for the actual process.
Untrusted pages or crawling Use a separate user and suitable seccomp configuration so Chromium can use the required user namespaces; account for writable output and HOME.
Host needs to consume screenshots Match or deliberately map container uid/gid to host ownership expectations, and verify the bind mount.
Using a hardened Playwright image Check that image’s own user and filesystem assumptions. Docker’s Hardened Images guide describes its Playwright image as non-root by default (uid 65532); this differs from the upstream Playwright image’s root default.

These images do not share one universal user or filesystem layout. Use documentation for the exact image and version in your deployment. Docker Hardened Images guide

9. Troubleshooting common errors

Symptom Likely cause What to check or change
EACCES or permission denied naming the PNG path The process cannot create a file in the destination directory, or the mounted directory’s ownership/mode does not allow it. Check id, the path, ls -ld, and the mount. Use a writable output directory and an identity compatible with the mount.
Screenshot appears in the container but not on the host The output path is outside the mounted directory, the mount mapping is wrong, or host ownership prevents access. Verify the in-container destination and both mount paths; inspect ownership on the host.
Browser cannot create a profile or cache HOME or a related cache/profile location is not writable. Check HOME for the effective user and point it at a writable location supported by the image.
Chromium refuses to launch with root or sandbox-related error Root execution and Chromium sandbox restrictions are being conflated with screenshot file access. Follow the Playwright Docker security guidance for trusted versus untrusted targets; use a separate user and suitable seccomp setup for untrusted browsing.
Executable missing or browser version error Playwright package and image/browser versions are mismatched, or the browser is not installed in that image. Pin and align the image and package versions; verify the browser installation for that version.
Browser crashes without a path-specific error Shared-memory or other container resource constraints may be involved. Review memory/IPC configuration; Playwright recommends --ipc=host for Chromium in Docker.

10. Performance, reliability, and cost considerations

Permission checks are usually cheap compared with starting a browser and loading a page. Keep the diagnostic run small so that a slow or crashing browser does not obscure a path problem. For recurring jobs, pin image and Playwright versions, use an explicit mounted output path, decide deliberately which user runs the process, and verify that both output and HOME remain writable after deployment changes. These steps reduce environment drift; they do not guarantee that a target site or container will always load successfully.

Writing screenshots to a bind mount avoids a separate copy step when another host process needs the result, but ownership mapping can require care. Running as root may simplify some writes while affecting host-side ownership and reducing browser isolation; for untrusted targets, follow the separate-user and sandbox guidance. No failure-rate or speed benchmark is established by the cited documentation, so measure your own workload if throughput or resource sizing matters.

Or skip the browser setup

If the job is simply to capture a page, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. One GET request returns a PNG, JPEG, WebP, or PDF, without installing Chromium or arranging a writable browser profile in your container. See the API documentation.

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

ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

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

FAQ

Does a screenshot permission error mean Chromium’s sandbox is disabled?

No. A path-specific write denial points to filesystem access. Sandbox configuration affects browser launch and isolation; diagnose it separately.

Why can the container create a screenshot that I cannot open on the host?

The bind mount may expose a file owned by a container uid/gid the host workflow cannot read, or the screenshot may have been saved outside the mounted directory. Check both the path mapping and ownership.

Should I always run Playwright as root in Docker?

No. The upstream image’s documented default is root, but untrusted browsing calls for a separate user and suitable sandbox configuration. Other Playwright images can have different defaults.

Can I fix every Chromium crash by changing directory permissions?

No. A browser crash may involve version alignment, shared memory, or other resource constraints. Use the error and failure stage to choose the diagnostic branch.