ScreenshotNeo

BlogComparisons

Puppeteer vs Selenium for Website Screenshot Testing

Compare Puppeteer and Selenium for website screenshot testing, with runnable capture examples, browser tradeoffs, and guidance for repeatable visual checks.

By the ScreenshotNeo team4 October 20269 min read

Short answer: Use Puppeteer when your screenshot workflow is already in Node.js and its Chrome or Firefox protocol support covers the features you need. Use Selenium when you need multiple language bindings, existing WebDriver tests, browser-specific execution, or Selenium Grid. Both can capture page and element screenshots; neither screenshot API alone provides a complete visual-regression process. You still need controlled rendering conditions, stored baselines, a comparison method, and a review path for approved changes.

If you need a managed screenshot API instead of running browsers and drivers, try ScreenshotNeo first: it removes common consent banners, popups, and chat widgets before capture, bills only clean shots, and its paid plans start at $5 for 3,000 screenshots.

1. How to choose

Need Better starting point Why
JavaScript or TypeScript test code targeting Chrome or Firefox Puppeteer It is a Node.js library with direct page and element screenshot methods. Its documented Chrome and Firefox support begins at Puppeteer v23.0.0.
Java, Python, C#, Ruby, or another supported language Selenium Selenium offers language bindings and fits teams already using WebDriver.
Remote browser execution or a distributed browser grid Selenium, if your team uses Grid Selenium Grid is an orchestration option; large-scale orchestration is outside Puppeteer’s scope.
Specific browser behavior, including Safari or Edge Evaluate Selenium and the target browser setup Selenium documents browser-specific support across Chrome, Edge, Firefox, Internet Explorer, and Safari. Verify the exact browser, platform, and screenshot behavior required.
Visual-regression checks Either can capture; add a comparison workflow Capture APIs do not by themselves define baselines, pixel or perceptual diffs, approvals, or baseline updates.

Do not assume every screenshot option works identically across browsers or protocols. Puppeteer uses CDP by default for Chrome and WebDriver BiDi for Firefox; Chrome can also use BiDi. BiDi support has feature limits, so check its supported parameters for the precise capture behavior you need.

2. Capture screenshots with Puppeteer

Install Puppeteer in a Node.js project. The standard package setup provides a browser for its default workflow; if your environment manages the browser separately, configure the executable and versions deliberately.

npm install puppeteer

Create screenshot.mjs:

import puppeteer from 'puppeteer';

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

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

  // Viewport screenshot. Set fullPage: true to capture the full document.
  await page.screenshot({ path: 'page.png', fullPage: false });

  // Element screenshot: wait for the target, then capture its bounding box.
  const card = await page.waitForSelector('main', { timeout: 10_000 });
  await card.screenshot({ path: 'main.png' });
} finally {
  await browser.close();
}
node screenshot.mjs

The screenshot guide documents page and element captures. For deterministic tests, make the page state explicit before capture: wait for the relevant content, set viewport and device scale, and avoid relying on a timing guess. Puppeteer screenshot documentation and the Puppeteer FAQ cover capture and browser support.

Puppeteer options and protocol considerations

  • fullPage: capture the full document instead of the current viewport when supported by the selected browser/protocol path.
  • Element capture: locate the element and use its screenshot method; ensure it is visible and stable first.
  • Viewport and device scale: set these consistently because dimensions and scale affect wrapping, layout, and raster output.
  • Browser and protocol: pin the Puppeteer/browser setup used for baselines. Chrome CDP and BiDi, and Firefox BiDi, may not expose identical behaviors.

The BiDi guide documents limited screenshot parameters, including clip, encoding, and fullPage, and lists unsupported features. Check it before depending on a protocol-specific option: Puppeteer WebDriver BiDi guide.

3. Capture screenshots with Selenium

Selenium supports multiple languages. This runnable Python example uses Selenium’s WebDriver screenshot API and an explicit wait for a page element.

python -m pip install selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--window-size=1440,1000')

driver = webdriver.Chrome(options=options)
try:
    driver.get('https://example.com')
    WebDriverWait(driver, 15).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, 'main'))
    )

    # Save the current viewport.
    driver.save_screenshot('page.png')

    # Save one element.
    main = driver.find_element(By.CSS_SELECTOR, 'main')
    main.screenshot('main.png')
finally:
    driver.quit()

Selenium’s official examples show both page and element screenshot capture. Browser setup and capabilities vary by browser and language binding. Use the official WebDriver documentation and supported browser documentation for your selected binding and browser. Selenium notes that “Each browser has custom capabilities and unique features.”

Python, JavaScript, and other bindings

The Python example above uses save_screenshot for a page and element.screenshot for an element. In other Selenium bindings, use the equivalent WebDriver and WebElement screenshot methods documented for that language. Keep the capture contract the same across bindings: navigate to a known URL, wait for a known state, set browser dimensions, save the artifact, and close the driver even if capture fails.

4. Build a useful visual-regression workflow

A screenshot is an artifact. A visual test also needs a baseline policy and a way to decide whether a rendered difference is a defect or an approved change.

  1. Choose the capture scope. Use a viewport for the visible fold, a full-page image for page-wide layout, or an element image for a component. Keep scope consistent between baseline and current captures.
  2. Make state reproducible. Use fixed test data, stable routes, a known authentication state, deterministic content where possible, and explicit waits for the content under test.
  3. Pin the rendering environment. Keep the host OS or container image, browser version, browser settings, headless mode, viewport, device scale, and relevant hardware consistent. Official visual-testing guidance identifies environment differences as a source of rendered image variation.
  4. Store named baselines. Key them by page or component and any intentional matrix dimensions, such as browser, viewport, or theme. Avoid silently replacing a baseline when a test changes.
  5. Compare with an explicit policy. Decide whether to use pixel equality, a tolerance, or a perceptual comparison. The tolerance should handle known rendering noise without concealing meaningful layout changes.
  6. Review and update deliberately. Make diffs available to reviewers. Update reference images only after a person or accepted workflow approves the visual change.
  7. Separate capture failure from visual failure. A timeout, blank page, missing element, or browser startup error should be reported as an infrastructure or page-load problem, not as a valid screenshot diff.

