Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If Cypress tests pass locally but fail in GitHub Actions, reproduce the CI environment before changing the tests: cypress run already runs headlessly by default. Compare the browser and version, viewport, operating system, Node and Cypress versions, application build and environment variables, server readiness, and runner resources. First make server startup deterministic, then use the failed run’s logs and artifacts to identify whether the cause is timing, a genuine application defect, a browser mismatch, or resource pressure.

What “headless mode” means in GitHub Actions

Cypress’s cypress run command runs headlessly by default; the GitHub Action README notes this has been the default since Cypress 8.0. Headless is not itself an error or a special CI-only test mode to turn off. It is the browser execution path your CI job uses, and the useful question is what differs between that path and the browser session in which the test passes locally.

Use headed mode locally if it helps you observe a failure, but treat it as a diagnostic aid, not proof that the CI problem is fixed. A headed run changes the execution environment. The meaningful confirmation is that the same test passes in a headless run under conditions sufficiently close to the GitHub Actions job.

Compare these inputs before editing assertions:

  • Browser: name and version, including whether local and CI use the same browser.
  • Display and platform: viewport, operating system, and any device or scale assumptions in the test.
  • Runtime: Cypress, Node.js, package manager, and dependency versions.
  • Application: build command, configuration, environment variables, base URL, and test data.
  • Startup and timing: whether the application is healthy and ready before Cypress begins, and whether the test depends on a fixed delay.
  • Capacity: whether the runner has enough memory for the browser, application, and local server together.

Make the GitHub Actions job reproducible

Start from the maintained Cypress GitHub Action and pin its major version rather than assembling a background server and test command with shell timing. The following pattern builds the app, starts it through the action, waits for a health endpoint, and selects Chrome explicitly. Replace the health URL, build and start commands, and browser with values that match your project.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
name: Cypress Tests
on: push
jobs:
  cypress-run:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v7
      - uses: cypress-io/github-action@v7
        with:
          build: npm run build
          start: npm start
          wait-on: 'http://localhost:8080/health'
          browser: chrome

The action can install dependencies, build and start the application, wait for configured URLs, and then run Cypress. Its current official GitHub Actions guide recommends cypress-io/github-action@v7. The example also pins the checkout action to major version 7 and uses Ubuntu 24.04; adapt those choices to your repository’s supported action and operating-system setup rather than assuming the sample fits every project.

Keep the action, Node version, Cypress version, and project dependency setup aligned. The action README documents v7’s Node 24 runtime and supported Node command-layer versions. Check its compatibility notes when choosing a Node version; don’t infer compatibility merely because installation succeeded on one run. Selecting browser: chrome makes the requested browser explicit, but does not alone pin the browser’s exact build.

Fix server-start races before increasing timeouts

A frequent CI-only failure is that Cypress starts while the app is still building, booting, or returning an error. Cypress’s CI guidance warns that there is no guarantee the server has booted by the time cypress run executes. A command such as npm start & npx cypress run starts processes concurrently; adding sleep 20 only guesses how long startup will take. Neither verifies the app is ready.

  1. Expose a readiness URL. Prefer a health endpoint that returns success only when the application is ready to serve the routes the tests need. A process existing or a port accepting connections may not mean the app has finished initialization.
  2. Configure the action to start and wait. Use the action’s start and wait-on inputs, as in the example. Point wait-on at the real health URL for your app.
  3. Allow enough time for a slow, healthy startup. The action’s default wait-on retry window is 60 seconds. If your build and startup genuinely need longer, increase wait-on-timeout based on observed startup time instead of replacing readiness checks with a fixed sleep.
  4. Inspect the failure if readiness is never reached. Review application process logs and test the configured URL from the runner. Determine whether the server crashed, the endpoint is wrong, the app is bound to a different host or port, or startup simply exceeds the configured window.

A larger wait window helps only when the application is still making progress and becomes healthy within that window. It will not repair a crashing server, an incorrect URL, or a test that targets a different environment.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Match the browser and runtime that CI actually uses

GitHub-hosted runner images include Chrome, Firefox, and Edge on Ubuntu and Windows; macOS runner images also include Safari, according to Cypress’s GitHub Actions guide. The available image contents and browser versions can change as runner images are updated. A test may therefore pass locally against one browser build and behave differently in CI even though both runs use the same browser name.

Record or inspect the browser name and version, Cypress version, Node version, operating system, and viewport in the failing job. Compare those values with the local run. Also verify that the CI build uses the expected environment variables, test account or fixture data, and base URL; differences in app configuration can look like a browser failure.

For stronger browser reproducibility, Cypress’s action documentation recommends using a cypress/browsers Docker image and pinning a specific image tag rather than using latest. A floating tag can change over time, defeating the purpose of the container. Pin a tag that supplies the browser and runtime versions your project needs, and update it deliberately when you intend to change that environment.

