How to Manage Flaky Tests in Cypress
Diagnose intermittent Cypress failures, make tests more deterministic, and use retries and CI evidence without letting retries hide the root cause.
A flaky Cypress test produces different results when the code and intended behavior have not changed. A test that fails once and passes on retry is still flaky: the retry reveals inconsistent behavior; it does not repair the cause.
Start by identifying the exact failed attempt, then make the test independent, wait for observable application state, and compare failing and passing CI evidence. Use retries to measure and manage instability while you investigate—not as a substitute for fixing it.
1. Confirm what is flaky
Record the spec and test title, failing command or assertion, browser, run mode, environment, CI job, and whether a later attempt passed. Check whether the failure happens only in CI, only after another test, or only under a particular data or network condition. A retry that changes the outcome is a useful signal to investigate. Cypress retries are disabled by default. Cypress documents how retries work and how to configure them.
Reproduce the symptom in both contexts when possible: run the test alone and as part of its normal suite. A test that passes alone but fails in the suite may depend on shared state, ordering, or setup performed elsewhere.
2. Make tests independent and control state
Cypress advises that “Tests should always be able to be run independently from one another and still pass.” End-to-end test isolation is enabled by default, but clearing browser state does not automatically reset a database, shared account, remote service, or other server-side fixture. See Cypress’s guidance on organizing tests.
- Give each test its own records or use unique test data; avoid depending on records left by earlier tests.
- Reset or seed external state through a controlled setup path. Make setup safe to run again.
- Do not rely on test order, a shared logged-in browser, or a one-time setup step to make a test pass.
- Run the test individually and in the suite to expose order-dependent behavior.
- Use programmatic login when login itself is not the behavior under test, so unrelated UI setup does not add more failure points.
Keep the behavior under test explicit. If a multi-step scenario fails, assertions at meaningful boundaries help show which step stopped producing the expected state.
3. Wait for the state that matters
A fixed delay assumes the application will always become ready within a chosen time. That assumption often breaks under variable CI load or network timing. Prefer Cypress’s retryable queries and assertions: they check for the expected condition over time. When a step depends on an API response, wait for that request and then assert the resulting UI state.
describe('search', () => {
it('shows results after a search completes', () => {
cy.intercept('GET', '/api/search*').as('search');
cy.visit('/search');
cy.get('[data-cy="search-input"]').type('cypress');
cy.get('[data-cy="search-submit"]').click();
cy.wait('@search').its('response.statusCode').should('eq', 200);
cy.get('[data-cy="search-results"]')
.should('be.visible')
.and('contain', 'cypress');
});
});
Adapt the route, selectors, and expected result to the application. The example checks both the response and the user-visible result: a successful request alone does not prove the UI rendered correctly.
Avoid making cy.wait(5000) the routine fix. A delay can mask a race for a while, slow every run, and still be too short on a slower runner. If a specific fixed delay is truly part of the behavior being tested, document why; otherwise wait for a request, selector, or assertion that represents readiness.
4. Reduce selector and interaction fragility
Prefer stable application-provided data-* attributes, such as data-cy, over selectors tied to CSS classes, layout, or incidental text. A styling change should not usually break a behavioral test. Cypress’s best practices cover selector strategy and test design.
- Assert that an element is visible or enabled before an interaction when that is a meaningful precondition.
- Account for asynchronous transitions and animations by asserting the resulting state, not by guessing how long they take.
- Keep tests focused enough that a failure points to one behavior. Reuse setup helpers carefully; shared helpers should not hide state dependencies.
- Stub or control external dependencies when the test is about your application’s behavior, and reserve real integration checks for cases where the external interaction is what you need to validate.
5. Compare failing and passing CI attempts
When a test flakes in CI, inspect the attempt that failed rather than only the final green status. Compare it with a passing attempt on the same code when available. Check the application build and server startup, browser and Cypress configuration, test data, network access, and resource availability. Cypress’s debugging guide discusses race conditions and the value of assertions around important actions and requests.
For recorded Cypress Cloud runs, Test Replay can provide the DOM, network requests, console logs, and element state from an attempt. Cypress Cloud’s Flaky Test Management applies to recorded runs with retries enabled; its detection, analytics, and alerting require a Team plan according to the current Cypress documentation. Cloud is useful when the team needs centralized attempt evidence and flake visibility; local or CI artifacts remain options for teams that do not use it.
6. Configure retries as a signal and policy
Retries rerun the test and its hooks, so they increase execution time and can repeat setup or side effects. Configure a restrained allowance that fits the suite and the team’s release policy, then track tests that pass only after retry. Cypress supports separate run-mode and open-mode retry counts.
// cypress.config.js
const { defineConfig } = require('cypress');
module.exports = defineConfig({
retries: {
runMode: 1,
openMode: 0,
},
});
This is an example configuration, not a universal recommended count. Choose counts based on the cost of another attempt and the signal your team needs. Keep flaky tests visible in reporting or issue tracking, assign an owner, and remove the retry allowance or close the follow-up once the root cause is fixed.
Decide explicitly what a retry-pass means for CI:
- Keep the run green while tracking the flake: useful when teams need delivery to continue, provided the retry is reported and investigated.
- Fail on detected flakiness: useful when a strict reliability gate matters more than avoiding interruption.
Cypress documents experimental strategies that affect how detected flakes influence pass/fail results. These settings can change, so check the current experimental features documentation before adopting one. There is no universally correct retry count or policy.
7. Troubleshooting common causes
| Symptom | Likely cause | What to check or change |
|---|---|---|
| Fails once, passes on retry | A race, variable response time, shared state, or another nondeterministic dependency | Inspect the failed attempt; replace timing guesses with a request or UI assertion; isolate state. |
| Passes alone, fails in the suite | Order dependence, reused records, or setup performed by another test | Run in different suite positions; give the test independent data and repeatable setup. |
| Fails in CI but passes locally | Different build, browser, environment, resource availability, network timing, or test data | Compare runner configuration and failed-attempt evidence; verify the server is ready before the test proceeds. |
| Element not found intermittently | The UI has not reached the expected state, or the selector is coupled to implementation details | Wait for the relevant response or retryable query; use a stable data-* selector. |
| Request wait times out | The route matcher is wrong, the action did not trigger the request, or the service did not respond | Check the intercepted URL and method, verify the triggering action, and inspect network evidence. |
| Assertion passes before the UI is usable | The assertion checks an intermediate condition rather than the behavior the next step needs | Assert the final visible or interactive state required by the next action. |
| Retries make CI much slower | Many tests need repeated attempts, or retrying the whole scenario repeats expensive hooks | Use retries selectively, reduce avoidable setup, and prioritize root-cause fixes for tests that retry. |
| Cloud does not show flake insights | The run may not be recorded, retries may be off, or the plan may not include the relevant management features | Check recorded-run and retry configuration and confirm the current plan requirements in Cypress documentation. |
8. Capture visual evidence of a failing page
A screenshot can help when the failure involves an unexpected page layout or visible overlay. Cypress screenshots are useful evidence, but a screenshot does not explain why the page reached that state; pair it with the failed command, assertion, request, and attempt logs. For reproducible visual inspection of a page, a screenshot API can capture the rendered result. ScreenshotNeo is a website screenshot API and MCP server for developers; its clean captures accept consent banners and remove known consent platforms, newsletter popups, and chat widgets before capture. See ScreenshotNeo.
Or skip the browser setup
Make one GET request to capture a page. Full API options are in the ScreenshotNeo documentation.
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}`);
- Cookie banners, popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are never billed; response headers identify the page verdict and billing status.
- An MCP server lets AI agents use
take_screenshot,get_page_info, andcapture_pdf. - 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan.
Sign up for 1,000 free screenshots a month—no card required.
9. Performance, reliability, and cost
Retries trade execution time for another observation. Since they rerun tests and hooks, a suite with many retrying tests can take longer and repeat setup work. Prefer fixing the source of instability, make setup efficient and repeatable, and use a retry policy that matches the cost of delayed feedback against the risk of accepting an intermittent failure.
Reliability improves when tests have independent data, clear readiness conditions, stable selectors, and enough evidence to identify the failed step. A passing retry alone does not establish that the application is reliable. Review retry outcomes over time and treat repeat flakes as remediation work.
Cypress Cloud can add recorded attempt evidence and flake management for teams that need those capabilities. Evaluate the current plan requirements and fit against the value of centralized replay and analytics. For visual snapshots of a page, ScreenshotNeo charges only for clean shots; its free tier includes 1,000 shots per month, with paid plans starting at $5 for 3,000. Do not treat a page screenshot as a replacement for Cypress’s test-attempt evidence.
10. A practical checklist
- Identify the exact failed test, attempt, environment, and whether a retry changed the result.
- Run it alone and in suite context; remove dependencies on order and shared external state.
- Replace arbitrary waits with retryable queries, assertions, and request waits tied to the behavior.
- Use stable selectors and assert the result needed before each dependent action.
- Compare failed and passing CI attempts, including server, browser, build, data, and network details.
- Set retries deliberately, monitor retry-passes, and assign root-cause fixes.
- Choose whether a detected flake should leave CI green or fail the run, and document that policy.
FAQ
Does a test that passes on retry count as fixed?
No. The changed outcome is evidence of nondeterminism. Find and correct the dependency that made the result vary.
Are Cypress retries enabled by default?
No. Cypress retries are off by default; configure run-mode and open-mode behavior deliberately.
Should I use a fixed wait to stop a flaky test?
Usually not. Wait for the request or application state the next step actually depends on, then assert that state.
Can test isolation prevent every state-related flake?
No. Browser context isolation does not automatically reset databases, shared accounts, remote services, or other external state.
Do I need Cypress Cloud to manage flakes?
No. You can investigate with your own CI artifacts and logs. Cloud provides replay and management features for recorded runs; confirm the current plan requirements if you need its analytics or alerting.


