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.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Cross-browser testing means checking that your website works in the browsers and devices your audience actually uses. No team can test every browser and device combination, so the practical approach is to agree a supported set based on audience data, test core user journeys and accessibility on that set repeatedly, and treat a pass in one browser or emulator as evidence for that browser only. Graceful degradation is an acceptable outcome when core information and services still work for the people who need them.

What cross-browser testing covers

MDN Web Docs defines the practice in one sentence: “Cross-browser testing is the practice of ensuring that a website works across various browsers and devices.” In practice that means checking more than how a page looks. A useful test pass covers:

  • Core interactions: navigation, forms and validation, search, and any authentication or payment path.
  • Responsive layouts at the breakpoints your design uses, including text and controls that remain legible and tappable.
  • Keyboard-only operation and, where your audience relies on it, assistive technology such as screen readers.
  • Behavior on low-capability devices, where slow hardware changes how the page loads and responds.
  • Failure details that identify the exact platform, device, and browser version, not just the browser name.

Exact visual identity across browsers is not always necessary. If a control renders differently in an older browser but still works and is reachable by keyboard, that difference is usually acceptable. A missing button or an unreadable error message is not.

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

Step 1: Define the support matrix

The support matrix is the list of browsers, operating systems, device classes, and assistive-technology requirements you commit to supporting. Build it before writing a single test, because every later decision depends on it.

Start from audience data

Use first-party analytics if you have them: browser families, versions, operating systems, screen sizes, and the share of traffic from low-capability devices. Record the version policy you agree with the site owner, such as “the two most recent major versions of each browser family.” Write it down. A matrix that lives only in someone’s head will drift.

Use support tiers instead of one flat list

MDN recommends a tiered approach rather than promising exhaustive testing everywhere. The table below shows how the tiers map to effort.

Tier Applies to What you promise How you test
Full support Common modern environments in your audience data The complete experience The full matrix for significant changes and release checks
Basic core experience Older environments your audience still uses Core information and services work; enhancements may be absent Smoke tests of core journeys
Defensive coding only Rare environments No bespoke promise; code fails safely Not tested individually; checked through feature detection and fallback review

Do not copy a browser list

MDN’s example uses Chrome, Edge, Firefox, and Safari for a North American ecommerce site, and notes that Opera is Chromium-based in that example. That is an illustration of the reasoning, not a list to adopt. Your own audience data decides the set, and the set changes as the browser landscape changes.

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

Step 2: Rank the features by failure risk

Test first where browsers are most likely to differ. Work through this list and mark each item as high, medium, or low risk for your product:

  • Forms and client-side validation, including date, number, and file inputs.
  • Navigation, menus, and anything that depends on focus management.
  • Layout breakpoints, sticky elements, and overflow behavior.
  • Media playback and image formats.
  • Browser APIs your code calls directly, such as storage, clipboard, or geolocation.
  • Authentication and payment flows, where a failure directly loses users or money.
  • Newer or less widely supported CSS and JavaScript features.

Before you state that a feature is unsupported in a particular browser, check it against MDN’s compatibility data or the Can I Use site. Do not rely on memory for compatibility boundaries.

Step 3: Run a fast baseline, then expand

Test in stages so that feedback arrives while changes are still small.

  1. Baseline on every meaningful change. Run the core journeys in two stable desktop browsers, one relevant mobile platform, and a keyboard-only pass of the changed pages.
  2. Expand for significant changes and releases. Run the complete agreed matrix, including the older-browser core experience checks.
  3. Use real devices where you can. Physical phones and tablets reveal touch, font rendering, and performance behavior that desktop tools miss. Emulators and virtual machines are useful when hardware or an operating system is unavailable, but describe them as approximations, not as identical to a real device.
  4. Record what you ran. Each run should list the browser build, operating system, device, viewport, and network conditions.

Step 4: Automate the repeatable journeys

Browser automation makes repeated coverage practical for deterministic journeys: opening key pages, completing forms, moving through navigation, and confirming that expected content appears. The example below uses Playwright, which can drive Chromium, Firefox, and WebKit from one test suite. Playwright is one option among several; Selenium, for example, is also named by MDN as an automation approach.

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

Install Playwright and its browsers

  1. Create the project or add Playwright to an existing one: npm init playwright@latest.
  2. Download the browser binaries the config uses: npx playwright install.
  3. On a Linux CI runner, also install the operating-system libraries the browsers need: npx playwright install --with-deps.

