ScreenshotNeo

BlogComparisons

Selenium vs Puppeteer for Website Screenshot Automation

Compare Selenium and Puppeteer for website screenshots, with runnable Node.js examples, setup guidance, tradeoffs, and a hosted alternative.

By the ScreenshotNeo team4 October 202611 min read

Both Selenium and Puppeteer can automate website screenshots. Choose Puppeteer when a Node.js service needs a direct page or element screenshot API and its browser and protocol support fits. Choose Selenium when your team needs its language bindings, browser coverage, or existing WebDriver and Grid infrastructure. There is no established universal winner for screenshot speed or reliability; compare both on the pages and environment you actually run.

This guide focuses on screenshot automation from Node.js. It includes runnable examples for page and element captures, explains how to choose and compare the tools, and covers common capture failures. For other Selenium languages, use the official documentation for the binding you select.

1. Quick comparison

Need Better fit to investigate Why
Node.js screenshot service with direct capture methods Puppeteer It documents page and element screenshot methods and screenshot-specific options.
Existing Selenium tests or Grid Selenium You can use WebDriver capture within the browser automation and orchestration your team already maintains.
More language bindings Selenium Selenium supports multiple language bindings; Puppeteer is a Node.js library.
A particular browser or protocol requirement Check exact support first Puppeteer documents Chrome and Firefox. Selenium documents browser-specific support for Chrome, Edge, Firefox, Safari, and Internet Explorer. Verify the browser, protocol, version, and capture behavior you need.
No browser binary or driver maintenance Consider a hosted screenshot API A hosted service changes the operating model: less browser infrastructure to maintain, with less direct control over the browser environment.

Puppeteer’s FAQ describes Selenium as broader in language bindings and orchestration tooling, including Selenium Grid. That is a difference in project scope, not a blanket quality ranking. Both tools can capture pages and elements.

2. Puppeteer: runnable Node.js screenshot examples

Puppeteer is a natural candidate when the capture service is already in Node.js and you want page- and element-level screenshot methods. Install it in a new project:

npm init -y
npm install puppeteer

Save the following as screenshot-puppeteer.mjs. It launches the browser installed for Puppeteer, opens the target page, waits for a chosen page condition, captures a full-page PNG, and then captures a selected element as a separate PNG.

import puppeteer from 'puppeteer';

const url = process.argv[2] ?? 'https://example.com';
const browser = await puppeteer.launch({ headless: true });

try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });

  await page.goto(url, { waitUntil: 'networkidle2', timeout: 60_000 });
  await page.locator('body').wait();

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

  const target = await page.$('main');
  if (!target) {
    throw new Error('Could not find a <main> element to capture');
  }
  await target.screenshot({ path: 'main.png', type: 'png' });

  console.log('Wrote page.png and main.png');
} finally {
  await browser.close();
}

Run it with node screenshot-puppeteer.mjs https://example.com. Replace main with a stable CSS selector on the page. The locator wait ensures the element exists; for a single-page app, also wait for the application-specific content or state that means the page is ready.

Useful Puppeteer screenshot options

  • fullPage: true captures beyond the viewport; omit it for the currently visible viewport.
  • clip: { x, y, width, height } limits a page screenshot to a rectangle. Use coordinates in the page’s CSS pixel space and ensure the region is within the rendered page.
  • path writes the result to a file. Without it, the screenshot API can return image data (binary or base64, depending on the option and API version).
  • type selects a supported image output such as PNG, JPEG, or WebP where available in the installed version. Check the API documentation for the exact accepted values.
  • quality applies to lossy formats such as JPEG; it is not a meaningful quality control for PNG.
  • Set viewport dimensions and device scale factor before navigation and capture when output size and layout consistency matter.

Use the Puppeteer screenshot guide and ScreenshotOptions API reference for the current version’s complete option definitions.

3. Selenium: runnable Node.js screenshot examples

Selenium WebDriver can capture the current browser context and individual elements. This example uses the JavaScript binding with ChromeDriver. Install the packages and make sure a compatible Chrome browser and driver are available in your environment:

npm init -y
npm install selenium-webdriver

Save as screenshot-selenium.mjs. Selenium’s screenshot method returns Base64 image data; the example decodes it and writes PNG files.

import { Builder, By, until } from 'selenium-webdriver';
import chrome from 'selenium-webdriver/chrome.js';
import { writeFile } from 'node:fs/promises';

