ScreenshotNeo

BlogEngineering

How to Run Playwright in the Cloud Across Five Browser Engines

Run one Playwright suite across Chromium, Chrome, Edge, Firefox and WebKit in CI, with cloud-provider guidance, fidelity caveats and working config.

By the ScreenshotNeo team29 September 20268 min read

How to Run Playwright in the Cloud Across Five Browser Engines

Playwright can run one test suite against five configured browser targets in the cloud: bundled Chromium, bundled Firefox, bundled WebKit, branded Google Chrome and branded Microsoft Edge. The key detail is that these are five configurations, not five independent rendering engines. Chromium, Firefox and WebKit are Playwright browser engines; Chrome and Edge are branded Chromium channels.

Define one Playwright project for each target, then run the matrix with npx playwright test. Use --project when you need to rerun only one browser. The same model works locally and with hosted providers such as Sauce Labs and BrowserStack.

What the five-browser matrix actually means

Playwright’s project model lets a suite share test code while changing browser, device, channel, timeout, retries or environment settings per project. The official documentation describes projects for Chromium, WebKit and Firefox as well as branded Google Chrome and Microsoft Edge channels. Read the Playwright projects documentation.

One Playwright project matrix can execute the same suite across five browser configurations.
One Playwright project matrix can execute the same suite across five browser configurations.
Project Playwright target What it represents
chromium browserName: 'chromium' Playwright’s bundled Chromium build
chrome channel: 'chrome' Installed Google Chrome channel based on Chromium
edge channel: 'msedge' Installed Microsoft Edge channel based on Chromium
firefox browserName: 'firefox' Playwright’s patched Firefox build
webkit browserName: 'webkit' Playwright’s WebKit build, used as a Safari compatibility proxy

WebKit is not branded Safari. Playwright says its WebKit build comes from current WebKit main-branch sources, while branded Safari is unsupported. Firefox is also a Playwright-patched build rather than the branded desktop Firefox distribution. If exact Safari media codecs or macOS behavior matter, schedule a macOS WebKit environment and document the proxy limitation. See Playwright’s browser guidance.

Prerequisites and version pinning

  1. Install Node.js and add Playwright to your project.
  2. Pin the Playwright version in package.json and your lockfile.
  3. Install the matching browser binaries with npx playwright install.
  4. Update the package and browsers together when upgrading.
npm install -D @playwright/test
npx playwright install

Keeping the package and browser bundles aligned avoids running tests against an unsupported browser revision. In CI, cache dependencies only when the cache key includes the Playwright version.

Complete five-project configuration

Create playwright.config.ts with shared defaults and one project per target:

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

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  timeout: 30_000,
  expect: { timeout: 5_000 },
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 4 : undefined,
  reporter: [['html'], ['line']],
  use: {
    baseURL: process.env.BASE_URL ?? 'https://example.test',
    trace: 'retain-on-failure',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'], browserName: 'chromium' },
    },
    {
      name: 'chrome',
      use: { ...devices['Desktop Chrome'], channel: 'chrome' },
    },
    {
      name: 'edge',
      use: { ...devices['Desktop Chrome'], channel: 'msedge' },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'], browserName: 'firefox' },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'], browserName: 'webkit' },
    },
  ],
});

Use browserName for Playwright’s bundled engines. Use channel for installed branded browsers. Do not set both for the same project. Device presets set a coherent viewport and user agent; replace them with explicit values when pixel-level consistency matters.

Write tests that survive five browsers

Prefer user-visible locators and web standards instead of browser-specific selectors. Avoid timing sleeps unless the behavior genuinely depends on elapsed time. Wait for a locator, response or state transition.

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

test('checkout completes', async ({ page }) => {
  await page.goto('/checkout');
  await page.getByLabel('Email').fill('person@example.test');
  await page.getByRole('button', { name: 'Continue' }).click();
  await expect(page.getByRole('heading', { name: 'Payment' })).toBeVisible();
});

Run the full matrix or focus a single target:

npx playwright test
npx playwright test --project=webkit
npx playwright test tests/checkout.spec.ts --project=edge
npx playwright show-report

Share authentication with a setup project

When every browser needs the same login, create a setup project that writes storage state, then make browser projects depend on it. Playwright runs setup first and can run dependent projects in parallel.

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

export default defineConfig({
  projects: [
    {
      name: 'setup',
      testMatch: /.*\.setup\.ts/,
    },
    {
      name: 'chromium',
      dependencies: ['setup'],
      use: { browserName: 'chromium', storageState: 'playwright/.auth/user.json' },
    },
    {
      name: 'firefox',
      dependencies: ['setup'],
      use: { browserName: 'firefox', storageState: 'playwright/.auth/user.json' },
    },
    {
      name: 'webkit',
      dependencies: ['setup'],
      use: { browserName: 'webkit', storageState: 'playwright/.auth/user.json' },
    },
  ],
});

Keep authentication files out of source control. If login behavior itself is browser-sensitive, test it separately in each project rather than assuming one saved state proves every browser works.

Run Playwright in a cloud provider