Configure one project per browser and device profile

Each entry in projects is a separate run target. The two branded projects use the channel option so the tests run in the installed Chrome or Edge rather than Playwright’s managed Chromium build. Playwright may run projects in parallel, subject to its worker limits.

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  retries: process.env.CI ? 2 : 0,
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    trace: 'on-first-retry',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'chrome-branded', use: { ...devices['Desktop Chrome'], channel: 'chrome' } },
    { name: 'edge-branded', use: { ...devices['Desktop Edge'], channel: 'msedge' } },
    { name: 'mobile-android', use: { ...devices['Pixel 7'] } },
    { name: 'mobile-ios', use: { ...devices['iPhone 14'] } },
  ],
});

Write a journey test that also checks the keyboard

Locators that match labels and roles let the test fail when a label disappears, which a CSS selector would not catch. The test below submits the form with the keyboard as well as checking the error message.

import { test, expect } from '@playwright/test';

test('checkout rejects an invalid email when submitted from the keyboard', async ({ page }) => {
  await page.goto('/checkout');
  await page.getByLabel('Email').fill('not-an-email');
  await page.getByLabel('Email').press('Enter');
  await expect(page.getByText('Enter a valid email address')).toBeVisible();
});

Run the suite

  • All projects: npx playwright test
  • One browser while you debug: npx playwright test --project=firefox
  • Open the HTML report with traces and failure details: npx playwright show-report

Run it in CI often

Playwright’s own guidance is direct: “Setup CI/CD and run tests frequently. The more often you run your tests the better.” Run the full project list on pull requests where the runtime allows, and use a smaller smoke subset where the full matrix is too slow. Keep Playwright and its browser binaries updated, because the bundled Chromium is not identical to branded Chrome or Edge in every case.

What automation does not prove

A green run means the scripted journeys passed in the browsers you configured. It does not establish that the site works on every real phone, operating system version, network, or accessibility setup. Keep these checks separate from the automated suite:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Visual and usability review on real devices, including text size and touch target spacing.
  • Screen-reader testing with the assistive technology your audience uses.
  • Performance on constrained hardware and slow connections.
  • Exploratory testing of flows that no script was written for.

Report failures so they can be reproduced

A bug report that says “broken in Safari” wastes the next person’s time. Include every item below:

  • The URL or page, and the exact reproduction steps.
  • Expected result and actual result.
  • Browser name and version, operating system, device model, and viewport.
  • Evidence: a screenshot, console output, or a video or trace.

MDN specifically recommends narrowing a bug by varying the platform and the browser version. If the failure appears on one version and not the one before it, that version boundary is the most useful fact in the report.

Keep the matrix current

Revisit the matrix when audience data changes, when a feature you depend on gains or loses support, when a browser release changes behavior, or when the product scope changes. Prerelease browsers are useful in two cases: when you are adopting a new web technology, and when you are investigating a bug that may already be fixed upstream. Keep recurring tests in the development workflow so that coverage does not depend on someone remembering to run it.

Choosing between local automation and a hosted service

There are at least two approaches. You can run automation against browser binaries and devices you control, or you can use a commercial remote browser and device service. Many teams combine them: local runs on every commit, and a hosted service for hard-to-reproduce combinations or device coverage they cannot maintain.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
The Web Testing Handbook
  • Used Book in Good Condition
Option Good fit when Trade-offs to check
Local Playwright projects You need fast, repeatable runs in CI and control over browser versions No physical devices; the managed Chromium build may differ from branded Chrome or Edge
Selenium Your team already uses Selenium or needs its language bindings MDN names it as an automation approach; compare framework fit and maintenance with your current stack
BrowserStack You need many browser and device combinations or remote devices MDN lists it among commercial remote options; verify current pricing and terms with the vendor
Sauce Labs You want hosted browser and device testing with several frameworks Its documentation lists Selenium, Cypress, Playwright, Cucumber.js with Playwright, TestCafe, Replay, and Vibium; verify current pricing and terms with the vendor

When you compare options, check these axes against your own needs:

  • Whether the exact browser, operating system, version, and device combinations you need are available.
  • Real-device access versus emulation, and how much fidelity your tests require.
  • Support for your existing framework and languages.
  • Debugging evidence: screenshots, video, logs, and reproducible session details.
  • CI integration, parallel capacity, queue time, and maintenance effort.
  • Privacy and security constraints for the test environment and any application data in it.
  • Price at your expected usage level, using current vendor terms.

