Use your browser test framework’s screenshot API: Playwright Test’s toHaveScreenshot() for capture plus visual comparison, Cypress’s cy.screenshot() for images and failure artifacts, or Selenium WebDriver’s screenshot methods for saved image files. First make the page or component reach a known state; then capture the scope you need. A screenshot used to debug a failed test is not automatically a visual regression test: comparison against an approved baseline is a separate step in Cypress and Selenium workflows.
Choose the screenshot you need
Automated browser tests can save the browser-rendered UI without a physical screen-capture device. Pick the capture scope and purpose before adding a screenshot call; each answers a different question.
| Goal | Capture | Useful for |
|---|---|---|
| Diagnose a failed test | Failure screenshot or viewport | Seeing what the user-facing page looked like when the assertion failed. |
| Inspect a component | Element or clipped region | Checking a focused UI area without unrelated page changes. |
| See the current screen | Viewport | Capturing what is visible without scrolling. |
| Inspect page layout | Full page | Reviewing long-page structure; stitching can have fixed/sticky-element quirks. |
| Detect unintended visual change | Screenshot compared with a reviewed baseline | Visual regression testing. Capture alone does not establish whether a difference is acceptable. |
For comparison tests, prefer the smallest scope that covers the intended change. A component-level baseline usually limits unrelated noise; a full-page baseline is appropriate when page-wide layout is what you are validating.
Capture and compare screenshots with Playwright
Playwright Test includes screenshot assertions, so a single assertion can capture and compare a page with a reference image. The first run creates the reference; subsequent runs compare against it. The assertion waits for two consecutive screenshots to match before comparing. The documented API is for the Playwright Test runner.
#1 Best Overall
Page screenshot with a visual assertion
import { test, expect } from '@playwright/test';
test('page visual state', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveScreenshot('page.png');
});
Run the test with your usual Playwright Test command. On the first run, inspect the generated reference and commit it only if it represents the intended design. Later runs report visual differences against that image. PNG is the default; using a filename ending in .webp selects WebP.
Wait for the intended state
Navigation completing does not necessarily mean the UI is ready for a meaningful image. Assert for the state under test—for example, the expected heading or loaded component—before the screenshot assertion. Prefer a state assertion over an arbitrary sleep: fixed delays can be too short on a slow run and waste time on a fast one.
Playwright’s screenshot assertion disables animations by default and can hide the caret. Its options also allow clipping and diff tolerance. Use those controls narrowly: tolerance should absorb insignificant rendering noise, not mask a real layout or styling change. Consult the Playwright visual comparisons documentation for current options and baseline behavior.
Update references deliberately
When a design change is expected, regenerate references with npx playwright test --update-snapshots. Review the diff before committing; wholesale acceptance can turn a real regression into the new baseline. Playwright warns that rendering can vary with host operating system, browser version, settings, hardware, power source, and headless mode. Create and compare baselines in the same environment whenever possible.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsCapture screenshots with Cypress
Cypress provides cy.screenshot() for manual captures. Under cypress run, Cypress also captures screenshots automatically when tests fail; this automatic failure capture does not happen in cypress open. The default screenshot directory is cypress/screenshots. Failure capture can be disabled with screenshotOnRunFailure: false.
Manual capture after an assertion
describe('product page', () => {
it('shows the loaded product details', () => {
cy.visit('/products/example');
cy.contains('Example product').should('be.visible');
cy.screenshot('product-ready');
});
});
This captures evidence after the relevant state is verified. You can also capture on a failure via Cypress’s run-mode behavior rather than adding manual screenshots to every test. See Cypress screenshot command documentation for command details.
Choose viewport, full-page, or runner capture
Cypress screenshot configuration covers a viewport image, a full-page image, or a runner capture that includes the Cypress browser view. A viewport capture records what is currently visible. A full-page capture scrolls and stitches images; fixed or sticky elements can therefore appear more than once. A runner capture is useful when the test runner context itself matters. Check the current Cypress configuration documentation for the applicable setting names.
Use a plugin or service for visual diffs
cy.screenshot() saves an image; it does not itself compare that image to a baseline. Visual regression requires a separate plugin or service. A local workflow stores reference images with the project and handles comparison and rendering consistency in the team’s environment. A managed workflow may provide hosted rendering, baseline management, dashboards, or review steps; exact features and costs vary by provider. Cypress’s visual testing guidance discusses local approaches and integrations including Chromatic, Percy, and Sauce Labs Visual.
Free tools Windows power users keep installed
One-click scans. No signup required.
Before capturing, control API data with fixtures or another repeatable source. If a page contains content that cannot be stabilized, mask only the narrow dynamic region. A broad mask can conceal the very regression the test should detect.
Capture screenshots with Selenium WebDriver
Selenium WebDriver can capture the current browsing context and save a PNG. Method names depend on the language binding; element screenshots are also available in documented bindings. Confirm whether your chosen driver and method capture the window, visible frame, or a particular element rather than assuming identical full-page behavior across bindings.
Python example
from selenium import webdriver
driver = webdriver.Chrome()
try:
driver.get("https://example.com")
driver.save_screenshot("page.png")
finally:
driver.quit()
Remove the single leading space before driver = if copying this block into Python; the executable form is:
Rank #3
from selenium import webdriver
driver = webdriver.Chrome()
try:
driver.get("https://example.com")
driver.save_screenshot("page.png")
finally:
driver.quit()
JavaScript example
const { Builder } = require('selenium-webdriver');
const fs = require('node:fs');
(async () => {
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://example.com');
const image = await driver.takeScreenshot();
fs.writeFileSync('page.png', image, 'base64');
} finally {
await driver.quit();
}
})();
In these Selenium examples, first confirm the page or component is ready before saving the image. The Python binding uses save_screenshot; JavaScript exposes takeScreenshot(), which returns Base64 data that the example writes as a PNG. Selenium’s documented bindings differ, so check the official Selenium screenshot documentation for your language and element/window capture behavior.
Recommended Free Tools
Or skip the browser setup
If you need an image of a public page rather than an in-test browser state, ScreenshotNeo is a website screenshot API and MCP server. It cannot replace a test framework’s access to your test session, fixtures, or assertions, but it can capture a URL in one request. The API accepts parameters used by other screenshot APIs, which can make switching easier. The API documentation lists the request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
- It accepts cookie/consent banners as a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off.
- Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status.
- Its MCP server offers
take_screenshot,get_page_info, andcapture_pdffor Claude, Cursor, and other MCP clients. - The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000. Every feature is on every plan.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
Make screenshot tests stable and useful
Control when the image is taken
Wait for an observable application condition: a result list loaded, a dialog visible, or a loading indicator gone. Then capture. A screenshot taken during a transition can fail intermittently even when the product is correct.
Make test data repeatable
Stub API responses or otherwise provide stable data. Randomized ordering, changing prices, timestamps, rotating promotions, and user-specific content can alter pixels for reasons unrelated to code changes. If a region must remain dynamic, mask or hide that region precisely rather than masking large sections of the page.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Rank #4
- This refurbished product is tested and certified to look and work like new. The refurbishing process includes functionality testing, basic cleaning, inspection, and repackaging. The product ships with all relevant accessories, and may arrive in a generic box
Keep rendering conditions aligned
For baseline comparisons, keep the browser version, operating system, fonts, viewport, device scale, and headless settings consistent. Small differences in font rendering or layout can create pixel diffs. Playwright explicitly notes that host OS, version, settings, hardware, power source, and headless mode can affect rendering; use a consistent environment for both reference generation and comparison.
Choose capture scope and storage intentionally
- Use element or clipped captures for component-level changes.
- Use a viewport image when the visible screen is the subject.
- Use full-page capture for page layout, while checking for stitching artifacts around sticky and fixed elements.
- Save failure screenshots as CI artifacts so a failed run can be diagnosed without rerunning locally.
- Keep comparison baselines versioned and review their changes as code changes, not disposable outputs.
Choose a visual regression workflow
If the goal is only to understand why an assertion failed, framework-native screenshots may be sufficient. If the goal is to detect visual changes, decide who owns the baseline, where rendering occurs, how reviewers approve changes, and what data leaves your infrastructure.
| Decision | Local comparison | Managed visual testing |
|---|---|---|
| Baseline ownership | Images live with the project; the team updates and reviews them. | Provider workflow may manage baselines and approvals. |
| Rendering coverage | Typically the browser and environment configured by the team. | May include hosted rendering across browsers or viewport widths; verify provider specifics. |
| Data location | Comparison can stay within team infrastructure. | Assess what pages, images, or artifacts are sent to or rendered by the provider. |
| Review | CI artifact and diff review. | May include dashboards and pull-request review features. |
| Operations and cost | Team maintains rendering setup and baseline updates. | Potentially less workflow maintenance, usually with service costs; verify current terms. |
Cypress describes local plugins as free and commercial services as paid subscriptions, but that general distinction does not establish the current price or exact features of any individual provider. Confirm those details with the provider before adopting it.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshoot common screenshot-test failures
The screenshot changes on every run
Likely causes: dynamic text or data, an animation, a blinking caret, or inconsistent browser rendering. Fix: wait for the intended state, use stable fixtures, disable or control motion where supported, narrowly mask unavoidable dynamic content, and pin the comparison environment.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →The image is blank or captured too early
Likely cause: navigation completed before the application rendered its target state. Fix: assert the expected content or component is visible before calling the screenshot API; do not rely on a guessed delay as the only readiness check.
Best Value
Cypress has no failure screenshot
Likely causes: the test ran in cypress open rather than cypress run, or screenshotOnRunFailure is disabled. Fix: use run mode for automatic failure captures and check the configured screenshot directory, defaulting to cypress/screenshots.
Cypress full-page images repeat a sticky header
Cause: full-page capture scrolls and stitches sections. Fix: compare a viewport or targeted element if that answers the test question, or account for the stitching behavior when using a full-page image.
A screenshot exists, but no visual diff is reported
Cause: image capture and image comparison are separate capabilities. Fix: add a Cypress plugin or visual-testing integration, or choose a framework assertion such as Playwright Test’s toHaveScreenshot() that performs comparison.
Selenium returns data but no PNG file appears
Cause: some bindings return Base64 image data rather than writing a file. Fix: decode or write that data using the binding’s documented format; verify the driver method and output path.
A changed design causes a wall of failed snapshots
Cause: a legitimate UI change differs from approved references, or a shared rendering change altered many images. Fix: inspect representative diffs, determine whether the change is expected, then update only the appropriate baselines using the framework’s documented process. Avoid automatically accepting every changed image.
Frequently Asked Questions
Does Playwright’s screenshot assertion work with every Playwright setup?
The documented `toHaveScreenshot()` visual assertion is for the Playwright Test runner.
Can Cypress compare screenshots by itself?
No. `cy.screenshot()` captures an image; visual comparison requires a plugin or service.
Do Selenium screenshot methods always capture a full page?
No. Capture scope and full-page behavior depend on the binding and driver; check the documented method for the binding you use.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