A hosted browser service supplies remote workers, operating systems, browser versions and result artifacts. Sauce Labs documents Playwright execution through its saucectl CLI and ties supported Chromium, Firefox and WebKit builds to the Playwright release. Sauce Labs Playwright documentation.

BrowserStack documents Playwright combinations including playwright-chromium, playwright-firefox, playwright-webkit, branded chrome and edge, with browser versions and parallel combinations selected through capabilities. BrowserStack Playwright documentation.

Provider selection checklist

  • Coverage: confirm the provider offers the exact engine, branded channel, browser version and operating system you need.
  • Safari fidelity: determine whether you receive WebKit on Linux, WebKit on macOS, or real Safari. WebKit is a proxy for branded Safari.
  • Parallelism: compare worker limits, queue time and the number of projects you run per commit.
  • Artifacts: verify availability of traces, video, screenshots, console logs and network records.
  • Version control: check how quickly new Playwright and browser versions become available and how long old versions remain supported.
  • Security: review private networking, secret handling, IP allowlists and data retention if tests access non-public systems.
  • Total cost: include parallel workers, test duration, retries and scheduled cross-browser runs.

Typical cloud CI flow

  1. Install the locked dependencies.
  2. Authenticate the provider with CI secrets.
  3. Start the provider’s Playwright runner or configure its remote endpoint.
  4. Run the five projects in parallel where the plan allows it.
  5. Upload the Playwright report and provider artifacts.
  6. Rerun only the failed project before rerunning the whole matrix.
npm ci
npx playwright install --with-deps
npx playwright test --reporter=line,html

The exact remote command and capability format are provider-specific, so use the provider’s current Playwright integration documentation rather than copying an old launcher snippet.

Performance and reliability

  • Parallelize by project and file: five browsers multiply work. Set a worker limit that your cloud plan can actually run.
  • Use retries as diagnosis: a retry can expose transient infrastructure failures, but a test that passes only on retry is still unstable.
  • Reuse setup: dependency projects avoid repeating expensive login or seed steps for every test file.
  • Control data: create isolated users or reset server state so parallel browsers do not edit the same records.
  • Capture failure artifacts: retain traces and screenshots on failure; keep videos when they help explain timing or rendering issues.
  • Pin and review: update Playwright and browser versions deliberately, then inspect failures caused by genuine browser changes.

Cloud queue time can dominate short suites. For fast pull requests, run Chromium and one compatibility target first, then run the complete five-project matrix on protected branches or a scheduled job. Keep the full matrix when a change touches layout, input, navigation, media or browser APIs.

Or skip the browser setup

If your goal is a clean image or PDF of a page rather than interactive browser assertions, ScreenshotNeo provides a single HTTP capture call. Its cleanup steps accept cookie and consent banners and remove more than 60 known consent platforms, newsletter popups and chat widgets before capture; each step can be disabled. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status.

Screenshot cleanup removes common consent and overlay elements before capture.
Screenshot cleanup removes common consent and overlay elements before capture.

See the ScreenshotNeo API documentation for all options.

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 also supports full-page and element capture, dark mode, device presets, retina scale, custom CSS and JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage data and PDFs. An MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.

There are 1,000 free screenshots each month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan. Create a free ScreenshotNeo account.

Troubleshooting

“Executable doesn’t exist”

Cause: the matching browser bundle was not installed or the CI cache is stale. Fix: run npx playwright install (or --with-deps on Linux) and key caches by the Playwright version.

Chrome or Edge project fails to launch

Cause: the branded channel is not installed on the worker. Fix: use a provider image that supplies that channel, install it in your image, or use bundled Chromium when brand fidelity is unnecessary.

WebKit passes locally but fails in cloud

Cause: operating-system, font or media differences. Fix: pin the cloud OS, install required fonts, and treat WebKit as a Safari proxy rather than claiming branded Safari coverage.

Only one browser is running

Cause: a project filter or provider capability limits the matrix. Fix: remove --project, verify all project names, and inspect the provider’s parallel configuration.

Tests time out intermittently

Cause: shared test data, slow remote queues or an application race. Fix: isolate data, wait on locators or responses, raise timeouts only for known slow operations, and inspect traces before increasing retries.

Visual snapshots differ by browser

Cause: fonts, antialiasing, viewport, device scale factor or genuine rendering differences. Fix: pin fonts and viewport, set an explicit scale, keep snapshots per project, and review differences instead of using one universal baseline.

FAQ

Are Chrome and Edge separate engines?

No. They are branded Chromium channels. The five-target matrix contains three independent Playwright engines plus two Chromium brand configurations.

Does Playwright automate branded Safari?

No. Playwright’s WebKit target is the closest supported proxy. Use macOS WebKit when that compatibility signal matters.

Can projects use different devices?

Yes. Each project can select a device preset or define its own viewport, user agent, locale, timezone and other settings.

Should every pull request run all five targets?

Run the full matrix when browser behavior is relevant. For faster feedback, use a smaller presubmit set and reserve the complete matrix for protected branches or scheduled runs.

When is a screenshot API a better fit?

Use an API when you need rendered images or PDFs, not interactive assertions, and want to avoid maintaining browser binaries, cleanup scripts and cloud workers.