ScreenshotNeo

BlogHow-to

How to Install Headless Chrome on Ubuntu 24

Install Google Chrome on Ubuntu 24, run it in current Headless mode, capture screenshots or PDFs, and fix common setup errors.

By the ScreenshotNeo team1 October 20266 min read

Direct answer: install the regular Google Chrome Stable package from Google’s APT repository, then launch that binary with --headless. Headless Chrome is a mode of the normal browser, not a separate package. The commands below install Chrome on Ubuntu 24, verify the executable, and show screenshot, DOM, and PDF jobs.

1. Check your Ubuntu 24 system

Confirm the operating system and CPU architecture before adding the repository:

cat /etc/os-release
uname -m

Google’s documented repository example uses arch=amd64. On an ARM machine, that exact repository entry may not be appropriate; use a Chrome build and installation path that supports your architecture.

2. Install Google Chrome Stable

Google’s Linux installation example imports Google’s signing key, registers the Stable repository, refreshes APT metadata, and installs google-chrome-stable. Run:

curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/googlechrom-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrom-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list
sudo apt update
sudo apt install -y google-chrome-stable

These steps are from Google’s documented Linux/Colab installation example. The repository line is specifically written for amd64 and does not prove that every Ubuntu derivative, architecture, container, or GPU setup has identical dependencies.

3. Verify the installation

Check that the package and executable are available:

google-chrome-stable --version
command -v google-chrome-stable
apt policy google-chrome-stable

Some systems also provide the shorter google-chrome command. Use the name that exists on your machine consistently:

command -v google-chrome || true

4. Start Chrome in Headless mode

Launch the installed browser without a visible window:

google-chrome-stable --headless

Current Headless mode is unified with regular Chrome. Since Chrome 112, Chrome creates platform windows without displaying them while retaining normal browser functionality. Since Chrome 132.0.6793.0, the older implementation is distributed separately as chrome-headless-shell. See Google’s Chrome Headless mode documentation for the implementation history.

5. Run useful Headless commands

--dump-dom prints the serialized DOM after Chrome parses the page and runs its scripts. This is different from downloading raw HTML with curl.

google-chrome-stable --headless --dump-dom https://example.com

Capture a screenshot

Chrome writes screenshot.png in the current directory by default. Set the viewport with --window-size=WIDTH,HEIGHT:

google-chrome-stable --headless --screenshot --window-size=1280,900 https://example.com
google-chrome-stable --headless --print-to-pdf=page.pdf https://example.com

For a long-running page, limit waiting time or allow timer-driven code to advance:

google-chrome-stable --headless --timeout=30000 --screenshot https://example.com
google-chrome-stable --headless --virtual-time-budget=5000 --dump-dom https://example.com

These capture flags and timing options are documented in the Chrome command-line reference.

6. Make captures repeatable

  • Use an absolute output path in automation so the working directory cannot change the destination.
  • Set a fixed viewport with --window-size when comparing images.
  • Use --virtual-time-budget for pages whose content appears after JavaScript timers.
  • Use --timeout to prevent a broken page from holding a job forever.
  • Run each job in a writable temporary directory and copy successful artifacts to permanent storage.
tmp_dir=$(mktemp -d)
cd "$tmp_dir"
google-chrome-stable --headless --timeout=30000 --window-size=1440,900 --screenshot=https://example.com
ls -lh screenshot.png

7. Security and sandbox considerations

Do not add --no-sandbox as a routine installation step. It disables Chrome’s security sandbox. Google’s Colab GPU example uses it for that specialized environment, but the example does not establish that ordinary Ubuntu desktop or server installations require it.

Prefer running Chrome as an unprivileged user with its sandbox enabled. If an isolated container forces you to investigate --no-sandbox, treat that as a deployment security decision: restrict the container, reduce network and filesystem access, and document why the flag is present.

8. Current Headless Chrome versus chrome-headless-shell

