sodcalculator

10 Tech How-To

Consistent Chrome Headless Screenshots on Linux & Windows

Guide 10-31080 · Updated · Step by step

Getting pixel-identical screenshots from Chrome headless across Linux and Windows is tricky because font rendering, DPI scaling, and Chrome’s own defaults differ per OS. This guide gives you a repeatable setup — a set of flags, a fixed viewport, and a consistent environment — so the same command produces the same PNG on both systems.

What You’ll Need

  • Chrome or Chromium installed on both machines (any recent stable version).
  • Command-line access (Terminal on Linux, Command Prompt or PowerShell on Windows).
  • Basic familiarity with running commands and editing a small script.
  • Optional: a tool like pngcheck or ImageMagick to verify output dimensions.

Step-by-Step

  1. Install the same Chrome version on both systems.
    Version differences cause rendering changes. Use the same major version (e.g., both on Chrome 120) and ideally the same minor build. On Linux, you can pin a version via apt or download the exact .deb; on Windows, use the offline installer for a specific version.
  2. Set a fixed viewport size with --window-size.
    Chrome’s default window size differs by OS. Always pass --window-size=1280,720 (or your desired size) to both. This includes the browser chrome, so add --hide-scrollbars to avoid scrollbar width differences.
  3. Disable GPU and hardware acceleration.
    Use --disable-gpu on both. On Windows, also add --disable-software-rasterizer to prevent fallback rendering differences.
  4. Force a consistent device scale factor.
    Windows may apply DPI scaling (e.g., 125% or 150%). Add --force-device-scale-factor=1 to both systems to ensure a 1:1 pixel mapping.
  5. Use the same font rendering settings.
    Linux uses fontconfig, Windows uses ClearType. To minimize differences, add --font-render-hinting=none and --disable-lcd-text on both. This makes text rendering closer, though not always identical.
  6. Set a common user agent and platform.
    Websites may serve different CSS or images based on OS. Use --user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" on both to emulate the same platform.
  7. Disable features that cause variability.
    Add --disable-extensions, --disable-default-apps, --disable-sync, and --no-first-run. These prevent popups, sync changes, and first-run dialogs from altering the page.
  8. Use the same screenshot command.
    On both systems, run:
    chrome --headless --disable-gpu --hide-scrollbars --force-device-scale-factor=1 --window-size=1280,720 --screenshot=output.png "https://example.com"

    Adjust the path to your Chrome executable (e.g., chrome on Linux, "C:\Program Files\Google\Chrome\Application\chrome.exe" on Windows).

  9. Wait for the page to fully load.
    Headless Chrome captures the screenshot as soon as the page load event fires, but images and fonts may still be loading. Use the --virtual-time-budget=5000 flag to give the page 5 seconds of virtual time to settle. This is crucial for consistent results.
  10. Verify the output.
    Check the file size and dimensions on both systems. They should be identical (or very close). Use file output.png on Linux or identify output.png (ImageMagick) on Windows to confirm dimensions.

Common Mistakes

  • Forgetting to set the same Chrome version. A patch update can change rendering.
  • Not using --hide-scrollbars. Windows scrollbars are always visible, Linux overlay scrollbars are not, causing width differences.
  • Using different viewport sizes. Even a 1-pixel difference shifts layout.
  • Ignoring DPI scaling on Windows. Without --force-device-scale-factor=1, a 125% scaling yields a 1600×900 screenshot instead of 1280×720.
  • Not waiting for fonts and images. Screenshots taken too early will have missing or fallback fonts.

Tips

  • Use a shared script. Write a small shell/batch script that contains the full command and use it on both machines to avoid typos.
  • Test with a simple page first. Create a local HTML file with known text and colors to verify consistency before testing complex sites.
  • Consider using Docker. Running Chrome headless in a Docker container (e.g., chromium image) on both systems gives near-perfect consistency, as the environment is identical.
  • Use --disable-features=CalculateNativeWinOcclusion on Windows. This prevents Windows-specific occlusion from affecting rendering.
  • If you need pixel-perfect, use a virtual machine. Even with all flags, minor font differences may persist. A Linux VM on Windows or vice versa can eliminate them.

Troubleshooting

  • Screenshots are different sizes. Check that --window-size and --force-device-scale-factor=1 are present. Also, remove any --headless=new or --headless=old variations; use plain --headless.
  • Text looks blurry on one system. Ensure --font-render-hinting=none and --disable-lcd-text are used on both. If still blurry, try --disable-font-subpixel-positioning.
  • Page loads differently (e.g., cookie banners). Use --disable-cookie-encryption? No, that’s not a real flag. Instead, use --user-data-dir to a fresh temp folder on both systems to ensure no saved preferences or cookies.
  • Screenshot is blank or white. The page may be blocking headless. Try adding --disable-blink-features=AutomationControlled to make Chrome appear less automated.
  • Chrome won’t start on Linux as root. Add --no-sandbox (only in a controlled environment) or run as a non-root user.
  • Images or fonts missing. Increase --virtual-time-budget to 10000 or more. Also check that the site doesn’t block based on user agent; your custom user agent should fix that.

Frequently Asked Questions

Why do my screenshots still differ slightly even with all flags?

Font rendering engines (fontconfig vs. ClearType) and subpixel positioning can cause sub-pixel differences. Using a Docker container is the most reliable way to achieve pixel-identical results.

Can I use Puppeteer or Selenium instead of command-line flags?

Yes, but you still need to set the same viewport, device scale factor, and user agent in your automation code. The flags in this guide are the underlying settings those tools use.

Does Chrome version really matter that much?

Yes. Chrome updates frequently change rendering, CSS support, and even default fonts. Using the same major version is essential; ideally, pin the exact build.

What if I need a full-page screenshot?

Full-page screenshots are harder to make consistent because the page height can vary. Use --screenshot with a fixed viewport for consistency; for full-page, you’ll need a tool like Puppeteer with a fixed width and capture beyond the viewport.

Is it better to use Chrome or Chromium?

Chromium is more minimal and may have fewer OS-specific integrations, but Chrome is fine. The key is to use the same binary on both systems.

Can I automate this for many URLs?

Yes, write a loop in your script that iterates over URLs, calling the same Chrome command each time. Ensure the output filenames are unique per URL.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →