What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To capture website screenshots with Puppeteer in Docker, install puppeteer in your Node.js project, let its install step download a compatible Chrome for Testing browser, add the Linux libraries that browser needs, and run Chrome as a non-root user with writable profile and output paths. Then launch the browser, navigate to the page, and call page.screenshot(). The guide below builds that setup and covers the common container failures.

Choose how Puppeteer will get its browser

For most applications, use puppeteer. Its install process normally downloads a compatible Chrome for Testing browser and, for Puppeteer versions starting with v21.6.0, a chrome-headless-shell binary. The browser files are stored in $HOME/.cache/puppeteer by default, as documented since Puppeteer v19.0.0. Puppeteer’s installation documentation estimates the Linux browser download at approximately 282 MB; that is a browser-download estimate, not a guaranteed increase of exactly that amount in a Docker image layer.

Choose puppeteer-core when you deliberately manage the browser yourself or connect to a remote browser. It does not download Chrome. For a local managed browser, configure its executablePath or channel when launching Puppeteer, and keep the browser and Puppeteer versions compatible.

Install the project dependency

In your Node.js project, install Puppeteer and preserve the generated or existing lockfile so Docker can install the same dependency resolution on later builds:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
npm install puppeteer

Some package managers block dependency install scripts. If Puppeteer’s install script is blocked, its browser download may be skipped and launch can fail because Chrome is missing. Allow the Puppeteer install script in your package manager’s configuration, or explicitly install the browser during the image build with npx puppeteer browsers install.

Use the official container or build your own

Puppeteer publishes a Docker image through GitHub Container Registry. Its tag changes over time, so check the current registry listing and deliberately select a versioned tag rather than assuming an observed tag will remain current. The project’s Dockerfile is also a useful reference for custom images. At the time the current project Dockerfile was reviewed, it used a Node 24 Bookworm base pinned by digest, installed fonts and DBus packages, created a pptruser account, installed browser dependencies, and switched back to the unprivileged user after setup. Those are project-specific practices, not a universal minimal package list.

A custom image gives you control over the Node base, operating-system libraries, fonts, and browser update cadence. Pin the base image and application dependencies to make builds more reproducible, and review Puppeteer’s current Docker documentation when changing the browser or Linux distribution.

Build a custom Docker image

The example below assumes your project has a package.json and lockfile in its root, plus an application file named app.js. It uses Debian Bookworm, installs a starting set of browser libraries, installs the locked npm dependencies, and runs the application as a dedicated non-root account. Browser dependencies differ by browser version and base distribution; if Chrome reports another missing library, add the matching package for your chosen distribution using Puppeteer’s current Docker guidance or official project Dockerfile as a reference.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
FROM node:24-bookworm-slim

ENV XDG_CONFIG_HOME=/tmp/.chromium
ENV XDG_CACHE_HOME=/tmp/.cache

RUN apt-get update && apt-get install -y --no-install-recommends 
    ca-certificates 
    fonts-liberation 
    libasound2 
    libatk-bridge2.0-0 
    libatk1.0-0 
    libcups2 
    libdbus-1-3 
    libdrm2 
    libgbm1 
    libgtk-3-0 
    libnspr4 
    libnss3 
    libx11-6 
    libx11-xcb1 
    libxcb1 
    libxcomposite1 
    libxdamage1 
    libxext6 
    libxfixes3 
    libxrandr2 
    libxshmfence1 
    libxss1 
    libxtst6 
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

COPY app.js ./
RUN useradd --create-home --uid 10001 appuser 
    && mkdir -p /output /tmp/.chromium /tmp/.cache 
    && chown -R appuser:appuser /app /output /tmp/.chromium /tmp/.cache

USER appuser
CMD ["node", "app.js"]

The package list is an example starting point, not a guarantee that every Puppeteer and Bookworm combination needs exactly those libraries. A browser launch error that names a missing shared library means the selected image needs that library or a compatible package. Add fonts for the languages and scripts you need to render; without appropriate fonts, a screenshot may load successfully but show missing glyphs or fallback typography.

If your project uses a different entry point or additional application files, copy them into the image and adjust the command. For package managers that suppress Puppeteer’s install script, add the explicit browser-install command after dependency installation, for example RUN npx puppeteer browsers install, and verify the browser cache is available to the runtime user.

