ScreenshotNeo

BlogHow-to

How to Run Cypress End-to-End Tests in GitLab CI

Add Cypress end-to-end tests to GitLab CI with a working pipeline, browser choices, artifacts, caching, and optional Cypress Cloud parallelization.

By the ScreenshotNeo team4 October 20269 min read

Put a .gitlab-ci.yml file at the root of your repository, install dependencies, start the application, and run Cypress. A single-worker run does not need Cypress Cloud. For Cypress’s documented multi-machine parallelization, GitLab must start multiple workers and Cypress Cloud must record and coordinate the run.

Start with this small pipeline if your project has an e2e npm script and Cypress can find a suitable browser and runtime in the job environment:

stages:
  - test

test:
  image: node:latest
  stage: test
  script:
    - npm ci
    - npm start &
    - npm run e2e

This mirrors the basic setup in the Cypress GitLab CI guide. Treat it as a starting point: replace node:latest with a maintained, pinned Node image appropriate for your application, ensure the app is ready before Cypress starts, and use a browser image when you need a specific browser. See the ScreenshotNeo API documentation for the screenshot API option later in this guide.

1. Check the project before adding the job

The pipeline can only run commands and tests your repository defines. Before adding the job, confirm these points:

  • package.json has the test script you plan to call, such as e2e, or use npx cypress run directly.
  • Cypress is a project dependency and is installed by npm ci from the lockfile.
  • The app can start in the CI job and Cypress uses the correct base URL.
  • The chosen image has the Node runtime, Cypress dependencies, and browser required by your configuration.
  • Any test credentials or service configuration come from CI variables rather than committed secrets.

For example, a package script can make the CI command explicit:

{
  "scripts": {
    "start": "your-app-start-command",
    "e2e": "cypress run"
  }
}

Use your actual application start command and scripts. The example names are not requirements imposed by GitLab or Cypress.

2. Make the server ready before Cypress runs

The command npm start & runs the server in the background, but it does not prove the server is ready. Cypress may begin while the application is still starting, causing intermittent connection errors. Add a readiness check that waits for your app’s URL before running tests. Choose a tool and command that fit your project; the Cypress GitLab example does not require one particular readiness utility.

Keep the start and test commands in the same job for the simplest setup. If your app needs a build step, environment variables, a database, or other services, add those prerequisites to the pipeline and make the app’s test URL match the CI environment.

3. Choose a browser image and pin the environment

A generic Node image is suitable only if it also provides the browser and system dependencies Cypress needs. If the tests must run in Chrome or Firefox, choose an appropriate Cypress browser image and pass that browser to cypress run. Cypress’s GitLab documentation demonstrates cypress/browsers:22.15.0 with Firefox:

stages:
  - test

test:
  image: cypress/browsers:22.15.0
  stage: test
  script:
    - npm ci
    - npm start &
    - npx cypress run --browser firefox

The version here is a documented example, not a promise that it is the best current tag for every project. Select and maintain an image version that provides your required Node and browser versions. Pinning the image makes the CI environment explicit and helps avoid unexpected changes when a floating tag moves. Confirm current image tags and browser support in the Cypress guide when you update the environment.

Setup Use it when Trade-off
Node image Your required Cypress runtime and browser dependencies are available in the image. Verify browser and system dependencies yourself; a generic Node tag does not select Chrome or Firefox for you.
Cypress browser image You want a consistent environment with an installed browser such as Chrome or Firefox. Choose and update a suitable image tag as part of maintaining the pipeline.

4. Cache dependencies and retain test evidence

GitLab cache and artifacts serve different purposes. A cache can speed later jobs by reusing dependency paths. Artifacts preserve files produced by the job, such as Cypress screenshots and videos, so they remain available for debugging. Do not rely on a cache as the authoritative record of failed-run evidence.

This example follows the cache and artifact shape in Cypress’s GitLab guide. Adjust paths for your package manager and Cypress output settings, and choose an expiry that matches your debugging needs:

cache:
  key: "${CI_COMMIT_REF_SLUG}"
  paths:
    - node_modules/
    - .npm/

test:
  image: cypress/browsers:22.15.0
  stage: test
  script:
    - npm ci
    - npm start &
    - npx cypress run --browser chrome
  artifacts:
    when: always
    paths:
      - cypress/videos/**/*.mp4
      - cypress/screenshots/**/*.png
    expire_in: 1 day

when: always asks GitLab to retain matching artifacts even when the job fails. The paths must match the output locations used by your Cypress configuration. Set expire_in deliberately: short retention uses less storage but leaves less time to inspect failures; longer retention preserves evidence longer.

A cache is an optimization, so the job should still install correctly when no cache is available. Keep npm ci tied to the committed lockfile. The example cache key scopes reuse to a branch slug; choose a key strategy that fits your branch and dependency workflow.

5. Decide whether Cypress Cloud parallelization is worth it

Begin with one worker. Increase concurrency when measured suite duration justifies the additional CI capacity and Cypress Cloud setup. In GitLab, parallel provisions multiple copies of a job. Cypress’s --parallel flag asks Cypress Cloud to coordinate spec distribution across those machines. The documented workflow also uses --record, so this multi-machine form requires recorded runs and Cypress Cloud.

