Cross-Browser Testing with Cypress: A Modern Guide
Run Cypress tests across Chrome, Firefox, Edge, and experimental WebKit. Choose a practical browser matrix, configure CI, and troubleshoot browser-specific failures.
Run the same Cypress suite in each browser you want to support by installing that browser in your local or CI environment and selecting it with cypress run --browser <browser>. A practical starting matrix is Chrome and Firefox, plus Edge if it matters to your users. Cypress also offers experimental WebKit support, but that run has documented limitations and is not a guarantee of equivalent Safari coverage.
Cypress supports Chrome-family browsers, Firefox, and WebKit. Its documentation says it officially supports the latest three major versions of Chrome, Firefox, and Edge. Browser support and minimum versions can change, so check the cross-browser guide and browser-launch reference when setting up or updating a matrix.
1. Choose a browser matrix that matches your support promise
Cross-browser testing is most useful when it checks the browser families and versions your application promises to support. More jobs can increase confidence, but they also add runtime, maintenance, and CI cost. Cypress does not prescribe one universal matrix.
| Browser choice | When it fits | What to account for |
|---|---|---|
| Chrome | A strong baseline for applications whose users include Chrome-family browsers. | For reproducible CI runs, Cypress recommends Chrome for Testing where possible. Its binaries are versioned and do not auto-update. |
| Firefox | When Firefox is in your supported-browser promise or important to your audience. | Use a Cypress-launchable version. The current reference says Firefox versions earlier than 140 cannot be launched. Cypress 15.0.0 through 15.18.1 used a lower floor of Firefox 135. |
| Edge | When you support or need coverage for Edge users. | Cypress officially supports the latest three major versions. Preview channels are available in the browser reference, but a preview run is not the same as testing a supported stable release. |
| WebKit | As an additional signal for behavior in Safari’s browser engine. | Cypress labels WebKit experimental. It has known limitations, including no cy.origin() support, Test Replay incompatibility, and a disabled forceNetworkError option in cy.intercept(). |
Check the current browser reference before pinning versions: browser support floors and Cypress behavior are release-sensitive. Do not make experimental WebKit a required release gate until your suite works with its limitations and your team accepts the maintenance implications.
2. Install Cypress and the browsers
In an existing project with Cypress installed, check the available browser names and versions with:
npx cypress info
Install the browser binaries in the same machine or CI image that runs Cypress. Cypress can only launch a browser it detects in that environment. For a local interactive run, open the Cypress app and choose a detected browser. For repeatable CI runs, use the command line and pin the browser image or binary version where your environment allows it.
Use Chrome for Testing where practical for CI reproducibility. Ordinary Chrome installations may update independently, so an otherwise unchanged test environment can begin running against a different browser version.
3. Run Cypress in each browser
The browser option selects the browser for that run. These commands assume Cypress is installed in the project and each named browser is installed and detectable:
# Chrome (or Chrome for Testing if detected under this name)
npx cypress run --browser chrome
# Firefox
npx cypress run --browser firefox
# Edge
npx cypress run --browser edge
# Experimental WebKit, if available in this Cypress setup
npx cypress run --browser webkit
To run a specific spec in each browser, add the same spec selector to each command:
npx cypress run --browser chrome --spec "cypress/e2e/checkout.cy.js"
npx cypress run --browser firefox --spec "cypress/e2e/checkout.cy.js"
npx cypress run --browser edge --spec "cypress/e2e/checkout.cy.js"
Use the browser name Cypress reports for your installed binary. The browser-launch reference includes Chrome for Testing, Chrome and its channels, Chromium, Edge and preview channels, Firefox variants, deprecated Electron, and experimental WebKit. Names and availability depend on the installed browser and Cypress version; consult the reference rather than assuming every environment recognizes every alias.
4. Make a test repeatable across browsers
Cypress runs the same spec files, but browsers differ in rendering, APIs, security behavior, and timing. Keep assertions focused on user-visible behavior and avoid relying on incidental details such as exact font rasterization or browser-specific timing.
// cypress/e2e/checkout.cy.js
describe('checkout', () => {
it('lets a customer complete checkout', () => {
cy.visit('/checkout');
cy.get('[name="email"]').type('dev@example.com');
cy.get('[data-testid="continue"]').click();
cy.get('[data-testid="order-confirmation"]')
.should('be.visible');
});
});
This example assumes the application exposes the selectors shown and that the test environment provides the route. Prefer stable selectors such as dedicated test IDs for controls. If an assertion fails in only one browser, first determine whether the application behavior differs or whether the test depends on a browser-specific implementation detail.
5. Run the matrix in CI
A matrix gives each browser its own job, making failures attributable and allowing independent parallel execution if your CI system supports it. Install Cypress and the selected browser in the job image, then run the corresponding command. The following GitHub Actions example uses the Cypress GitHub Action and its browser input; choose and pin an action version and browser image according to your repository’s update policy.
name: Cypress browser matrix
on:
push:
pull_request:
jobs:
e2e:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
browser: [chrome, firefox, edge]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- uses: cypress-io/github-action@v6
with:
install: false
start: npm run start -- --host 0.0.0.0
wait-on: 'http://127.0.0.1:3000'
browser: ${{ matrix.browser }}
Adapt the Node version, action version, start command, wait URL, and browser list to the project and current action documentation. This example assumes the app serves on port 3000. If your CI image does not include a browser, install it or use an image that contains the required browser; a browser name in the matrix does not install that browser by itself.
WebKit should be a separate, deliberate job if you include it. Verify the installation method for your Cypress version and CI image, and account for its experimental status and unsupported APIs before making it a gate.
6. Handle browser-specific behavior
Cross-origin navigation
When a test visits or interacts with multiple origins, follow Cypress’s cross-origin testing guidance. Browser security behavior can differ. In particular, Cypress documents that disabling web security is supported only on Chrome-based browsers. A test relying on that setting will not transfer unchanged to Firefox or WebKit; prefer a test design that respects browser security where possible.
WebKit compatibility
WebKit support is an experiment based on Playwright WebKit, according to Cypress’s browser-launch reference. Treat failures involving unsupported Cypress features separately from application defects. The documented lack of cy.origin(), Test Replay incompatibility, and disabled forceNetworkError behavior can prevent a test from running as written.
Browser-specific expectations
Keep the expected product behavior consistent, but allow for legitimate rendering differences. Investigate layout and interaction failures in the browser that reported them. Avoid weakening all browsers’ assertions just to hide one browser’s failure; determine whether the mismatch is a product bug, a test assumption, or a documented browser limitation.
7. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| Cypress says the browser is not installed or cannot be found. | The browser is absent, installed outside the environment Cypress scans, or invoked with an unrecognized name. | Install the browser in the local or CI environment, run npx cypress info, and use a browser name listed for that setup. |
| Firefox will not launch. | The installed Firefox version may be below the current launch floor. | Check the current browser-launch reference. It says versions below 140 cannot be launched in the current context; Cypress 15.0.0–15.18.1 had a floor of 135. |
| The CI result changes after no test code changed. | A browser binary may have updated independently. | Use a versioned browser binary, such as Chrome for Testing where feasible, and keep the browser version visible in CI logs. |
| A test that passes in Chrome fails at a cross-origin step in another browser. | The test may depend on browser-specific security settings. Disabling web security is supported only on Chrome-based browsers. | Review the Cypress cross-origin guide and redesign the test to work with the browser’s normal security model. |
A WebKit run fails at cy.origin(). |
Cypress documents that WebKit does not support cy.origin(). |
Do not treat this failure as proof of a Safari application defect. Restructure coverage or keep that spec out of the experimental WebKit run. |
forceNetworkError interception behaves differently in WebKit. |
The option is disabled for WebKit in Cypress’s documented limitations. | Use another test strategy for that scenario or run it in a supported browser. |
| Only one browser has a flaky assertion. | Timing assumptions, browser rendering differences, or a real browser-specific defect may be involved. | Use Cypress retryable assertions and wait for a meaningful application state instead of a fixed short delay. Reproduce in the affected browser and inspect the actual DOM and behavior. |
| The CI matrix takes too long or costs too much. | Every additional browser job adds execution and infrastructure demand. | Prioritize browsers by support commitments and audience, use parallel jobs if available, and consider running a smaller matrix on every change with broader coverage on a scheduled or release workflow. |
8. Performance, reliability, and cost
- Runtime: Each browser run executes test work. A parallel matrix can reduce wall-clock time if CI capacity permits, while increasing concurrent resource use.
- Reproducibility: Keep Cypress and browser versions controlled in CI. Chrome for Testing is Cypress’s recommended option where possible because its binaries are versioned and do not auto-update.
- Reliability: A green run only describes the browsers and versions actually exercised. An experimental WebKit run has known limitations and should be interpreted accordingly.
- Cost: Compare the confidence from each browser job with added test duration and infrastructure cost. Cypress’s guidance recommends balancing those factors rather than applying one fixed matrix.
- Maintenance: Revisit browser versions, support commitments, and WebKit limitations when updating Cypress or the application. Browser support facts are volatile.
Or skip the browser setup
If your goal is to capture a page image for review, documentation, or an AI workflow rather than execute browser assertions, ScreenshotNeo returns a screenshot or PDF from one API request. It does not replace Cypress cross-browser testing: it is a screenshot API and MCP server for capture workflows.
See the ScreenshotNeo API documentation. This cURL request saves a WebP screenshot:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
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)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
Cookie and consent banners, newsletter 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 not billed, and the response identifies the page verdict and billing status. An MCP server lets AI agents use 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. These capture options are useful for image workflows, while Cypress remains the tool for running browser tests.
Sign up for 1,000 free screenshots a month with no card.
FAQ
Does Cypress run tests in Safari?
Cypress offers experimental WebKit support, which uses Safari’s browser engine. Cypress documents limitations, so do not treat it as a drop-in replacement for every Safari test context.
Can I run the same spec in several browsers?
Yes. Run the spec once per browser with cypress run --browser, or define separate CI matrix jobs that use the same spec files.
Should every pull request test every browser?
That depends on your support promise, desired confidence, execution time, and CI capacity. Cypress recommends balancing confidence against duration and infrastructure cost.
Why use Chrome for Testing in CI?
Cypress recommends it where possible for reproducibility because its binaries are versioned and do not auto-update.