const url = process.argv[2] ?? 'https://example.com';
const options = new chrome.Options().addArguments('--headless=new', '--window-size=1440,900');
const driver = await new Builder().forBrowser('chrome').setChromeOptions(options).build();

try {
  await driver.get(url);
  await driver.wait(until.elementLocated(By.css('body')), 15_000);

  const pageBase64 = await driver.takeScreenshot();
  await writeFile('page.png', Buffer.from(pageBase64, 'base64'));

  const main = await driver.findElement(By.css('main'));
  const elementBase64 = await main.takeScreenshot();
  await writeFile('main.png', Buffer.from(elementBase64, 'base64'));

  console.log('Wrote page.png and main.png');
} finally {
  await driver.quit();
}

Run it with node screenshot-selenium.mjs https://example.com. The exact way Chrome and its driver are installed depends on your operating system, container, and Selenium version. Selenium Manager may help resolve drivers in supported setups; verify behavior against the current Selenium documentation and your deployment constraints.

The example captures the current browsing viewport and an element. Selenium’s standard WebDriver screenshot workflow does not make Puppeteer’s fullPage option portable across drivers. If you need a full document image, verify support for your chosen browser and binding or implement a page-specific scroll-and-stitch workflow, taking care with sticky elements, lazy content, and changing page state.

For the official Selenium screenshot workflow, see Selenium’s windows and tabs guide and follow the documentation for your chosen language binding.

4. Make the comparison fair

A screenshot comparison is meaningful only when both runs target the same visual state. Keep these conditions aligned:

  1. Use the same browser family and, where possible, the same browser build.
  2. Set the same viewport dimensions, device scale factor, and color scheme.
  3. Use equivalent cookies, authentication, locale, and application data.
  4. Wait for the same meaningful page condition, such as a heading, chart, or application-ready marker.
  5. Handle animations and lazy-loaded content consistently. If the page reveals content only as it scrolls, scroll it into view before capture and wait for loading to settle.
  6. Use the same capture scope and image format. Compare viewport with viewport, full page with full page, and equivalent element bounds.
  7. Repeat representative runs under the concurrency and resource limits expected in production.

A navigation promise resolving does not guarantee that an asynchronous application has finished rendering. Network-idle conditions can also be unsuitable for pages with long-lived requests. Wait for the state relevant to the screenshot instead of treating one generic navigation event as visual readiness.

No controlled benchmark in the reviewed sources establishes that either library is universally faster or more reliable. Measure your own representative pages if latency, throughput, or visual consistency will determine the choice.

5. Browser support, protocols, and operations

Browser and protocol fit

Puppeteer’s FAQ documents Chrome and Firefox support. It says Chrome uses the Chrome DevTools Protocol by default and Firefox uses WebDriver BiDi by default. Selenium’s documentation covers browser-specific workflows for Chrome, Edge, Firefox, Safari, and Internet Explorer. These broad descriptions do not guarantee that every browser version supports every capture detail identically. Check the exact browser, protocol, feature, and version combination before committing.

Where the browser runs

With Puppeteer, your service runs and maintains compatible browser binaries and the capture environment. With Selenium, it manages WebDriver drivers and the execution environment, potentially using an existing Grid for distributed execution. Consider the container image, browser updates, fonts, memory, process limits, and concurrency in either case. A hosted screenshot API is another operating model when avoiding this maintenance matters; it provides less direct control over the browser setup.

Language and team fit

Puppeteer offers a JavaScript and TypeScript-oriented API. Selenium’s language bindings make it a practical choice when capture must live in a Python, Java, C#, Ruby, or other Selenium-based codebase. Avoid adding a second automation stack solely for screenshots unless the API or deployment benefits justify the added maintenance.

6. Output scope and page-state edge cases

  • Full-page images: Tall pages can produce large files and high memory use. Lazy images may not load until scrolled into view; trigger the page behavior and allow images to settle before capture.
  • Element images: A missing selector should be handled as a page-specific failure, not silently replaced with a blank screenshot. Confirm the selector is unique and visible, and account for elements inside frames or shadow roots if applicable.
  • Responsive layouts: A different viewport can change the page layout, menus, and element location. Set it before navigation or before the page’s responsive state is measured.
  • Fonts and assets: A capture taken before web fonts or images finish loading may differ across runs. Wait for relevant assets or a page-level ready signal.
  • Animations and video: Animated content can differ from frame to frame. If stable images matter, pause or disable animation using a page-specific method and document that choice.
  • Authentication and consent: Supply the same session state in both tools. Avoid placing credentials in logged URLs or source control; use an appropriate secret store and test access in the actual runtime.
  • Very long pages: Check image dimensions and memory consumption before raising concurrency. If only a section matters, an element or clipped capture may be cheaper to store and compare.