A representative configuration is:

stages:
  - test

test:
  image: cypress/browsers:22.15.0
  stage: test
  parallel: 5
  script:
    - npm ci
    - npm start &
    - npx cypress run --record --parallel --browser chrome --group UI-Chrome

Set up the Cypress project for Cloud recording and configure its record key as a protected CI variable according to current Cypress secret-handling guidance. Do not put a real record key in repository source. Keep the GitLab commit SHA available and reliable if you enable Cypress Cloud’s GitLab integration; the integration documentation says the user enabling it needs GitLab administrator access.

Understand what each flag does:

Setting Purpose Needs Cloud?
GitLab parallel Starts multiple copies of the job. GitLab setting itself does not coordinate Cypress specs.
--browser Selects a browser installed in the job environment. No.
--record Records the test run to Cypress Cloud using project setup and credentials. Yes.
--parallel Requests Cloud-coordinated distribution of recorded specs across machines. Yes; use with recorded runs.
--group Labels related recorded runs, such as browser-specific runs. Used to organize Cloud recorded results.

Cypress distributes whole spec files, uses historical duration information to balance assignment, and does not guarantee spec order. Make each spec independent of other specs and avoid relying on a particular order. Specs with broadly similar durations tend to distribute more evenly. If one spec takes most of the time, adding workers may not reduce the wall-clock duration much.

Parallel execution has a cost: each GitLab worker consumes CI capacity, and Cloud recording and related features are subject to Cypress’s current plan and product terms. Measure the end-to-end time and worker usage before increasing parallel. Cypress’s Kitchen Sink example reports a serial run of 1:51 becoming 59 seconds on two machines, a 53% reduction; that is a vendor example, not a forecast for your suite. Browser startup, video encoding, and short specs can reduce the benefit.

6. Keep the pipeline maintainable

  1. Start with one worker. Get installation, app startup, browser selection, and the test command stable first.
  2. Use an explicit image version. Keep the runtime and browser environment consistent, then update it deliberately.
  3. Retain useful failure output. Confirm that screenshots and videos are written to the paths listed as artifacts.
  4. Use CI variables for secrets. Protect recording keys and application credentials; do not commit them in YAML.
  5. Scale after measuring. Compare the single-worker duration with parallel duration and account for available GitLab workers and Cloud requirements.
  6. Keep specs independent. Parallel assignment may change which worker runs a spec and its run order.

Or skip the browser setup

If your CI task is to capture a website screenshot rather than exercise application behavior, ScreenshotNeo provides a screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. For example, this cURL request saves a WebP screenshot; see the API documentation for options:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Cookie banners and consent prompts, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers report the page verdict and billing status. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card required.

Troubleshooting

Symptom Likely cause Fix
npm run e2e says the script is missing. The project does not define an e2e script, or the job uses a different name. Add the script to package.json or run npx cypress run directly.
Cypress cannot connect to the application. The background server has not finished starting, exited, or is listening at another URL or port. Check the server logs and base URL; add a readiness check before Cypress starts.
Cypress cannot find or launch the requested browser. The selected image does not contain that browser, or its environment does not provide the required runtime dependencies. Use an appropriate Cypress browser image and pass a browser name available in that image.
Parallel job fails before tests are distributed. The project is not configured for Cloud recording, the record key is absent or invalid, or --parallel was used without recorded runs. Configure Cloud recording and provide the key through CI variables; otherwise remove the Cloud parallelization flags and use one worker.
Parallel workers run specs in an unexpected order. Parallel assignment does not guarantee spec order. Remove cross-spec dependencies and make each spec set up the state it needs.
Artifacts are missing after a failed job. The configured paths do not match Cypress output, or the job does not collect artifacts on failure. Check Cypress output settings and paths; use when: always if failure evidence should be retained.
Pipeline is still slow with several workers. Specs may be short, uneven in duration, or dominated by startup and encoding overhead; workers may also queue for capacity. Measure the suite, balance spec durations where practical, and compare saved time with the cost and availability of extra workers.
Dependencies reinstall every run. The cache is unavailable, its key changes, or its paths do not match the package manager configuration. Review the cache key and paths. Keep the pipeline correct without a cache because caches are reusable optimization, not guaranteed storage.

FAQ

Can I run Cypress in GitLab CI without Cypress Cloud?

Yes. A single-machine job can run cypress run locally in CI without recording. The documented Cypress multi-machine parallelization workflow uses Cloud recording and coordination.

Does GitLab’s parallel setting split Cypress specs by itself?

No. It starts multiple job instances. Cypress Cloud’s recorded parallel mode coordinates which spec files each worker runs.

Can I run both Chrome and Firefox?

Yes, if the chosen job environment has the requested browser. Run separate browser-specific jobs or groups and pass the corresponding --browser value.

Should I cache node_modules?

You can use the documented cache pattern, but keep npm ci as the reproducible install step and make sure the job works when the cache is absent.

Do parallel specs run in a fixed order?

No. Design tests so that one spec does not depend on another spec having run first.

Sources