ScreenshotNeo

BlogHow-to

Puppeteer Screenshots on a Raspberry Pi in India: Chromium Setup

Use Puppeteer with Chromium on Raspberry Pi OS by checking your architecture, installing or selecting a compatible browser, and verifying its dependencies.

By the ScreenshotNeo team4 October 202610 min read

To take a screenshot with Puppeteer on a Raspberry Pi, first identify the Pi’s model, Raspberry Pi OS release, and whether the OS is 32-bit or 64-bit. Then either install a compatible Puppeteer-managed browser or use Raspberry Pi OS’s Chromium package, find its actual executable path, and pass that path as executablePath when launching Puppeteer. Do not assume a browser path or x64 download from another machine will work on your Pi.

The core screenshot call is await page.screenshot({ path: 'screenshot.png', fullPage: true }). The setup around that call depends on the browser and OS image. Raspberry Pi’s documentation identifies Chromium as the default browser in new Raspberry Pi OS installations, but the exact executable path and compatibility still need to be checked on the image you are using. The technical setup is the same in India; the sources consulted do not document an India-specific software difference.

1. Check your Pi, OS, and Node.js

Run these commands on the Raspberry Pi, or in the same environment where the screenshot script will run:

uname -m
cat /etc/os-release
node --version
npm --version

uname -m commonly reports aarch64 for 64-bit Arm or armv7l for a 32-bit Arm userland. Check the OS release as well: the architecture of the OS userspace determines which packages and browser binaries can run. Do not treat a 64-bit capable Pi processor as proof that the installed OS is 64-bit.

Current Puppeteer system requirements list Node.js 22.12 or later and Chrome for Testing on Debian/Ubuntu Linux x64 and arm64. That does not certify every Raspberry Pi OS release, older 32-bit image, or Pi model/browser combination. Check the Puppeteer system requirements for the release you intend to install.

2. Choose how the browser will be managed

Approach What you install What to verify
Puppeteer-managed browser puppeteer, which normally downloads a compatible browser during installation. That the browser build is available and supported for this OS and architecture, and that install scripts were allowed to run.
Raspberry Pi OS Chromium Chromium supplied by the OS package manager and puppeteer or puppeteer-core. The installed executable path, shared libraries, and compatibility between Chromium and your Puppeteer version.
Other managed browser puppeteer-core plus a browser you install and maintain yourself. You are responsible for browser installation, executable configuration, dependencies, and version alignment.

puppeteer normally downloads a browser as part of installation. puppeteer-core does not download Chrome and expects you to configure the browser yourself. For details, see the Puppeteer installation guide.

3. Install Puppeteer and Chromium

Option A: let Puppeteer manage its browser

In a new project, install Puppeteer and check whether its browser installation completed:

mkdir pi-screenshot
cd pi-screenshot
npm init -y
npm install puppeteer
npx puppeteer browsers list

If your package manager or deployment setup blocks install scripts, the browser may not have been downloaded. Puppeteer documents installing its managed browser manually:

npx puppeteer browsers install

This installs a Puppeteer-managed browser; it is separate from Raspberry Pi OS’s Chromium package. If the managed browser cannot run on your Pi’s OS or architecture, use the system-browser approach below or verify support for your specific image before proceeding.

Option B: use Raspberry Pi OS Chromium

Use the OS package manager to install Chromium according to the documentation for your particular Raspberry Pi OS release. The available package name and browser path can depend on the release, so this guide does not assume one universal installation command or path. Raspberry Pi’s documentation describes Chromium as the default browser in new OS installations; Arm’s guide recommends using the distribution package manager for Chromium on Arm Linux.

After installation, locate the executable on the Pi itself:

command -v chromium
command -v chromium-browser
which chromium
which chromium-browser

Some commands may return no path. That is useful information: do not copy a path from another release or Pi. Check the installed package’s file list and your OS documentation to find the executable that exists on this image. Install Puppeteer without a bundled browser download by using puppeteer-core:

