ScreenshotNeo

BlogHow-to

Convert a Webpage to a Transparent PNG with Headless Chrome

Use Puppeteer and Chrome to capture a webpage as a transparent PNG. Learn how to set capture bounds, handle opaque page backgrounds, and troubleshoot common issues.

By the ScreenshotNeo team4 October 20266 min read

Use Puppeteer’s page.screenshot() with omitBackground: true to save a webpage as a transparent PNG. This hides Chrome’s default white background; it does not remove an opaque background painted by the page itself. Puppeteer uses PNG by default, but the example below sets type: 'png' explicitly. Puppeteer screenshot options.

1. Install Puppeteer and capture a page

Install Puppeteer in a Node.js project, then save this as capture.mjs. Puppeteer’s package manages a compatible Chrome for you in the standard installation workflow.

npm install puppeteer
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1440, height: 1000, deviceScaleFactor: 1 });

  await page.goto('https://example.com', {
    waitUntil: 'networkidle2',
    timeout: 60000,
  });

  await page.screenshot({
    path: 'capture.png',
    type: 'png',
    omitBackground: true,
  });
} finally {
  await browser.close();
}

Run it with node capture.mjs. The finally block closes Chrome even if navigation or capture fails. The official Puppeteer screenshot guide demonstrates networkidle2; no navigation wait condition guarantees that every site has finished rendering. For pages that continue loading data, wait for a meaningful selector or application state as shown below.

2. Choose the capture area

Capture the current viewport

Without fullPage, Puppeteer captures the viewport. Set its dimensions before navigation or capture using page.setViewport(). The viewport controls the layout width and height; deviceScaleFactor controls pixel density.

Capture the full page

await page.screenshot({
  path: 'full-page.png',
  type: 'png',
  omitBackground: true,
  fullPage: true,
});

fullPage defaults to false. A very long page can produce a large image and consume more memory. Lazy-loaded images may not appear unless they have been scrolled into view or otherwise loaded by the page. If the page uses lazy loading, scroll through it and wait for its images before capturing.

Capture a specific rectangle

await page.screenshot({
  path: 'region.png',
  type: 'png',
  omitBackground: true,
  clip: { x: 100, y: 120, width: 800, height: 500 },
});

The clip rectangle is in page screenshot coordinates. Use either a full-page capture or a clip that matches the region you need; clipping is useful for a fixed area, while fullPage captures the document extent. See the ScreenshotOptions API for current option details.

3. Wait for the content you need

For a mostly static page, waiting for navigation to reach networkidle2 is a practical starting point. Sites with polling, analytics, streaming requests, or client-side rendering can remain active or render content after navigation completes. Wait for a page-specific signal instead of assuming the network becoming idle means the page is visually complete.

await page.goto('https://example.com/dashboard', {
  waitUntil: 'domcontentloaded',
  timeout: 60000,
});

await page.waitForSelector('[data-report-ready="true"]', {
  timeout: 20000,
});

await page.screenshot({
  path: 'report.png',
  type: 'png',
  omitBackground: true,
});

Replace the selector with an element that appears only when the desired content is ready. If there is no reliable selector, wait for a known application condition or use a short delay as a last resort; arbitrary delays are less reliable because load times vary.

4. Make the page background transparent

omitBackground: true omits Chrome’s default white page background, allowing transparent pixels where the page does not paint a background. It does not make a white or colored CSS background transparent. If the result still has an opaque rectangle, inspect the target page’s html, body, and relevant containers for background colors or images.

When you control the page, remove or override only the background you want transparent. For example, inject a small style before capture:

await page.addStyleTag({
  content: `
    html, body {
      background: transparent !important;
    }
  `,
});

await page.screenshot({
  path: 'transparent.png',
  type: 'png',
  omitBackground: true,
});

This changes the rendered page for the capture. A full-page background image, opaque content panel, or element-level background may still cover pixels. Target those elements explicitly if that is the intended design. Do not remove backgrounds indiscriminately from pages where they convey structure or readability.

