website/docs/HeadlessAndXvfb.md
This page explains how the WebdriverIO testrunner supports headless execution on Linux using Xvfb (X Virtual Framebuffer). It covers when Xvfb is useful, how to configure it, and how it behaves in CI and Docker.
--headless=...) when possible for minimal overhead.DISPLAY)session not created: probably user data directory is already in use ...Chrome failed to start: exited abnormally. (DevToolsActivePort file doesn't exist)
The user data directory collision error can be misleading as it is often the result of a browser crash and immediate restart that reuses the same profile directory from the prior instance. Ensuring a stable display (e.g., via Xvfb) often resolves it - if not, you should pass a unique --user-data-dir per worker.Four runner options control Xvfb behavior:
autoXvfb (boolean, default: true)
false, the runner never uses Xvfb.true, the runner may use Xvfb when needed.xvfbAutoInstall (boolean, default: false)
xvfb-run if missingxvfbAutoInstallMode ('root' | 'sudo', default: 'sudo')
sudo -n) if not root; skip if sudo missingxvfbAutoInstallCommand (string | string[], optional)
xvfbMaxRetries (number, default: 3)
xvfbRetryDelay (number, default: 1000)
Examples:
export const config: WebdriverIO.Config = {
// Use Xvfb when needed
autoXvfb: true,
// Auto-install Xvfb packages using sudo
xvfbAutoInstall: true,
xvfbAutoInstallMode: 'sudo',
capabilities: [{
browserName: 'chrome',
'goog:chromeOptions': { args: ['--headless=new', '--no-sandbox'] }
}]
}
export const config: WebdriverIO.Config = {
// Use Xvfb when needed
autoXvfb: true,
// Auto-install Xvfb packages using a custom command and sudo
xvfbAutoInstall: true,
xvfbAutoInstallMode: 'sudo',
xvfbAutoInstallCommand: 'curl -L https://github.com/X11/xvfb/releases/download/v1.20.14/xvfb-linux-x64.tar.gz | tar -xz -C /usr/local/bin/',
capabilities: [{
browserName: 'chrome',
'goog:chromeOptions': { args: ['--headless=new', '--no-sandbox'] }
}]
}
export const config: WebdriverIO.Config = {
// Use Xvfb when needed
autoXvfb: true,
// Auto-install Xvfb packages using sudo
xvfbAutoInstall: true,
xvfbAutoInstallMode: 'sudo',
// Configure retry behavior for flaky CI environments
xvfbMaxRetries: 5,
xvfbRetryDelay: 1500,
capabilities: [{
browserName: 'chrome',
'goog:chromeOptions': { args: ['--headless=new', '--no-sandbox'] }
}]
}
The runner considers Xvfb when:
DISPLAY is set (headless environment), or headless browser flags are passedIf DISPLAY is set, the runner won’t force Xvfb by default and will honor your existing X server/window manager.
Notes:
autoXvfb: false disables Xvfb usage entirely (no wrapping with xvfb-run).xvfbAutoInstall only affects installation if xvfb-run is missing; it does not turn usage on/off.xvfbAutoInstallMode controls the installation method: 'root' for root-only installs, 'sudo' for sudo-based installs (default: 'sudo').xvfbRetryDelay × attempt number (e.g., 1000ms, 2000ms, 3000ms, etc.).If your CI sets up its own X server/window manager (e.g., with Xvfb :99 and a WM), either:
autoXvfb: true and ensure DISPLAY is exported; the runner will honor it and avoid wrapping.autoXvfb: false to explicitly disable any Xvfb behavior from the runner.GitHub Actions (using native headless):
- name: Run tests
run: npx wdio run ./wdio.conf.ts
GitHub Actions (virtual display via Xvfb if missing and opted in):
// wdio.conf.ts
export const config = {
autoXvfb: true,
xvfbAutoInstall: true
}
Docker (Ubuntu/Debian example – preinstall xvfb):
RUN apt-get update -qq && apt-get install -y xvfb
For other distributions, adjust the package manager and package name accordingly (e.g., dnf install xorg-x11-server-Xvfb on Fedora/RHEL-based, zypper install xvfb-run on openSUSE/SLE).
When xvfbAutoInstall is enabled, WebdriverIO attempts to install xvfb using your system package manager. The following managers and packages are supported:
| Package Manager | Command | Distributions (examples) | Package Name(s) |
|---|---|---|---|
| apt | apt-get | Ubuntu, Debian, Pop!_OS, Mint, Elementary, Zorin, etc. | xvfb |
| dnf | dnf | Fedora, Rocky Linux, AlmaLinux, Nobara, Bazzite, etc. | xorg-x11-server-Xvfb |
| yum | yum | CentOS, RHEL (legacy) | xorg-x11-server-Xvfb |
| zypper | zypper | openSUSE, SUSE Linux Enterprise | xvfb-run |
| pacman | pacman | Arch Linux, Manjaro, EndeavourOS, CachyOS, etc. | xorg-server-xvfb |
| apk | apk | Alpine Linux, PostmarketOS | xvfb-run |
| xbps-install | xbps-install | Void Linux | xvfb |
Notes:
xvfb manually.“xvfb-run failed to start”
xvfbMaxRetries and xvfbRetryDelay for flaky environments.Xvfb wrapped unexpectedly in CI
DISPLAY / WM setup, set autoXvfb: false or ensure DISPLAY is exported before the runner starts.Missing xvfb-run
xvfbAutoInstall: false to avoid modifying the environment; install via your base image or set xvfbAutoInstall: true to opt in.Frequent Xvfb startup failures in CI
xvfbMaxRetries (e.g., to 5-10) and xvfbRetryDelay (e.g., to 2000ms) for more resilient behavior in unstable environments.xvfb-run if Xvfb is needed and available.DISPLAY.