The right way to capture a failure screenshot depends on your test runner: Cypress saves screenshots automatically for failures in cypress run; Playwright Test can save one from an afterEach hook with a test-specific path; and pytest-selenium provides a debug-capture hook for saving screenshot data. In every case, make CI retain the screenshot files if you need them after the job ends.
Choose the capture method for your test runner
| Runner | Failure capture | Where to start |
|---|---|---|
| Cypress | Automatic during cypress run, including CI; not automatic during cypress open. |
Check cypress/screenshots after the run. |
| Playwright Test | Save a screenshot in a test or hook, using the test’s output path. | Add a conditional test.afterEach hook. |
| pytest-selenium | The documented pytest_selenium_capture_debug hook can save screenshot/debug information. |
Configure the hook in conftest.py using the documentation for your installed plugin version. |
These are not identical features: Cypress documents a runner-managed failure screenshot for one execution mode, while the Playwright and pytest-selenium approaches described here are hooks or API patterns you configure. Confirm details against the documentation for the version installed in your project.
Cypress: collect automatic failure screenshots
Know when Cypress captures
Cypress automatically captures a screenshot when a test fails during cypress run, whether the run is local or in CI. The automatic failure capture is not enabled for cypress open. Cypress describes its screenshot capability as available in both modes, but that does not mean automatic failure screenshots run in both. See the Cypress screenshots and videos guide.
The default output directory is cypress/screenshots. Cypress clears that folder before a cypress run unless trashAssetsBeforeRuns is set to false. If you need the files after the CI job finishes, configure the pipeline to export that directory as an artifact. Cypress Cloud can also show screenshots from CI runs.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Check or change the setting
The current Cypress screenshot API documents screenshotOnRunFailure as true by default. If you want to make that choice explicit in configuration, use the structure supported by your installed Cypress version:
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
screenshotOnRunFailure: true,
},
})
Set screenshotOnRunFailure: false to disable automatic failure screenshots. Configuration structure has changed across Cypress generations, so use the configuration format documented for your installed version; the Cypress.Screenshot API reference describes the setting.
Take an explicit screenshot in a test
Use cy.screenshot() when you need a deliberate capture at a particular point in the test rather than relying only on the automatic runner capture. Cypress supports capture modes including viewport, fullPage, and runner, where appropriate. Consult the cy.screenshot() API reference for options and behavior. For example:
it('shows the checkout error', () => {
cy.visit('/checkout')
cy.get('[data-testid="submit-order"]').click()
cy.get('[data-testid="payment-error"]').should('be.visible')
cy.screenshot('checkout-error', { capture: 'viewport' })
})
This explicit call runs only if execution reaches it. If an assertion fails before the call, the automatic capture during cypress run is the relevant fallback. Automatic failure filenames are based on the test name and include (failed); retries append attempt labels. See Cypress test retries.
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 problemsInterpret the image carefully
Cypress’s automatic failure screenshot uses a runner capture. The screenshot is taken asynchronously, so the page can change between the failure and the moment the image is captured. Treat it as evidence of the nearby failure state, not a guaranteed frame of the exact instant an assertion failed. An explicit cy.screenshot() placed before a risky action can preserve a known checkpoint, but it does not replace a failure capture.
Playwright Test: save an image from a failure hook
Add a conditional afterEach hook
Playwright Test’s TestInfo API provides an output path specific to a test. Pass that path to page.screenshot() from a test or hook. The condition below compares the final status with the expected status, so it also treats a test expected to fail as successful when it fails as expected.
import { test } from '@playwright/test'
test.afterEach(async ({ page }, testInfo) => {
if (testInfo.status !== testInfo.expectedStatus) {
await page.screenshot({
path: testInfo.outputPath('failure.png'),
fullPage: true,
})
}
})
This is a hook-based example, not a claim that Playwright automatically saves a failure screenshot by default. The Playwright TestInfo API reference documents the test-specific path and retry information. Adapt the sample to your project’s language and installed Playwright version.
Use retries to distinguish attempts
Test hooks and fixtures can access the retry number through testInfo. When a test is retried, consider incorporating that value in the filename if you are not using a test-specific output path, so captures from separate attempts do not overwrite each other. With testInfo.outputPath(), Playwright creates a path in the test’s output area; keep the test and retry context in your artifact naming or reporting if you need to compare attempts.
A screenshot hook also needs a usable page. If the browser or page has already been closed or crashed, screenshot capture can fail too; keep hook errors visible in test output so a failed capture is not mistaken for a missing application failure.
Rank #4
pytest-selenium: use the debug-capture hook
Configure the plugin hook
The pytest-selenium user guide documents pytest_selenium_capture_debug as a hook in conftest.py for saving screenshot and debug information to disk. The precise hook configuration and available debug items can depend on the installed plugin version, so follow the pytest-selenium User Guide for that version rather than copying a hook implementation written for an unknown release.
After wiring up the documented hook, verify that it writes files for a deliberately failing test and identify the destination directory. Then configure your CI job to retain that directory. This separates the two jobs: the plugin produces debug data, while the CI system preserves it after execution.
Make CI keep the screenshots
Export the directory your runner actually uses
A screenshot written inside a build agent’s workspace may disappear when the job ends. Configure artifact collection for the real output path: for Cypress, the default is cypress/screenshots; for Playwright or pytest-selenium, use the output directory or hook destination configured in your project. Artifact configuration is specific to your CI provider, so check its documentation for the exact setting and retention behavior.
Best Value
- Run the test command in the same job that creates the screenshots.
- Collect the screenshot directory even when the test command reports failure; otherwise a failed job may skip artifact upload.
- Give the artifact a useful name that identifies the workflow run or test batch.
- Open a known failing test’s image from the retained artifact to confirm that the path, permissions, and upload-on-failure behavior work.
Do not assume a local folder is persistent storage. Cypress clears its default screenshot folder before a run unless configured otherwise, so preserve artifacts outside the workspace if they must survive later runs.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common problems and fixes
- No Cypress screenshot appears in interactive mode: automatic failure screenshots are for
cypress run, notcypress open. Run the test in the run mode when you need that automatic behavior. - The screenshot folder is empty after a new run: Cypress clears
cypress/screenshotsbefore a run by default. Check that a test failed duringcypress run, and reviewtrashAssetsBeforeRunsif you need existing contents preserved. - The image exists locally but not in CI results: configure artifact upload for the correct directory and ensure it runs even when tests fail.
- A Playwright screenshot is missing: check that the hook condition is reached, that the page remains usable, and that the output path is valid. Use
testInfo.outputPath()for a test-specific destination. - pytest-selenium produces no debug file: confirm that the hook is configured in the project’s
conftest.pyaccording to the installed plugin version, and check the hook’s output destination and available debug items. - The Cypress image differs from the instant of failure: Cypress captures asynchronously, and the page may change in the interval. Add an explicit checkpoint screenshot before the action or state transition that matters.
- Retry images are hard to match to attempts: use Cypress’s attempt labels, or include Playwright retry context in your reporting and filenames when managing paths yourself.
Or skip the browser setup
If your goal is to capture a URL for debugging without configuring browser automation, ScreenshotNeo provides a one-request screenshot API. Its consent cleanup accepts cookie banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to AI agents and MCP clients.
For a test failure, send the failing page URL to the endpoint and save the returned image. This cURL example follows the API’s documented request pattern; replace the URL with the page you want to capture and supply your API key. See the ScreenshotNeo documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://stripe.com
-o shot.webp
The API can return PNG, JPEG, WebP, or PDF. Its other options include full-page capture with lazy images loaded, CSS-selector element capture, device and viewport settings, retina scale, dark mode, PDF layout controls, custom CSS or JavaScript, pre-capture clicks, selector/delay/network-idle waits, request and resource blocking, custom headers and cookies, user agent, authorization, timezone and geolocation, transparent backgrounds, resizing, configurable cache TTL, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage API, and OpenAPI specification. Parameter names used by other screenshot APIs also work, which can ease migration.
Pricing is $0 for 1,000 screenshots per month with no card, then 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. Every feature is on every plan. For a screenshot API, ScreenshotNeo is worth trying first when clean shots and billing only for successful, non-cached captures matter, with the lowest paid plan starting at $5 for 3,000 shots. Visit ScreenshotNeo, or sign up free for 1,000 screenshots a month with no card.
Frequently Asked Questions
Can a screenshot replace the test log or trace?
No. A screenshot records visible page content at capture time; retain the test output and any other diagnostics your runner or CI workflow provides to understand the sequence that led to the failure.
Will a URL screenshot API reproduce the exact state of a failed test?
Not necessarily. A fresh URL capture is separate from the browser session that failed, so it may not include that session’s state, authentication, or timing. Use the runner’s own screenshot when those details matter.
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.
Free tools Windows power users keep installed
One-click scans. No signup required.