7. Performance, reliability, and cost

Both tools consume resources to launch or control browsers and render pages. Actual latency and throughput depend on page weight, browser startup strategy, network conditions, waits, image dimensions, and concurrency. Reuse a browser process where the library and workload allow it, isolate capture contexts as needed, and close pages and browser sessions reliably. Set navigation and operation timeouts, cap concurrency, and record whether a failure occurred during navigation, readiness waiting, or screenshot writing.

Self-hosted cost includes engineering time and the compute, storage, and network resources used to run browsers; Selenium Grid may also require operating its distributed infrastructure. There is no dossier-backed per-shot cost or comparative performance figure for Selenium versus Puppeteer. Estimate from your own request volume and runtime, including retries and failed navigations.

For a hosted option, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. Its stated pricing is 1,000 shots per month free with no card; Starter is $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan. Treat those as plan allowances, not a benchmark against the cost of running your own browser fleet.

8. Troubleshooting

Symptom Likely cause What to check
Browser or driver fails to start Missing browser, incompatible driver, sandbox/container constraints, or unavailable runtime dependency Confirm the installed browser and driver versions, inspect startup logs, and validate the same container or host configuration used in production.
Navigation times out Slow page, blocked request, long-lived network activity, or a wait condition that never resolves Check the page directly from the runtime, set an intentional timeout, and wait for a specific content condition when network idle is not appropriate.
Screenshot is blank or incomplete Capture happened before app rendering, navigation reached an error page, or content requires interaction Check the final URL and page title, wait for an application-ready selector, and trigger the required interaction before capture.
Element capture reports no element Selector is wrong, element appears later, or content is in a frame or shadow root Inspect the DOM in the same session, wait for the selector, and use the correct frame or shadow-root access pattern.
Images or fonts are missing Assets are still loading, blocked, or lazy-loaded below the fold Wait for relevant assets, scroll through lazy regions where appropriate, and inspect network and console errors.
Screenshot differs between runs Viewport, browser build, session state, time, animation, or page data differs Fix those inputs and wait for a deterministic page state before comparing pixels.
Full-page output is unexpectedly short Tool or driver captured only the viewport, or page height was not settled Confirm the chosen API’s documented full-page behavior and wait until content expansion and lazy loading finish.
Capture works locally but fails in deployment Different fonts, browser dependencies, permissions, network access, or resource limits Use a production-like image, check filesystem and process permissions, and record browser startup and page errors.

9. Or skip the browser setup

If your main requirement is a screenshot from a URL, ScreenshotNeo offers a single GET request. See the ScreenshotNeo API docs for configuration and response details.

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 import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

Cookie banners are accepted like a visitor and removed along with 60+ known consent platforms, newsletter popups, and chat widgets before the shot; each cleanup step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with the response identifying the page verdict and billing status in headers. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Sign up free and get 1,000 screenshots a month with no card.

10. Frequently asked questions

Can Puppeteer replace Selenium?

It can replace Selenium for some Node.js browser automation jobs, but the projects have different scope. Selenium may still fit better when you need its language bindings, browser ecosystem, or Grid orchestration.

Can Selenium take a full-page screenshot?

WebDriver’s documented screenshot flow captures the current context, and element screenshots are available. Full-document capture behavior depends on browser and driver support or an additional scroll-and-stitch method, so verify the implementation you plan to deploy.

Which is more reliable?

The reviewed evidence does not establish a universal reliability winner. Reliability depends on the browser, page state, wait strategy, runtime, and failure handling in your system.

Which should a Python team use?

Selenium has a Python binding. Puppeteer is a Node.js library, so a Python team would need another integration boundary or a different tool if it wants Puppeteer’s API.

Do I need a screenshot API if I already use Selenium?

No. A hosted API is useful when you want to avoid maintaining the browser capture environment or need a URL-to-image service. Keep Selenium when its direct browser control and existing infrastructure are important.

Sources