How to Capture Screenshots in Cypress on CI
Cypress captures screenshots on test failure by default. Learn how to keep them as CI artifacts, capture deliberate checkpoints, and troubleshoot missing files.
Cypress automatically captures a screenshot when a test fails during cypress run, including on CI. By default, it saves the image under cypress/screenshots. To retrieve the file after the job finishes, configure your CI provider to upload that folder as an artifact, and make sure the upload step runs even when the test command fails. You can also use Cypress Cloud to view screenshots from recorded CI runs.
For a screenshot at a specific point in a test, call cy.screenshot() after the page reaches the state you want to inspect. The rest of this guide covers configuration, artifact retrieval, deliberate captures, and common failure cases.
1. Confirm Cypress is configured to save screenshots
Failure screenshots are enabled by default during cypress run. Check your Cypress configuration if files are missing, especially if the project has customized screenshot settings.
// cypress.config.js
const { defineConfig } = require('cypress');
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
return config;
},
},
screenshotOnRunFailure: true,
screenshotsFolder: 'cypress/screenshots',
trashAssetsBeforeRuns: true,
});
The defaults are screenshotOnRunFailure: true, screenshotsFolder: 'cypress/screenshots', and trashAssetsBeforeRuns: true. Cypress clears the screenshots folder before a run by default. If you set a custom folder, use that same path in the CI artifact-upload step.
2. Run Cypress in CI and upload the screenshot folder
Run Cypress with cypress run or your provider’s Cypress integration. Then configure the provider to upload cypress/screenshots as a job artifact. Put the upload step after the Cypress step and configure it to run when the test step fails; otherwise, the job can end before failure screenshots are retained.
Artifact action syntax, retention settings, and failure-condition syntax differ by CI provider and can change over time. Use the provider’s current documentation for the exact workflow configuration. Cypress maintains a GitHub Action and documents a GitHub Actions workflow; follow its current guide for action versions and setup.
- Make sure the CI job starts the application and waits until it is ready before running Cypress.
- Run the Cypress tests with
cypress run. - Configure an artifact upload for the configured
screenshotsFolder. - Set the upload step to run after a failed Cypress step as well as a successful one.
- After the job finishes, download the artifact from the CI run summary.
Cypress clears the screenshot folder at the beginning of a run when trashAssetsBeforeRuns is enabled. This keeps old images from being mistaken for current results. Set it to false only if retaining files across runs is intentional, and account for stale files in your artifact.
3. Capture a deliberate checkpoint with cy.screenshot()
Use cy.screenshot() when a useful image should be created even if the test passes, or when you want to inspect a particular state before a later action. Establish the expected state first, then capture it.
describe('checkout', () => {
it('shows the order confirmation', () => {
cy.visit('/checkout');
cy.get('[data-cy=place-order]').click();
cy.get('[data-cy=confirmation]').should('be.visible');
cy.screenshot('checkout-confirmation', {
capture: 'viewport',
});
});
});
Manual screenshots default to fullPage capture. Set capture to viewport for the visible browser area or runner to include Cypress browser and command-log context. You can pass a name and other supported options to cy.screenshot(); consult the [Cypress screenshot API](https://docs.cypress.io/api/commands/screenshot) for the complete current option list.
Screenshot capture is asynchronous. Cypress documents that it takes around 100 ms, during which the application can change, so the resulting image might not show the exact instant the command was issued. Wait for the UI state you need before calling the command. Full-page capture scrolls and stitches the page; fixed and sticky elements may appear more than once.
4. Choose how to retrieve CI screenshots
| Method | Use it when | Check |
|---|---|---|
| CI job artifact | You want files downloadable from the existing CI run. | Upload the correct screenshots folder, run the upload after failures, and check the provider’s retention settings. |
| Cypress Cloud | Your team records CI runs to Cypress Cloud and wants screenshots available with the run. | Confirm that recording is configured and reviewers have access. Cypress documents viewing CI screenshots in Cloud. |
These routes serve different retrieval workflows. Artifacts keep files with the provider’s job; Cloud presents screenshots with recorded runs. Whether Cloud is available depends on your team’s recording setup and access. Provider artifact behavior and retention depend on the workflow and provider configuration.
5. Troubleshoot missing or unexpected screenshots
| Symptom | Likely cause | Fix |
|---|---|---|
| No failure screenshot appears | screenshotOnRunFailure is disabled in configuration or through Cypress.Screenshot.defaults(), or the run did not execute in cypress run. |
Enable failure screenshots and confirm the CI command runs Cypress in run mode. |
| The artifact has no images, although the test failed | The upload step was skipped after the test command returned a failure, or its path does not match screenshotsFolder. |
Configure upload to run after failure and match the configured folder exactly. |
| Old screenshots are missing | trashAssetsBeforeRuns clears the screenshots folder before a run by default. |
Download artifacts from the relevant run. Set cleanup off only when retaining existing folder contents is required. |
| A manual screenshot has a different name | Automatic failure captures use the generated test name with (failed) appended. Duplicate manual names get numeric suffixes unless overwrite is enabled. |
Look for the generated filename or use distinct manual names; review the screenshot API’s overwrite option if replacement is intended. |
| The image shows a later or earlier UI state | Capture is asynchronous and the application may change before it completes. | Wait for the target selector or visible state to be ready before calling cy.screenshot(). |
| Sticky headers or buttons appear repeatedly | Full-page capture scrolls and stitches the page. | Use capture: 'viewport' when a single viewport is the relevant evidence, or account for repeated fixed elements in full-page output. |
6. Keep screenshot artifacts manageable and reliable
- Upload only the needed run output. Cypress clears the folder by default, which helps avoid bundling older files.
- Keep the artifact step independent of test success. Failure screenshots are most valuable when the Cypress command fails.
- Match the path in both places. A custom
screenshotsFolderrequires the artifact configuration to use the same location. - Use deliberate captures sparingly. Add manual screenshots at checkpoints that help diagnose the test, and give them distinct names.
- Choose an access and retention path. Artifact retention is controlled by the CI provider; Cloud access depends on recording and team access.
Screenshots are regenerated test assets and are commonly excluded from source control. CI artifacts or Cypress Cloud are intended retrieval paths when the team needs to inspect them later. Cypress’s approximate capture duration is an implementation note, not a performance guarantee. This workflow adds image files to the run output; actual storage and retention costs depend on your CI provider’s artifact policy.
Or skip the browser setup
If you need a screenshot of a public page outside the Cypress test run, [ScreenshotNeo](https://screenshotneo.com) provides a website screenshot API and MCP server. One GET request returns an image or PDF. See the [ScreenshotNeo API documentation](https://screenshotneo.com/docs/) 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
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}`);
ScreenshotNeo accepts cookie and consent 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, blank pages, timeouts, and failed loads are never billed, and cache hits cost nothing. Responses identify the page verdict and billing status in headers. Its MCP server lets Claude, Cursor, and other MCP clients take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up free for 1,000 screenshots a month, with no card required.
Frequently asked questions
Does Cypress take screenshots automatically in CI?
Yes. During cypress run, Cypress captures screenshots on test failure by default, unless failure screenshots have been disabled.
Where are Cypress screenshots saved?
The default directory is cypress/screenshots. A project’s screenshotsFolder setting can change it.
Does Cypress save screenshots from passing tests?
Not automatically as failure screenshots. Add cy.screenshot() at the checkpoint you want to retain.
Do I need Cypress Cloud to get screenshots from CI?
No. You can upload the screenshot folder as a CI artifact. Cloud is another option when the run is recorded and your team has access.
Should screenshots be committed to Git?
They are commonly treated as generated test assets and retained as CI artifacts when needed, rather than committed to source control.