For further guidance on baselines and environment variance, see the Playwright visual comparisons guide. It is adjacent guidance about visual comparisons, not evidence that Puppeteer and Selenium have identical features.

5. Browser and screenshot edge cases

  • Lazy-loaded content: scrolling or waiting for a target may be necessary before capture. A full-page capture does not guarantee every site has loaded content that appears only after interaction or scrolling.
  • Animations and transitions: they can make two captures differ depending on timing. Disable or settle them in the test environment when they are not the behavior under test.
  • Fonts and images: wait for the relevant assets and page state before taking a baseline. A fallback font can change line breaks and downstream layout.
  • Dynamic content: timestamps, rotating promotions, random IDs, and personalized content can create noise. Use stable fixtures or mask only the regions that are intentionally variable.
  • Cross-browser differences: compare a browser’s output to a baseline generated with that same browser and version unless cross-browser rendering itself is the test.
  • Long pages: full-page images may be large and can expose browser-specific capture limits or sticky-element behavior. Test the capture mode on representative pages.
  • Element not in view: wait for visibility and ensure the element has a usable bounding rectangle before capturing.

6. Reliability, performance, and cost

Reliability: browser, driver, protocol, operating system, and page state all affect output. Pin and record versions alongside baselines. In CI, use the same browser image for baseline generation and comparison where possible. For Selenium Grid, account for remote session startup and network dependencies; for Puppeteer, ensure the installed browser matches the library and protocol path.

Performance: screenshot capture time depends on browser startup, navigation, page scripts, network conditions, waits, and image size. Reusing a browser process can avoid repeated startup overhead, while isolated contexts or sessions help prevent state leaking between tests. Parallel runs can reduce wall-clock time but consume more CPU and memory and may make resource contention affect timing. Measure these factors in your own CI environment; the research sources provide no apples-to-apples benchmark.

Cost: Puppeteer and Selenium are open-source browser automation projects, but running them still uses developer time and compute for browsers, CI workers, containers, remote Grid capacity, artifact storage, and maintenance. A hosted screenshot API trades local browser setup for a per-plan service model; compare the cost with the value of managed capture and the exact behavior your workflow needs.

7. Troubleshooting

Symptom Likely cause Fix
Browser fails to launch Missing browser dependencies, incompatible browser/library versions, or an invalid executable path Install the browser dependencies for the CI image, verify the executable, and pin compatible versions.
Navigation times out The page remains active due to polling, analytics, or long requests; the chosen wait condition may be too strict Wait for the specific content needed instead of network quiet, and set a deliberate timeout. Distinguish slow navigation from a page that never reaches the required state.
Screenshot is blank or incomplete Capture occurred before content rendered, navigation failed, or the page requires scrolling or interaction Check the loaded URL and page state, wait for a stable selector, and trigger any required scroll or interaction before capture.
Element screenshot fails Selector did not match, element is hidden, detached, or outside the expected state Wait for visibility, verify the selector, and reacquire the element after navigation or rerender.
Images or fonts are missing Capture ran before assets loaded, or requests failed in the test environment Wait for the relevant assets, inspect network failures, and make the test environment’s asset access reliable.
Snapshots differ on every run Uncontrolled content, animation, font loading, browser version, or host rendering environment Stabilize data and assets, disable irrelevant animation, and pin browser and environment versions.
Chrome works but Firefox does not Protocol or browser feature behavior differs Confirm Puppeteer version (Chrome and Firefox support is documented from v23.0.0), check the BiDi feature list, and use only supported capture parameters.
Grid session fails or is slow Remote node capacity, browser capability mismatch, or network/session setup issue Verify requested capabilities against the target node and check Grid availability and resource limits.

8. Or skip the browser setup

For a managed website screenshot, ScreenshotNeo takes one GET request with a URL and returns an image or PDF. The API supports PNG, JPEG, and WebP, along with options such as full-page capture, element selection, device presets, viewport and retina scale, dark mode, custom CSS and JavaScript, waits, headers, cookies, user agent, caching, resizing, signed links, async jobs, bulk capture, and PDF settings. See the ScreenshotNeo API documentation for parameter 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)
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}`);
  • Cookie banners are accepted like a visitor, and 60+ known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off.
  • Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Response headers report the page verdict and billing state.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents and MCP clients.
  • The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000; every feature is available on every plan.

Sign up for ScreenshotNeo’s free plan and get 1,000 screenshots a month with no card.

9. FAQ

Can Puppeteer and Selenium both capture a full page?

Both document screenshot capture, but support for specific full-page behavior can depend on browser and protocol. Verify the path you will run in CI.

Does either tool compare screenshots automatically?

The screenshot APIs document capture. Baseline storage, image comparison, review, and approved snapshot updates need a separate workflow.

Can I use Puppeteer for Firefox?

Puppeteer documents Chrome and Firefox support from v23.0.0 onward. Its protocol paths differ, so check the feature support for the capture options you need.

Which tool should a team already using Selenium choose?

Keep Selenium if its language bindings, WebDriver setup, and Grid fit the team’s existing execution model. Switching libraries alone does not make screenshot output more reproducible.

What should be pinned for stable screenshots?

At minimum, control the browser version, operating environment, viewport, device scale, headless settings, test data, and the page state at capture time.