Use failure evidence to identify the class of problem

Preserve Cypress screenshots and videos from failed runs as GitHub Actions artifacts. The action README documents artifact upload patterns and supports DEBUG='@cypress/github-action' for action-level diagnostics. These records help answer different questions: an application log can reveal a server crash, an action debug log can explain setup or orchestration, and a Cypress screenshot or video can show what the page displayed when a test failed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the evidence to classify the failure before changing code:

  • Missing or late element: determine whether the app rendered the expected state and whether the test uses Cypress’s normal command retry behavior. Check the relevant request or UI state rather than immediately adding a global delay.
  • Wrong URL or unexpected page: check the configured base URL, environment variables, redirects, and the health endpoint used by the job.
  • Server error: inspect the application process output and confirm the runner can reach the app at the configured host and port.
  • Browser launch or version problem: inspect the selected browser and its version, plus action setup logs; compare them with the local environment.
  • Timeout: decide whether the server was late, the element never appeared, or the runner was overloaded. Those causes need different fixes.
  • Crash or abrupt termination: inspect runner and browser logs for memory pressure or process kills before changing a test assertion.

Cypress Cloud can add shareable reports, screenshots, videos, stack traces, Test Replay, and flaky-test visibility for CI runs. These can be useful when a failure is difficult to reproduce or when a team needs to inspect the sequence leading to a failure. They complement, rather than replace, a deterministic server-start check and a reproducible browser environment.

Fix timing failures without hiding defects

Cypress commands retry according to their behavior and configured timeouts. When an element appears asynchronously, write the test to wait for the condition that matters, such as a UI element becoming visible or a request completing, rather than assuming that a fixed number of seconds will always be enough. A targeted wait makes the dependency visible and avoids slowing every test.

Do not respond to every CI timeout by multiplying global timeouts. A longer timeout can mask a deterministic defect, a request that never completes, or a test targeting the wrong page; it can also make real failures take longer to report. Increase a timeout only when evidence shows the expected operation is valid but needs more time under the intended runner conditions, and scope the change as narrowly as possible.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Check runner resources when logs point to contention

Cypress notes that hardware requirements depend on the memory needed by the browser, the application under test, and the local server. If logs show out-of-memory errors, browser crashes, or severe contention, reduce parallel load or move to a runner with more memory after confirming the symptom. Simply buying more capacity is not a substitute for checking whether a process is leaking, a test is starting excessive work, or concurrent jobs are competing for the same resources.

Balance reliability against execution cost: more parallel work can shorten elapsed time but raises concurrent resource demand, while a larger runner may cost more. Change one factor at a time and compare the result with the failure evidence so the fix addresses the observed bottleneck.

Troubleshoot common GitHub Actions failures

Symptom Likely cause to verify Next action
Cypress begins before the app responds Server startup race or health URL not ready Use the action’s start and wait-on; inspect server logs and runner access to the health URL.
Wait-on expires but the app eventually works Healthy startup exceeds the 60-second default retry window Measure startup and set a suitable wait-on-timeout; retain the readiness check.
Test passes locally but renders a different page in CI Different base URL, environment variables, test data, or browser Compare job configuration and browser details with the local run; preserve screenshots and logs.
Only some runs time out on UI elements Unstable synchronization, variable response time, or contention Wait for the required condition, inspect the failed-run artifacts, and check resource evidence.
Browser crashes or job is killed Possible memory pressure or runner resource contention Check logs; reduce parallel load or use a higher-memory runner if the evidence supports it.
Failure appears only after runner-image changes Browser or system environment drift Compare versions; consider a pinned cypress/browsers image tag.
Headed local run passes while CI still fails The headed run does not reproduce CI’s headless environment Validate with a headless run using CI-like browser, viewport, versions, and app configuration.

Or skip the browser setup

For a separate screenshot of a deployed page, ScreenshotNeo offers a one-request alternative to configuring a browser capture yourself. It is not a replacement for Cypress’s test runner, assertions, or CI failure artifacts: use Cypress to diagnose the test, and use this API when you also need a clean image of a URL.

For this example, swap in the URL you want to capture and your ScreenshotNeo API key. See the ScreenshotNeo documentation for request options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000 shots. Learn about ScreenshotNeo, or sign up for 1,000 free screenshots a month with no card.

FAQ

Does cypress run open a visible browser window in GitHub Actions?

No. It runs headlessly by default; select headed mode only when you specifically need that diagnostic view.

Is there a published failure rate for Cypress headless tests in GitHub Actions?

No general failure-rate statistic for this specific problem is established in the cited official Cypress materials.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.