ScreenshotNeo

BlogHow-to

How to Render SVG Charts to PNG with Headless Chrome

Capture a browser-rendered SVG chart as PNG with Chrome’s CLI or Puppeteer, with control over framing, transparency and render readiness.

By the ScreenshotNeo team4 October 20267 min read

To render a browser-visible SVG chart to PNG, open the page containing the chart in headless Chrome and capture it with Chrome’s --screenshot flag or Puppeteer’s page.screenshot(). Choose a viewport, full-page capture, or a clipped chart element depending on the output you need. For charts that render asynchronously, wait for the chart’s own ready signal before taking the screenshot.

This approach captures the chart as Chrome renders it, including its page layout and styles. It assumes the SVG chart is already available on a browser page; the capture commands do not create or configure a chart library. Chrome’s official documentation describes --screenshot as saving the target page to screenshot.png in the current working directory (Chrome headless command-line reference).

1. Prepare the chart page

Make sure the page can render the SVG in the environment where Chrome will run. For an SVG generated by JavaScript, identify a reliable readiness condition from the page or chart application. That might be an application-owned global flag, a DOM attribute set after drawing, or a selector that appears only after rendering. There is no universal ready selector for all chart libraries.

For a static SVG that is already present at initial page load, navigation completion may be sufficient. For animated, data-driven, or asynchronously loaded charts, page load alone may happen before the chart is ready. Do not treat a fixed delay or Chrome’s timeout as proof of readiness.

2. Capture with Chrome’s headless CLI

Use Chrome’s --screenshot flag for a one-off capture. Set --window-size to control the viewport dimensions. Replace the URL with the page that contains your chart:

google-chrome --headless --window-size=1200,800 --screenshot=chart.png https://example.com/chart

Depending on your installation, the executable may be named chrome, chromium, or google-chrome. Use the binary available in your environment. Chrome documents that --timeout is a maximum wait before capture, even if loading continues:

google-chrome --headless --window-size=1200,800 --timeout=5000 --screenshot=chart.png https://example.com/chart

The timeout can bound how long the CLI waits; it does not verify that a chart-specific render step finished. If the chart needs a deterministic ready condition, use a scripted browser workflow such as Puppeteer.

3. Capture with Puppeteer

Puppeteer’s Page.screenshot() saves a PNG to a file path by default. This runnable Node.js example navigates to a chart page, waits for an application-owned readiness selector, and captures the chart element. Replace [data-chart-ready] with a selector your page sets only when the SVG is ready, and replace #chart with the chart container selector.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
try {
  const page = await browser.newPage({
    viewport: { width: 1200, height: 800 },
  });
  await page.goto('https://example.com/chart', { waitUntil: 'networkidle0' });
  await page.waitForSelector('[data-chart-ready]', { timeout: 15000 });

  const chart = await page.$('#chart');
  if (!chart) throw new Error('Chart element #chart was not found');
  await chart.screenshot({ path: 'chart.png', type: 'png' });
} finally {
  await browser.close();
}

The networkidle0 navigation condition waits for network activity to become idle, but some pages keep connections open or continue rendering after requests stop. The application readiness selector is the important chart-specific check. Puppeteer also supports element screenshots and page screenshot options including fullPage, clip, and omitBackground (Puppeteer screenshot API).

4. Choose the capture area and background

Need Puppeteer option What it captures
Visible browser viewport Default screenshot The current viewport at the configured dimensions.
Entire document fullPage: true The full scrollable page, including content outside the viewport.
Specific rectangle clip: { x, y, width, height } A rectangular region in page coordinates.
Chart element only elementHandle.screenshot() The bounding box of the selected element.
Transparent background omitBackground: true Omits the default page background where transparency is supported.

For a chart-only image, an element screenshot is usually the most direct choice because its bounds follow the chart element. Use a clip when you need a fixed crop independent of the element’s measured dimensions. For a transparent image, use PNG and omitBackground: true; page styles or SVG backgrounds may still paint an opaque color, so inspect the resulting file in the destination workflow.