Keep browser files and permissions aligned

  • Install browser dependencies as root during the image build, then run the app and Chrome under an unprivileged user.
  • Ensure the runtime user can read the Puppeteer browser cache and can write to its profile, configuration, cache, and screenshot output directories.
  • Keep browser and Puppeteer versions compatible. If you install Chromium or Chrome separately, configure Puppeteer with the matching executable path or channel.
  • Use an OS base with supported browser dependencies. Puppeteer’s documentation says Chrome does not support Alpine out of the box; if you choose Alpine, verify its compatible dependencies and align Chromium and Puppeteer versions rather than assuming a Debian recipe will work.

Write a screenshot script and run it in Docker

This runnable example accepts a target URL as its first command-line argument and saves a full-page PNG under /output. It sets a viewport, waits for the navigation event, and closes the browser in a finally block even if navigation or screenshot capture fails. Page readiness is site-specific: if the page renders content after navigation, add an appropriate selector wait or delay for that site instead of assuming one wait condition works for all pages.

const puppeteer = require('puppeteer');

async function main() {
  const targetUrl = process.argv[2];
  if (!targetUrl) {
    throw new Error('Usage: node app.js https://example.com');
  }

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

  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1440, height: 900 });
    await page.goto(targetUrl, {
      waitUntil: 'networkidle2',
      timeout: 60000,
    });
    await page.screenshot({
      path: '/output/page.png',
      fullPage: true,
    });
    console.log('Saved /output/page.png');
  } finally {
    await browser.close();
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Build the image from the directory containing the Dockerfile, package.json, package-lock.json, and app.js:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
docker build -t puppeteer-shot .

Run it with Docker’s init process and mount a host directory for the screenshot:

mkdir -p output
docker run --rm --init 
  -v "$PWD/output:/output" 
  puppeteer-shot https://example.com

The file should appear as output/page.png on the host. Without the bind mount, a file written to /output/page.png exists only in the container filesystem and is lost when a disposable container is removed. The mounted host directory must be writable by the container user; adjust ownership or permissions if the process cannot create the file.

Choose screenshot options for the page

page.screenshot() returns image bytes (a Uint8Array) or a base64 string when requested. Supplying path writes the result to disk; a relative path resolves from the current working directory. If you omit path, Puppeteer returns the image data rather than saving a file automatically.

Need Option or approach What to know
Whole page rather than viewport fullPage: true The default is false, which captures the viewport.
A region of the page clip Specify the capture rectangle for the desired area.
PNG output type: 'png' or a .png path PNG is the default format.
JPEG or WebP output type: 'jpeg' or 'webp', or a matching path extension Set quality from 0 to 100 for formats where quality applies. Quality does not apply to PNG.
Transparent background omitBackground: true Hides the default white background where the page output supports transparency.

For example, capture a clipped region as a JPEG by passing a clip rectangle and format in the screenshot options. Choose viewport dimensions before capture; a full-page capture changes the captured page area, not the viewport used while the page lays out.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Configure the container for reliability and security

Run without relying on --no-sandbox

Run Chrome as a non-root user and configure the container runtime appropriately. Puppeteer’s Docker troubleshooting example uses a non-privileged pptruser so that setup does not need --no-sandbox. Avoid treating --no-sandbox as a default fix: it weakens browser isolation, and the right configuration depends on the host and container runtime. If Chrome refuses to start, investigate user privileges and runtime restrictions before disabling the sandbox.

Support writable and read-only environments

Chrome writes profile, configuration, and cache data. In a read-only or restricted container, provide writable paths. Puppeteer documents setting XDG_CONFIG_HOME and XDG_CACHE_HOME to writable locations such as paths under /tmp, and setting the launch option userDataDir to a writable profile directory. Alternatively, mount writable volumes owned by the runtime user. The screenshot destination must also be writable, or return the screenshot bytes from your application rather than writing to a protected path.

Reap browser processes

Use Docker’s --init option where available. Puppeteer’s troubleshooting guidance recommends it to help reap child processes and avoid zombie processes. The example docker run command above includes --init.

Balance image size, reproducibility, and updates

The browser download is a substantial part of the image build, and the documented Linux download estimate is approximately 282 MB. Cache Docker build layers by copying package manifests before application files, as the Dockerfile does, so source edits do not automatically require reinstalling dependencies. Pin the Node base image and lockfile for repeatable builds, but plan to rebuild and update the browser and its dependencies deliberately. A pinned image is reproducible; it is not automatically current or secure forever.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Docker Container Linux Devops Programming Coding T-Shirt
  • Docker, Docker Swarm, Docker Compose, Programmer, Developer, Coding, Programming, Software Engineer, Code, DevOps, Deploy, Deployment, Kubernetes, Salt, Puppet, Chef, Terraform, Container, AWS, Azure, Cloud, Geek, Funny, Computer, Software, Tech, IT
  • Integration, Scrum, Compile, Compilation, Science, Bug, Debug, Python, Linux, Java, Javascript, Scala, Dotnet, Kotlin
  • Lightweight, Classic fit, Double-needle sleeve and bottom hem
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot the common Docker failures

Symptom Likely cause Fix
“Could not find Chrome” or missing browser at launch A package manager blocked Puppeteer’s install script, or the browser was not installed in the image. Allow the Puppeteer install script during build or run npx puppeteer browsers install explicitly. Confirm the browser cache path is accessible to the runtime user.
Chrome fails to launch and names a missing .so library The base image lacks a shared library required by the selected browser. Install the matching library package for that Linux distribution. Use current Puppeteer Docker guidance or its project Dockerfile as a starting point; old package lists can become incomplete.
Browser says it cannot create a profile or cache The configured home, cache, configuration, or profile path is not writable. Set XDG_CONFIG_HOME, XDG_CACHE_HOME, and, if needed, Puppeteer’s userDataDir to writable locations. Ensure the runtime user owns or can write to them.
Screenshot exists in the container but not on the host The screenshot path is in the container’s filesystem and was not mounted or copied out. Bind-mount an output directory, copy the file before container removal, or have the application return the screenshot bytes.
Container exits but browser child processes linger Child processes may not be reaped by the container process setup. Run the container with --init where available.
Chrome fails or behaves inconsistently on Alpine Chrome is not supported on Alpine out of the box, and the assumed libraries or Chromium/Puppeteer versions may not match. Use a supported base with the appropriate browser dependencies, or verify Alpine compatibility and align the browser and Puppeteer versions explicitly.
Screenshot is blank, incomplete, or missing late-loading content The page may not be ready when the screenshot is taken, or its content depends on viewport, authentication, or application-specific state. Set the needed viewport and credentials, then wait for a meaningful page selector or site-specific readiness condition. There is no single navigation wait setting established for every page.
Text appears with missing glyphs or unexpected fallback fonts The image lacks fonts required by the rendered languages or page design. Install suitable fonts in the image and rebuild it.

Or skip the browser setup

If you need a screenshot API rather than a browser container to maintain, ScreenshotNeo returns a screenshot or PDF from one GET request. Cookie and consent banners are accepted before capture, and more than 60 known consent platforms, newsletter popups, and chat widgets can be removed; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with response headers indicating the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

Here is a cURL call that writes a WebP screenshot:

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

See the ScreenshotNeo API documentation for request options. The service also offers 1,000 screenshots per month free with no card, and paid plans start at $5 for 3,000 screenshots. Sign up for the free plan.

When should you use Docker Puppeteer?

A Puppeteer container is a good fit when you need browser-level control over a site, want to run screenshot capture alongside a Node.js application, or need to customize browser setup, viewport, fonts, and page readiness. It also means you own the browser binary, operating-system dependencies, writable runtime paths, image rebuilds, and capture error handling. If those responsibilities are appropriate for your workflow, the combination of a locked dependency, compatible browser, non-root runtime, explicit output mount, and application-specific readiness logic is a sound starting point.

Frequently Asked Questions

Does Puppeteer work in Docker?

Yes. The container must include a compatible browser and its required Linux libraries, and the runtime must provide writable browser and output paths.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should I install puppeteer or puppeteer-core?

Use puppeteer for the usual bundled-browser setup. Use puppeteer-core when you manage the browser separately or connect to a remote browser.

Can I use Puppeteer with Alpine Linux?

Chrome does not support Alpine out of the box according to Puppeteer’s documentation; verify compatible dependencies and browser versions before choosing Alpine.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.