ScreenshotNeo

BlogHow-to

How to Run Puppeteer on Google Cloud Compute Engine

Create a Linux VM, install Puppeteer and Chrome, and run a secure screenshot script on Google Cloud Compute Engine. Includes fixes for common launch failures.

By the ScreenshotNeo team4 October 20268 min read

To run Puppeteer on a Google Cloud Compute Engine VM, create a Linux VM, install a supported Node.js version and Puppeteer, then run your script as a non-root user with Chrome’s sandbox enabled. The simplest setup uses the puppeteer package, which downloads a compatible Chrome for Testing browser during installation. This guide uses Ubuntu 24.04 LTS as one documented option; check the current requirements for your chosen operating system and architecture.

Puppeteer currently requires Node.js 22.12 or newer. Its Chrome for Testing requirements list Debian and Ubuntu on x64 and arm64. Confirm the current Puppeteer system requirements before creating a VM.

1. Create and connect to a Compute Engine VM

  1. Choose or create a Google Cloud project.
  2. Enable the Compute Engine API for the project.
  3. Create a Linux VM. Ubuntu 24.04 LTS is one option in Google Cloud’s Linux VM creation guide.
  4. Choose an architecture supported by the browser and operating system you plan to use. For Puppeteer’s Chrome for Testing, Debian and Ubuntu x64 and arm64 are listed in its system requirements.
  5. Connect using the SSH button in the VM list, or follow Google Cloud’s VM access guidance.

There is no universally correct machine size for browser automation. Page complexity, number of simultaneous browser instances, memory use, and runtime determine what your workload needs. Start with a modest configuration, measure it with representative pages, and adjust based on observed resource use.

2. Install Node.js and Puppeteer

Install Node.js 22.12 or newer using a method appropriate for your VM and organization. Verify the active versions:

node --version
npm --version

Then create a project and install Puppeteer:

mkdir -p ~/puppeteer-vm
cd ~/puppeteer-vm
npm init -y
npm install puppeteer

The puppeteer package normally downloads a compatible Chrome for Testing browser (and, in current installations, a chrome-headless-shell) as part of installation. The browser cache defaults to $HOME/.cache/puppeteer. The installing user and runtime user must be able to access the same browser installation and cache. If your package manager blocks install scripts, the browser download may be skipped and launching Puppeteer later can fail with “Could not find Chrome.” See the Puppeteer installation guide for current install behavior and configuration.

When to use puppeteer-core

Use puppeteer when you want the package to manage a compatible browser download. Use puppeteer-core when your environment already manages Chrome or Chromium and you need to supply its executable path yourself. With puppeteer-core, you own browser installation, updates, compatibility, and the runtime libraries Chrome needs. The Puppeteer documentation describes both package options.

3. Create and run a screenshot script

Save this as screenshot.js in the project directory. It launches Chrome in headless mode, visits a page, saves a full-page PNG, and closes the browser even if navigation or capture fails.

const puppeteer = require('puppeteer');

async function main() {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1440, height: 900 });
    await page.goto('https://example.com', {
      waitUntil: 'networkidle2',
      timeout: 60_000,
    });
    await page.screenshot({ path: 'screenshot.png', fullPage: true });
  } finally {
    await browser.close();
  }
}

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

Run it with:

node screenshot.js

Use waitUntil: 'load' when waiting for network quiet would take too long or never happen. Use domcontentloaded when the document structure is enough to begin your own readiness checks. Sites with client-rendered content may need a selector wait after navigation:

await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('main', { timeout: 15_000 });

Choose readiness behavior based on the page. Persistent analytics, polling, and streaming connections can prevent network-idle conditions from occurring. A navigation timeout also does not always mean the page is unusable: if your workflow can tolerate partial content, catch the navigation timeout and inspect the page before deciding whether to continue.

4. Keep the VM and browser workload secure

Keep Chrome’s sandbox enabled

Run the script as a regular Linux user and use Puppeteer’s default launch configuration. Avoid running Chrome as root. Do not add --no-sandbox as a routine fix: Puppeteer’s troubleshooting guide says that option is appropriate only when the opened content is absolutely trusted. Pages supplied by users or otherwise untrusted make sandboxing especially important. See Puppeteer’s troubleshooting guidance.

Restrict SSH access

Review the VM’s network rules and access method. Google warns that a default SSH rule can expose port 22 to the internet, allowing connection attempts from any network. Restrict SSH ingress to trusted networks or use suitable managed access controls, and consider OS Login, which Google recommends for most Linux VM user-access scenarios. See Google’s SSH network access best practices.

