ScreenshotNeo

BlogHow-to

How to Rename Cypress Screenshots

Rename Cypress screenshots with cy.screenshot(), control folders and duplicates, and keep CI artifacts predictable.

By the ScreenshotNeo team1 October 20265 min read

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: true only 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.