The vendor descriptions above come from each vendor’s own documentation and reflect what they say they support. They are not independent comparative test results.

Capture screenshots for visual review

Screenshots are useful as review evidence: a designer can compare a page across the matrix, and a bug report can attach the exact state of the page. Playwright can capture a full page inside any project. The test below saves one image per project, so the file name shows which browser or device produced it.

import { test } from '@playwright/test';

test('capture checkout for visual review', async ({ page }, testInfo) => {
  await page.goto('/checkout');
  await page.screenshot({
    path: `screenshots/checkout-${testInfo.project.name}.png`,
    fullPage: true,
  });
});

Run it with npx playwright test screenshots/ after creating the screenshots folder. Expect one file per project. Consent banners and chat widgets often appear in these images, so review them before sharing.

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

Or skip the browser setup:

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}`);

The Node.js call returns the image in res; save it with import fs from 'node:fs' and fs.writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer())). Options and parameters are listed in the ScreenshotNeo documentation.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting

Symptom Likely cause Fix
Error that a browser executable does not exist Browser binaries were not installed, or Playwright was upgraded without reinstalling them Run npx playwright install
Linux CI fails to launch Firefox or WebKit with missing library errors Operating-system dependencies are missing on the runner Run npx playwright install --with-deps in the CI setup step
The branded Chrome or Edge project fails to start The branded browser is not installed on the machine running the tests Install the browser there, or remove the channel project
A test fails only in WebKit A CSS or JavaScript feature is unsupported or behaves differently in that engine Check the feature on MDN or Can I Use, add a fallback, and record the browser version in the report
A test fails only in CI Fixed waits, timing assumptions, or a different viewport or font set Replace fixed waits with locators that auto-wait; open the trace from the first retry
Screenshots differ on every run Dynamic content, animations, dates, or fonts changing between runs Hide or mask dynamic regions and wait for the page to settle before capture
Hosted runs wait a long time to start Limited parallel capacity or a large matrix Run a smoke subset on every change and the full matrix on releases
The ScreenshotNeo call does not return an image Missing or incorrect access key, or an unencoded URL Check the status code and response body before saving the file; the cURL example uses --data-urlencode for the URL
A ScreenshotNeo capture still shows a banner or loading content A step is turned off, or the page needs more time Confirm the cleanup steps are enabled, then use the wait options for a selector, a delay, or network idle, as described in the documentation
A ScreenshotNeo call was not billed, or was billed unexpectedly Billing depends on the outcome of each capture Read the X-Page-Verdict and X-Billed response headers; only clean shots are billed

Or skip the browser setup

The Python, cURL, and Node.js calls above return a clean screenshot in one GET request. Three reasons teams use it for visual review:

  • Cookie banners, newsletter popups, and chat widgets are removed before the capture, so the image shows the page rather than the overlays. Each step can be turned off.
  • Only clean shots are billed. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing.
  • An MCP server lets AI agents take screenshots through the tools take_screenshot, get_page_info, and capture_pdf, for clients such as Claude, Cursor, or any MCP client.

1,000 screenshots a month are free with no card, and paid plans start at $5 for 3,000. Every feature is available on every plan.

Plan Price Screenshots included
Free $0, no card required 1,000 per month
Starter $5 3,000
Growth $15 15,000
Pro $39 60,000
Scale $99 250,000
Business $249 1,000,000

Yearly billing gives two months free. Prices are as listed at screenshotneo.com; check the site for current terms. Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card, and start with the one-call example above.

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

Frequently Asked Questions

What does graceful degradation look like in a real test?

Suppose a checkout uses a native date picker that some browsers do not render. The degraded version shows a plain text field with a format hint, the form still submits, and the validation message is readable by a screen reader. To test it, disable the enhanced control in the test browser and run the same journey. If the order still completes, the degradation is acceptable for that tier.

Does a ScreenshotNeo capture replace running cross-browser tests?

No. A capture shows one page at one moment. It does not run your assertions, so it cannot confirm that a form submits from the keyboard or that a menu opens. Use the Playwright projects for behavior and use captures for visual review and bug reports.

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.