Give cloud workloads only the access they need

If the script calls Google Cloud APIs, attach a user-managed service account with only the IAM roles the workload needs, and configure the cloud-platform scope as appropriate. Google documents this in its guide to creating a VM that uses a user-managed service account. Treat the VM identity as a security boundary: users who can connect to a VM may be able to act with permissions from its attached service account.

5. Troubleshoot common launch and capture failures

Symptom Likely cause What to check or fix
“Could not find Chrome” or browser executable missing The install script did not download the browser, or the runtime user cannot see the install-time cache. Reinstall with install scripts permitted, verify that a compatible browser was downloaded, and make the installing and runtime users’ browser cache paths consistent. Check Puppeteer’s installation guide for cache configuration.
Chrome exits immediately or reports missing shared libraries A Linux runtime dependency is absent. Find the Chrome executable and run ldd /path/to/chrome | grep not. Install the missing libraries using package names for the VM’s distribution and release. Consult the current Puppeteer Linux troubleshooting instructions; package names can vary by distribution.
“Running as root without –no-sandbox is not supported” The process is running as root while Chrome’s sandbox is enabled. Run the job as a non-privileged user. Keep the sandbox enabled for untrusted content; only consider disabling it when the content is absolutely trusted and the security tradeoff is acceptable.
Navigation times out on a page that appears partly loaded The selected navigation condition takes too long, or the site keeps network requests open. Try domcontentloaded or load and wait for a specific content selector. Set a timeout appropriate to the page and handle timeout errors deliberately.
Script works over SSH but fails under a service or scheduler The job runs as a different user or with a different environment, working directory, or cache path. Run the job with the intended user, use an explicit project working directory, and confirm that this account can access the installed browser and write output files.
Browser starts but a page or image is blank The page may need more time or a readiness condition; the target may also have returned a bot check or an error page. Inspect the page URL, title, and content before capture. Wait for the relevant selector, and log navigation errors and response details so your job can distinguish an application error from a successful capture.
Out-of-memory termination or unstable concurrent jobs The VM is running more browser work than its available memory can support. Reduce simultaneous browser instances, close pages and browsers in cleanup paths, and measure representative workloads before changing VM size.

For missing library diagnosis, run ldd against the actual Chrome executable installed by Puppeteer, not an assumed system path. Install the distribution-appropriate dependencies listed by the current troubleshooting guide; old package names may not apply to a newer OS release.

6. Make runs more reliable and manage cost

  • Always close browsers. Use try/finally so failed navigation and screenshot calls do not leave Chrome processes running.
  • Set explicit timeouts. Bound navigation and selector waits so a single slow page cannot hold a job indefinitely.
  • Control concurrency. Each browser process and page consumes resources. Increase parallelism only after observing memory and runtime under representative pages.
  • Plan browser updates. With puppeteer, reinstalling can bring a compatible browser download; with puppeteer-core, browser lifecycle and compatibility are your responsibility.
  • Watch disk and cache ownership. Browser downloads use disk space, and the default cache belongs under the installing user’s home directory.
  • Budget for the VM lifecycle. Compute Engine resources can continue to incur charges while provisioned. Delete the VM when it is no longer needed, following Google’s VM cleanup guidance.

There is no workload-independent machine size, throughput figure, or price estimate in the cited setup guidance. Measure your own page mix, concurrency, memory use, and run duration, then choose a VM configuration and lifecycle that fit the job.

Or skip the browser setup

If you only need website screenshots, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. One GET request returns a PNG, JPEG, WebP, or PDF. It can accept cookie and consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers.

For a screenshot, make this request with your API key:

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. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots, and every feature is on every plan.

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

FAQ

Can I use Puppeteer on an ARM Compute Engine VM?

Puppeteer’s current Chrome for Testing requirements list Debian and Ubuntu on arm64 as well as x64. Match the VM architecture and OS to those requirements and verify the current browser support before deployment.

Do I need a desktop environment on the VM?

This guide runs Puppeteer in its default headless mode, so it does not require a visible desktop for the screenshot script shown here.

Should I install Chrome separately?

Usually not with puppeteer, which downloads a compatible Chrome for Testing browser. Install and manage a browser separately when you choose puppeteer-core or have an environment-specific browser lifecycle.

Where does Puppeteer store its downloaded browser?

The default browser cache is $HOME/.cache/puppeteer. The account running the script must be able to access the browser installed there, or you must configure a consistent cache location.