How to Set Up a Cross-Browser Testing Environment
Set up a repeatable Playwright baseline for Chromium, Firefox, and WebKit, then decide when branded browsers, real devices, or a hosted grid are needed.
A practical cross-browser testing environment starts with your product’s supported-browser policy, then runs the same tests in separate Chromium, Firefox, and WebKit projects. Playwright can manage these browser binaries locally and in CI. Add branded Chrome or Edge channels, mobile emulation, physical devices, or a hosted browser grid only when your support commitments call for them. Playwright’s WebKit build is not branded Safari, so a WebKit pass does not prove Safari behavior.
This guide builds a JavaScript Playwright baseline, explains what each layer covers, and shows how to keep the setup reproducible. For screenshots outside an interactive test flow, ScreenshotNeo is a separate screenshot API and MCP server; it does not replace browser automation or functional assertions.
1. Choose a browser matrix from your support policy
There is no universal browser-version matrix that fits every site. Start with the browsers and device classes you promise to support, then use audience evidence and the budget for CI or hosted testing to decide how many combinations to run.
| Layer | What it checks | Limit to keep in mind |
|---|---|---|
| Playwright-managed Chromium, Firefox, WebKit | A controlled baseline across three browser engines | Chromium is not branded Chrome or Edge; Playwright WebKit is not branded Safari |
| Branded Chrome or Edge channel | Behavior in an installed public browser channel | Must be selected explicitly; Playwright does not install these channels by default |
| Mobile emulation | Responsive layouts and broad mobile flows | A device profile is not a physical handset |
| Physical device or hosted device grid | Device and OS behavior beyond local emulation | Define devices from your support needs; provider availability and versions change |
Record the browser project names, target devices, and the reason each is in scope. Add combinations when a support requirement, observed user issue, or browser-specific feature makes the extra coverage worthwhile.
2. Install Playwright and matching browsers
Playwright requires browser binaries matched to its version. Its documentation states: “Each version of Playwright needs specific versions of browser binaries to operate.” Install Playwright in the repository and use its CLI to install the browsers. Keep the package version in your package lockfile, and rerun browser installation when upgrading Playwright.
npm init -y
npm install --save-dev @playwright/test
npx playwright install
The default install provides the browsers used for Chromium, Firefox, and WebKit projects. To install a particular engine explicitly, use:
npx playwright install webkit
On Linux CI, browser dependencies may also need to be installed. Playwright provides an install command that includes dependencies:
npx playwright install --with-deps chromium
You can also install dependencies separately with npx playwright install-deps. Follow the same approach for the browsers your CI job actually runs. See the official Playwright browser installation guide for platform details and current options.
3. Configure Chromium, Firefox, and WebKit projects
Create playwright.config.ts in the project root. This example defines three projects, a base URL, and a test timeout. Replace the base URL and example test with your app’s values.
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
timeout: 30_000,
use: {
baseURL: 'http://127.0.0.1:3000',
trace: 'retain-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
Project names are labels for your test matrix. The device presets supply browser-oriented defaults such as viewport and user agent; they do not install branded browsers or turn WebKit into Safari. For a minimal test, create tests/home.spec.ts:
import { test, expect } from '@playwright/test';
test('home page has a title and primary navigation', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveTitle(/Example/);
await expect(page.getByRole('navigation')).toBeVisible();
});
Run all configured projects:
npx playwright test
Run just one project while diagnosing an issue:
npx playwright test --project=firefox
Playwright projects can also represent distinct configurations, such as branded browser channels, mobile profiles, or test subsets. Keep each project’s purpose clear so a green result can be interpreted correctly.
4. Decide whether you need branded Chrome or Edge
Playwright’s default Chromium is open-source Chromium. It is useful for engine-level coverage, but it is not automatically the same binary or configuration as public Chrome or Edge. If your regression policy specifically requires a branded public browser, or your app depends on media codecs or enterprise browser policy, install and select the channel explicitly.
npx playwright install chrome
Then add a project using the channel option:
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chrome-stable',
use: { browserName: 'chromium', channel: 'chrome' },
},
{
name: 'edge-stable',
use: { browserName: 'chromium', channel: 'msedge' },
},
],
});
Install the corresponding channel when your environment requires it, and confirm the channel is available on the machine running the tests. A project using channel: 'chrome' is still a Chromium-based Playwright project, but it launches the installed branded browser channel.
5. Add mobile coverage in layers
Device emulation is an efficient first layer for checking responsive layout and common flows. You can add a mobile project using a Playwright device profile, for example:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'mobile-chromium',
use: { ...devices['Pixel 7'] },
},
{
name: 'mobile-webkit',
use: { ...devices['iPhone 13'] },
},
],
});
Use profiles available in the installed Playwright version; the profile catalog can change as the framework evolves. Emulation helps test dimensions and browser-level behavior, but it is not a physical Android phone or iPhone. If touch behavior, hardware, OS integration, or a specific physical device matters to your support promise, choose real devices or a hosted device service based on your target audience.
6. Know what WebKit coverage does and does not prove
Playwright’s WebKit is built from WebKit main-branch sources and is not branded Safari. A WebKit project is valuable for catching engine differences, but do not describe its result as a Safari pass. If Safari itself is in your support policy, use a supported Safari environment or a device/browser service that provides the target combination, and validate that provider’s current capabilities.
7. When to move to a hosted browser grid
A hosted grid is useful when local machines cannot reasonably supply the OS, browser, or device combinations your support matrix requires. BrowserStack documents Playwright browser and OS combinations, device selection, and its current support matrix. Those versions and combinations are maintained and can change, so check the provider’s live documentation when configuring a run.
Before adding a remote grid, identify the exact gap: for example, a required operating system, a real mobile device, or a branded browser version. Then confirm the provider supports that combination and configure credentials and capabilities using its current instructions. Avoid copying fixed browser versions from an old article into a long-lived setup.
Playwright also documents connecting to Selenium Grid as an experimental integration. The documented setup depends on Selenium 4 and a Chrome DevTools Protocol WebSocket connection, and the remote browser connection described there is limited to Google Chrome and Microsoft Edge. Validate the Selenium Grid independently before connecting Playwright. Do not assume this route provides remote Firefox or WebKit. See Playwright’s Selenium Grid documentation and BrowserStack’s current Playwright browser and OS matrix.
8. Keep local and CI runs reproducible
- Commit the package lockfile and install dependencies with the repository’s lockfile-aware command in CI.
- Install browser binaries matching the locked Playwright version as part of CI setup.
- Install the needed OS dependencies where the runner requires them.
- Use the same named projects locally and in CI, or document why a job intentionally runs a subset.
- When Playwright is upgraded, refresh browser binaries and review any changed device profiles or browser options.
- Store any hosted-grid credentials in the CI secret mechanism and follow that provider’s current configuration guide.
Keeping the framework and browser binary versions aligned avoids a common source of “works locally, fails in CI” errors. The exact CI commands depend on the operating system and runner; use Playwright’s installation documentation for the selected environment.
9. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Browser executable is missing | The browser binaries were not installed, or do not match the Playwright package version. | Run npx playwright install after installing dependencies; reinstall after a Playwright upgrade. |
| Browser launches locally but fails in Linux CI | Required system packages are missing. | Install dependencies with npx playwright install --with-deps for the browsers in use. |
| Chrome or Edge channel cannot be launched | The branded channel is unavailable on the runner or was not installed. | Install the selected channel where supported and check its availability; use the managed Chromium project if branded behavior is not required. |
| WebKit passes but Safari has a bug | Playwright WebKit is not branded Safari and does not establish Safari behavior. | Validate with a Safari environment or hosted device/browser combination that meets the support requirement. |
| Mobile test looks right but fails on a handset | Device emulation does not reproduce every physical-device or OS behavior. | Reproduce on target physical devices or a hosted device service when the behavior is in scope. |
| Remote browser session is rejected | Capabilities, supported versions, or credentials may not match the provider’s current requirements. | Check the provider’s live Playwright matrix and setup documentation; verify secrets and requested browser/OS pair. |
| Selenium Grid connection works only for some browsers | The documented Playwright integration is experimental and described for Chrome and Edge. | Confirm the grid works independently and use a different supported route for remote Firefox or WebKit. |
10. Performance, reliability, and cost
Each added browser project increases the number of browser runs, so begin with the support-driven baseline and expand deliberately. During diagnosis, run a single project with --project; in regular CI, choose the project set that gives the coverage your policy requires. Browser installation and dependency setup also take CI time, so install only the engines and channels the job needs.
Local browser runs keep the environment under your control but are constrained by the developer machine or CI runner. Hosted grids extend the available browser, OS, and device combinations, while adding provider-specific setup and costs. The research sources do not establish a universal runtime, price, or optimal matrix; check the chosen provider’s current terms and capability tables and measure against your own suite.
For a predictable baseline, pin Playwright through the lockfile, install matching binaries in CI, and treat framework upgrades as browser-environment upgrades too. Preserve failure traces when useful for debugging, as in the sample configuration.
Or skip the browser setup
If you need a page screenshot rather than an interactive browser test, ScreenshotNeo’s API can capture it with one GET request. This does not replace cross-browser assertions or physical-device validation.
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}`);
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and responses identify page verdict and billing status in headers. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
FAQ
Does one passing Chromium test mean a site works in Chrome?
It gives coverage in Playwright-managed Chromium. If your policy requires branded Chrome behavior, add and run the explicit Chrome channel project.
Can I call a Playwright WebKit run a Safari test?
No. Playwright WebKit is not branded Safari. Describe it as WebKit coverage and validate Safari separately when required.
Do I need real phones to start cross-browser testing?
No. Start with browser projects and emulation for layout and broad flows. Add physical devices when your support policy or a device-specific issue calls for them.
Should every pull request run every browser and device?
That depends on suite duration, CI capacity, and release risk. Use the support matrix to decide which projects run for each workflow, then keep the policy explicit.