await page.screenshot({
  path: 'chart-transparent.png',
  type: 'png',
  clip: { x: 100, y: 120, width: 900, height: 520 },
  omitBackground: true,
});

To capture the whole document instead:

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

5. cURL, Python, and Node.js with ScreenshotNeo

For a one-off page screenshot without installing or managing a browser locally, ScreenshotNeo provides a website screenshot API. Its endpoint accepts a URL and returns an image or PDF. These examples capture the page containing the chart; ensure the chart is rendered in the page at capture time.

cURL

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

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com/chart"},
    timeout=90,
)
r.raise_for_status()
open("chart.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com/chart',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(({ writeFile }) =>
  writeFile('chart.webp', Buffer.from(await res.arrayBuffer()))
);

See the ScreenshotNeo API documentation for API parameters, output options, and configuration. ScreenshotNeo can capture full pages or a selected element, set viewport and device presets, use custom CSS or JavaScript, wait for selectors or network idle, and choose image output settings. Its response headers report the page verdict and whether the capture was billed.

6. Troubleshooting

Symptom Likely cause Fix
PNG is blank or the chart is missing The chart has not been inserted or drawn when capture occurs, or the page failed to load its data. Wait for a page-owned ready selector or flag. Check the page and its data requests in a normal browser.
Chart is cut off The viewport is too small, the chart container clips overflow, or the capture crop is too narrow. Increase --window-size or Puppeteer viewport dimensions; use an element screenshot or adjust the clip bounds.
Extra page content appears around the chart A viewport or full-page screenshot captures more than the chart element. Capture the chart element directly or use a clip matching the required bounds.
Background is opaque The page or SVG paints a background, or the screenshot option did not omit the browser’s default background. Use PNG and omitBackground: true; inspect the page’s CSS and SVG background fills.
CLI captures too early The timeout is only a maximum wait, not a signal that chart rendering completed. Use Puppeteer and wait for an application-specific ready condition before capture.
Puppeteer times out waiting for network idle The page maintains long-lived network requests or never becomes fully idle. Use a different navigation condition, then wait for the chart’s explicit ready selector.
Element selector is not found The selector differs from the actual page markup, or the chart is created later. Confirm the selector and wait for the relevant container or ready marker before querying it.
Screenshot file is not where expected The path is relative to the process’s current working directory. Use an absolute output path or check the working directory before running Chrome.

7. Performance, reliability, and cost

Chrome CLI is convenient for a single capture and avoids writing a browser script. Puppeteer is better when a workflow needs explicit readiness checks, repeatable viewport settings, element targeting, or integration into a Node.js process. Full-page captures and large viewports can produce larger images and require more rendering work than a chart-element capture.

For reliable automation, make the input page deterministic: wait for its data and SVG rendering, choose stable selectors, and set the viewport explicitly. A timeout limits waiting but does not make a capture correct. The cited documentation does not establish pixel-identical output across Chrome versions or chart libraries, so inspect dimensions and appearance in the consuming workflow.

Running Chrome yourself has no per-shot API charge, but your workflow must provide the browser runtime and compute. A hosted screenshot API has a service cost instead of local browser management. ScreenshotNeo offers 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots. Only clean shots are billed, while bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. See its documentation for details.

Or skip the browser setup

Make one API request for the page containing your SVG chart:

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

ScreenshotNeo documentation covers the available capture options. 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 use the screenshot tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Sign up for 1,000 free screenshots a month.

FAQ

Does this convert an SVG file directly?

The commands capture a browser page. Put the SVG chart in a page first, or use an API that accepts HTML/CSS input when that better fits your workflow.

Can headless Chrome output formats other than PNG?

The DevTools Protocol documents PNG as the default screenshot format and also lists JPEG and WebP. Puppeteer’s screenshot API supports image type options; PNG is its default. Check the API options for the version you use.

Should I use a fixed sleep to wait for the chart?

A fixed sleep can be too short on a slow run and unnecessarily long on a fast one. Prefer a chart-specific readiness condition that the page sets after drawing.