Choice Use it when Installation path
Regular Chrome with --headless You need current Chrome behavior and broad browser feature coverage. Google Chrome Stable APT package shown above.
chrome-headless-shell A task specifically requires the older lightweight shell implementation. Chrome for Testing distribution; Google’s legacy documentation shows npx @puppeteer/browsers install chrome-headless-shell@stable.

The shell is a separate binary, not another flag for the Stable package. Read the Headless Chrome shell documentation before choosing it.

9. Troubleshooting

Symptom Likely cause Fix
google-chrome-stable: command not found The package was not installed or the executable name differs. Run sudo apt update && sudo apt install -y google-chrome-stable, then check command -v google-chrome-stable and command -v google-chrome.
APT reports a missing or invalid signature The keyring file or repository entry is incorrect. Recreate /usr/share/keyrings/googlechrom-keyring.gpg with the documented key command, verify the signed-by path, and run sudo apt update again.
APT cannot find google-chrome-stable The repository was not written, metadata is stale, or the architecture does not match. Inspect /etc/apt/sources.list.d/google-chrome.list, run sudo apt update, and confirm uname -m is compatible with the amd64 entry.
Chrome exits immediately in a service The process has no usable home, temporary directory, display environment, or sandbox permissions. Run as a real unprivileged user, provide a writable temporary directory, and use Headless mode. Do not jump directly to --no-sandbox.
Screenshot is blank or incomplete The page needs time for scripts, lazy images, fonts, or network requests. Increase --timeout, add a suitable --virtual-time-budget, and confirm the URL is reachable from the server.
Only the first viewport appears Regular screenshots capture the configured viewport. Set a larger --window-size, or use browser automation that scrolls and stitches the page when a full-page image is required.
chrome:// URL is denied Chrome 123 added a permission requirement for Headless access to Chrome scheme URLs. Add --allow-chrome-scheme-url only for the specific diagnostic job that needs it.
Fonts or images differ from a desktop capture The server has different fonts, device scale, viewport, locale, or network timing. Install required fonts, fix the viewport and locale, wait for page readiness, and keep the capture environment consistent.

10. Performance and reliability notes

  • Starting a fresh Chrome process for every URL is simple but adds startup cost. A browser automation runner that reuses a controlled browser can reduce startup overhead.
  • Limit concurrency to the CPU and memory available. Each page can consume substantial memory, especially with large images, video, advertisements, and complex JavaScript.
  • Set explicit timeouts and collect exit codes. A command that returns an image file is not automatically proof that every page element finished loading.
  • Keep temporary profiles isolated between jobs when pages may write cookies, local storage, or service-worker data.
  • Cache stable assets and avoid unnecessary third-party requests where your capture policy permits it, but remember that blocking resources can change the rendered result.
  • For production capture, record the Chrome version, viewport, URL, timestamp, exit status, and output checksum so a later comparison has context.

11. Cost and operations

Running Chrome yourself has no per-screenshot API charge, but you pay in server CPU, memory, storage, maintenance, browser upgrades, fonts, network egress, retries, and monitoring. The right choice depends on volume and how much browser infrastructure you want to operate.

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server. One request returns a PNG, JPEG, WebP, or PDF, so you do not need to install or maintain Chrome on your Ubuntu host. See the ScreenshotNeo 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}`);

Before capture, ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

The Free plan includes 1,000 screenshots each month with no card. Paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account.

FAQ

Is there a separate Google Chrome Headless package for Ubuntu?

No. The normal Chrome binary enters Headless mode when launched with --headless. The separate chrome-headless-shell binary is the older implementation distributed through Chrome for Testing.

Can I use Headless Chrome without Node.js or Puppeteer?

Yes. The command-line flags work directly from a shell script. Add Node.js or Puppeteer only when your workflow needs programmatic browser control beyond the built-in CLI operations.

Why does --dump-dom differ from curl?

Chrome parses the document and runs page scripts before serializing the DOM. curl normally returns the HTTP response body without rendering it.

When should I use chrome-headless-shell?

Use it when a workflow specifically calls for the older lightweight shell. For normal automation and current Chrome behavior, use the regular Stable binary with --headless.