How to Rename Cypress Screenshots
Rename Cypress screenshots with cy.screenshot(), control folders and duplicates, and keep CI artifacts predictable.
Use cy.screenshot('your-file-name'). The string becomes the screenshot filename beneath Cypress’s screenshots folder and the path associated with the spec.
cy.screenshot('checkout-confirmation')
This creates a PNG named checkout-confirmation.png. For a hierarchy, include slashes:
cy.screenshot('checkout/payment-success')
Cypress creates the nested directories below the screenshots folder automatically.
How Cypress builds the final path
By default, Cypress writes screenshots to cypress/screenshots. The effective path is based on the screenshots folder, the adjusted spec path, and the name you provide:
{screenshotsFolder}/{adjustedSpecPath}/{name}.png
The spec path is adjusted using the project’s common ancestor directories. Keep specs under a consistent common directory when you need predictable artifact paths.
Rename a screenshot in a test
describe('checkout', () => {
it('shows the payment success state', () => {
cy.visit('/checkout/success')
cy.screenshot('checkout/payment-success')
})
})
The argument is relative to the screenshots folder. It can be a simple filename or a slash-delimited path. Cypress adds the .png extension.
Replace an existing screenshot intentionally
If the same name is generated more than once, Cypress appends a numeric suffix such as (1) by default. That preserves earlier captures. Pass overwrite: true when a stable single artifact is the goal:
cy.screenshot('checkout-confirmation', {
overwrite: true,
})
Use overwrite only when replacement is expected. Otherwise, the suffix helps you detect multiple captures that would have collided.
Use the screenshot options that affect naming workflows
The name is the first argument; options are the second argument. A callback can report the resolved path after Cypress has saved the image:
cy.screenshot('checkout-confirmation', {
onAfterScreenshot(_element, props) {
console.log(props.path)
},
})
props.path is authoritative. It is safer for uploads, renaming scripts, and other post-processing than reconstructing the path yourself, especially when specs move or Cypress changes common-ancestor calculations.
Change the screenshots root directory
Set screenshotsFolder in cypress.config.js or cypress.config.ts:
import { defineConfig } from 'cypress'
export default defineConfig({
screenshotsFolder: 'artifacts/cypress/screenshots',
})
This changes the root for screenshots created by cy.screenshot() and screenshots Cypress creates after failed tests. It does not remove the spec-based path beneath that root.
Failure screenshots, retries, and CI
Automatic screenshots after failures
During cypress run, Cypress automatically captures a screenshot when a test fails. Failure names follow the normal test-based pattern with (failed) appended. Disable this behavior with:
import { defineConfig } from 'cypress'
export default defineConfig({
screenshotOnRunFailure: false,
})
This setting controls automatic failure captures; it does not disable explicit cy.screenshot() calls.
Retries
When a test is retried, Cypress adds an attempt suffix to screenshots for each retry attempt. A test title that stays the same can therefore produce different filenames in CI.
Cleanup before a run
Before cypress run, Cypress clears the entire screenshots folder by default, including nested files. Preserve files between runs with:
import { defineConfig } from 'cypress'
export default defineConfig({
trashAssetsBeforeRuns: false,
})
Choose this only when your CI workflow needs previous artifacts. Otherwise, cleanup prevents stale images from being mistaken for output from the current run.
Get the resolved path from Node events
For centralized uploads or artifact processing, use Cypress’s after:screenshot and after:spec Node events. The screenshot event receives the resolved file information after the image is written:
import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
setupNodeEvents(on) {
on('after:screenshot', (details) => {
console.log('Saved screenshot:', details.path)
})
on('after:spec', (spec, results) => {
console.log('Finished spec:', spec.relative)
console.log('Screenshot results:', results.screenshots)
})
},
},
})
Use the callback or Node event when an external process needs the actual path. Do not assume a path from the test title alone: spec layout, retries, failure suffixes, and cleanup settings can change what is present on disk.
Practical naming patterns
| Goal | Example | Result |
|---|---|---|
| One stable artifact | cy.screenshot('checkout-confirmation', { overwrite: true }) |
Replaces the same named file |
| Keep every capture | cy.screenshot('checkout-confirmation') |
Later collisions receive (1), (2), and so on |
| Group by feature | cy.screenshot('checkout/payment-success') |
Creates nested folders |
| Upload exactly what Cypress wrote | onAfterScreenshot(_el, props) { ...props.path... } |
Uses the resolved path |
Troubleshooting
The file has a number such as (1)
Cause: the same effective name was saved more than once.
Fix: give each capture a unique path, or pass overwrite: true when replacement is intentional.
The screenshot is not in the directory you expected
Cause: Cypress combines screenshotsFolder, the adjusted spec path, and your name.
Fix: inspect the resolved path through onAfterScreenshot or after:screenshot, then adjust screenshotsFolder if the root should change.
Failed-test screenshots have unexpected names
Cause: automatic failure captures use test-based names and append (failed). Retries add attempt suffixes.
Fix: disable automatic captures with screenshotOnRunFailure: false, or treat failure artifacts separately from explicitly named screenshots.
Previous screenshots disappeared in CI
Cause: Cypress clears the screenshots folder before cypress run by default.
Fix: set trashAssetsBeforeRuns: false when retaining files across runs is required, and clean them with your CI job when they are no longer needed.
My upload script cannot find the image
Cause: the script reconstructed a path instead of using Cypress’s resolved path.
Fix: pass props.path from onAfterScreenshot or consume the after:screenshot event.
Performance, reliability, and cost notes
- Use explicit names for screenshots that are consumed by other jobs; this avoids parsing suite and test titles.
- Use slash-delimited names to keep large suites navigable without changing the project-wide screenshots root.
- Use
overwrite: trueonly for intentionally stable outputs. Unique names preserve evidence from repeated states and retries. - Keep generated screenshots, videos, and downloads out of source control when they are reproducible build artifacts.
- In CI, decide whether cleanup should happen before every run. Retaining old files improves forensic access but increases storage and can create stale-artifact confusion.
- For uploads, process the path supplied by Cypress after the write completes rather than racing the filesystem.
Or skip the browser setup
If you need a screenshot from a URL instead of a Cypress test, ScreenshotNeo provides a single GET request. Its API documentation covers the available capture options.
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}`);
Before the capture, ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and each response reports the result in X-Page-Verdict and X-Billed headers. Its MCP server lets AI agents such as Claude and Cursor call take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Create a free ScreenshotNeo account to get started.
FAQ
Can I rename a screenshot after Cypress saves it?
Yes, but naming it correctly in cy.screenshot() is more reliable. If another process must rename or upload it, use the resolved path from onAfterScreenshot or after:screenshot.
Can the screenshot name include folders?
Yes. Slashes in the name create nested directories below the spec-related screenshot path.
What extension does Cypress use?
Cypress writes PNG screenshots and adds the .png extension to the supplied name.
Why is a failed screenshot different from my explicit name?
Failure captures are generated automatically from the test name and receive a (failed) suffix. They are separate from explicitly named cy.screenshot() calls.