npm install puppeteer-core

You can also use the full puppeteer package with a separately installed browser, but explicitly setting executablePath is still necessary when you want to select the system Chromium.

4. Make a screenshot with the system Chromium

Create screenshot.js. Replace /path/from/command-v/chromium with the real path returned on your Pi. The script checks that the path exists, opens a page, waits for it to load, captures a full-page PNG, and closes the browser even if capture fails.

const fs = require('node:fs');
const puppeteer = require('puppeteer-core');

async function main() {
  const executablePath = '/path/from/command-v/chromium';
  if (!fs.existsSync(executablePath)) {
    throw new Error(`Chromium executable not found: ${executablePath}`);
  }

  const browser = await puppeteer.launch({
    executablePath,
    headless: true,
    args: ['--no-sandbox'],
  });

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

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

Run it from the project directory with node screenshot.js. The --no-sandbox argument is sometimes needed in constrained Linux environments, but it weakens Chromium’s security isolation. Prefer running Chromium as a non-root user with its sandbox enabled where your environment supports that. Do not expose a browser process to untrusted input as a substitute for a secure execution environment.

If you use puppeteer and its downloaded browser instead, the same script works without executablePath: change require('puppeteer-core') to require('puppeteer') and remove the executable path check and launch option.

5. Adjust capture behavior for the page

Wait strategy

The waitUntil setting controls when navigation is considered complete. load waits for the page load event; domcontentloaded is earlier; networkidle2 waits for low network activity. Pages with analytics, streaming requests, or long polling may never become network-idle. For those pages, use a bounded navigation wait and then wait for the specific content you need:

await page.goto('https://example.com', { waitUntil: 'domcontentloaded', timeout: 60000 });
await page.waitForSelector('main article', { timeout: 15000 });
await page.screenshot({ path: 'article.png', fullPage: true });

For lazy-loaded images, scrolling through the document can trigger loading before the screenshot. This is a page-specific workaround; it can take time on long pages:

await page.evaluate(async () => {
  const step = Math.max(400, window.innerHeight);
  for (let y = 0; y < document.body.scrollHeight; y += step) {
    window.scrollTo(0, y);
    await new Promise((resolve) => setTimeout(resolve, 150));
  }
  window.scrollTo(0, 0);
});
await page.screenshot({ path: 'full-page.png', fullPage: true });

Viewport, element, and format

Set the viewport before navigation if the site uses responsive layout. Capture a single element by selecting it and passing the element handle’s screenshot method. PNG is the default; JPEG and WebP are available in Puppeteer versions that support those formats.

await page.setViewport({ width: 390, height: 844, deviceScaleFactor: 2 });
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
const card = await page.waitForSelector('.product-card');
await card.screenshot({ path: 'card.png' });
await page.screenshot({ path: 'page.jpg', type: 'jpeg', quality: 80 });

For a full page, use fullPage: true. Extremely tall pages can consume substantial memory and produce large files; consider capturing a particular element or several viewport-sized sections instead.

6. Verify browser compatibility and Linux libraries

A browser can be present but fail to launch because its version is incompatible with Puppeteer or because a shared library is missing. Puppeteer publishes a supported browser mapping by release. Since distribution Chromium can update on a different schedule from Puppeteer’s expected Chrome for Testing, check that mapping when launches fail or behavior changes.

Use ldd to inspect the actual executable for missing shared libraries:

ldd /actual/path/to/chromium | grep 'not found'

Replace the path with the executable found on the Pi. No output from the filter generally means the command found no dependencies marked “not found”; it does not prove the browser will launch successfully. Puppeteer’s Linux troubleshooting guide lists common Debian-family dependencies, but those package names are diagnostic guidance, not a verified one-line dependency command for every Raspberry Pi OS release.

7. Troubleshooting

Symptom Likely cause What to do
Could not find Chrome or a browser download directory is empty Install scripts were blocked, or Puppeteer’s managed browser was never installed. For Puppeteer-managed mode, run npx puppeteer browsers install. For system Chromium, install it separately and set the verified executablePath.
spawn ... ENOENT The configured browser path does not exist or is misspelled. Run command -v chromium and command -v chromium-browser on the target image; use the path that actually exists.
error while loading shared libraries A required Linux shared library is missing. Run ldd /actual/path/to/chromium, identify entries marked not found, and install the corresponding dependency using package guidance for your OS release.
Browser starts and exits with a sandbox error The process user or runtime environment cannot use Chromium’s sandbox as configured. Prefer a non-root user and a supported sandbox configuration. Use --no-sandbox only when the environment requires it and the security trade-off is acceptable.
ProtocolError, launch failure, or unexplained browser behavior after an update Chromium and Puppeteer versions may not align. Check Puppeteer’s supported browser mapping. Pin a compatible package/browser combination or update both deliberately.
Browser installs but will not run on a 32-bit image The selected browser build may not support the OS architecture. Confirm uname -m and OS bitness. Do not assume current arm64 support extends to older 32-bit Pi images.
Navigation times out on a site that visibly loaded The page may keep network connections active, making networkidle2 unsuitable. Use domcontentloaded or load, then wait for a specific selector or bounded delay.
Screenshot misses images or below-the-fold content Images may be lazy-loaded or content may render after initial navigation. Wait for a target selector, scroll through the page to trigger lazy loading, then capture. Keep waits bounded.
Blank or incomplete screenshot Navigation failed, a bot check appeared, required content was not ready, or the viewport triggered a different layout. Log the final URL and page title, inspect console and request failures, wait for the expected selector, and verify the viewport.

8. Performance, reliability, and cost

A Raspberry Pi has finite CPU and memory. A full-page capture, high device scale factor, multiple concurrent browser tabs, or a page with heavy scripts can increase capture time and memory use. Start with one browser and one page at a time, use only the viewport and resolution you need, and close pages and browsers in finally blocks. Reuse a browser process for a controlled batch of captures rather than launching Chromium for every URL, while creating and closing a page per job.

For reliability, set navigation and selector timeouts, log the URL and error when a capture fails, and retry only transient failures with a limit. Do not retry forever: a permanently incompatible browser, missing library, or unsupported architecture will not be fixed by repeated attempts. When updating the OS Chromium package or Puppeteer, check version compatibility and rerun a representative capture.

The local software route has no per-screenshot API charge, but it uses your own Pi’s power, storage, maintenance time, and network connection. Hardware prices and availability in India were not verified here. If you already own a compatible Raspberry Pi board, no new board is implied by this guide.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request can return a PNG, JPEG, WebP, or PDF. Its cookie and consent handling accepts the banner like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. Every feature is on every plan: 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000, and yearly billing gives two months free.

Install the Python dependency with python -m pip install requests. See the ScreenshotNeo API documentation for request options.

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,
)
r.raise_for_status()
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()));

Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Create a free ScreenshotNeo account to get started.

FAQ

Does this setup change because I am in India?

The consulted software documentation does not identify an India-specific change to Puppeteer or Chromium setup. Follow the instructions for your Raspberry Pi OS release and architecture.

Can I use Raspberry Pi OS’s Chromium with Puppeteer?

Yes, if the installed Chromium and Puppeteer are compatible. Find the executable on the Pi and configure executablePath; verify libraries if it does not launch.

Should I use puppeteer or puppeteer-core?

Use puppeteer when you want its install flow to manage a browser. Use puppeteer-core when you install and configure Chromium or another browser yourself.

Is 32-bit Raspberry Pi OS supported by current Puppeteer browser downloads?

The current system requirements cited here list Chrome for Testing on Linux arm64 and x64. They do not establish support for every older 32-bit Pi image; verify the exact release and architecture.