5. Use Chrome’s command line for a non-transparent screenshot

For a one-off viewport screenshot where transparency is not required, Chrome’s headless command line is simpler:

chrome --headless --screenshot --window-size=412,892 https://example.com

Chrome saves screenshot.png in the current working directory. The CLI reference also documents --timeout to set the maximum wait before capture, including when the page is still loading. The documented CLI screenshot options cover viewport size and timeout, but do not document a transparency option. Use Puppeteer’s omitBackground for the transparent PNG requirement. See Chrome Headless command-line reference and Chrome Headless mode.

6. Troubleshoot common problems

Symptom Likely cause Fix
The PNG background is still white or colored The page or a container paints an opaque CSS or image background. omitBackground only omits Chrome’s default background. Inspect html, body, and the visible containers. Remove or override the relevant background when you control the page, then capture with omitBackground: true.
Content or images are missing Capture ran before client rendering, image loading, or lazy loading completed. Wait for a meaningful selector or app state. Scroll lazy-loaded content into view and wait for its images before taking a full-page screenshot.
Navigation times out The site keeps connections open, is slow, or blocks automated browser traffic. Use a navigation condition suited to the page, such as domcontentloaded, then wait for the specific content you need. Set a reasonable timeout and handle navigation failures explicitly.
Chrome does not start The runtime lacks browser dependencies, has an incompatible Chrome setup, or disallows the launch configuration. Use Puppeteer’s supported installation path and check the runtime’s Chrome dependencies and launch permissions. For containers, follow the deployment environment’s browser requirements.
The saved file is not transparent The output may be JPEG, or an image viewer may display transparency as white. Save as PNG with type: 'png' and inspect the alpha channel in an editor or viewer that shows transparency.
The full-page image is unexpectedly huge The document is unusually long or the device scale factor is high. Capture a clip or viewport, reduce the viewport/device scale factor, or split the document into sections.

7. Reliability, performance, and cost

Launching a browser has more setup and resource cost than a direct screenshot API call, but it gives you control over navigation, page state, styling, viewport, and capture bounds. Reuse a browser process for batches of captures when appropriate, while creating a fresh page for each job and closing pages and the browser cleanly. Set navigation and selector timeouts so a stalled site does not hold a worker indefinitely.

For reliable output, make captures reproducible: specify viewport and device scale factor, wait for an application-specific ready signal, and record failures separately from successful image files. Treat external pages as variable: authentication, blocked resources, site changes, and timing can affect the result. PNG preserves transparency but can be larger than lossy formats; choose PNG because alpha is required, then resize or crop to the actual needed bounds.

Self-hosting means you operate the browser runtime and its compute; there is no per-image service charge, but infrastructure and maintenance still have costs. If screenshots are occasional and need a transparent browser canvas, local Puppeteer is direct. If the task is repeated website capture and you prefer not to maintain browser workers, an API can be simpler.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. Its API returns PNG, JPEG, WebP, or PDF with one GET request. This is a hosted screenshot option for routine page captures; the documented product facts here do not claim an API option for transparent PNG backgrounds.

cURL:

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

Python:

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)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo API documentation for request options and response handling. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed; an MCP server lets AI agents take screenshots; and 1,000 screenshots a month are free with no card, with paid plans starting at $5 for 3,000. Sign up for the free plan.

Frequently asked questions

Does a transparent PNG make text and images transparent too?

No. It makes unpainted background pixels transparent. Page content remains visible unless its own styles make it transparent.

Can Chrome’s headless CLI produce a transparent PNG?

The cited CLI screenshot documentation describes PNG capture and sizing, but does not document a transparency flag. Puppeteer exposes omitBackground for transparency.

Is networkidle2 always the right wait condition?

No. It is a useful starting point for some pages, but dynamic applications may need an explicit selector or application-ready signal.

Why choose PNG instead of WebP or JPEG?

PNG supports the transparency requirement in this workflow. JPEG does not preserve alpha; use another format only when transparency is not needed and the receiving workflow supports it.