Blog

Xvfb: Practical Guide and How to Get Real GPU Rendering

One-line xvfb-run for Playwright, Selenium and Puppeteer. Why Xvfb renders on the CPU (llvmpipe) and how to make Chrome use the GPU, with measurements.

Xvfb: practical guide, and how to get real GPU rendering

Xvfb (X virtual framebuffer) is an X server that draws into memory instead of onto a screen. It is the classic way to run a browser, a graphical application or an E2E test suite on a Linux server with no display. This guide covers the essentials, then the limitation most tutorials leave out: Xvfb does not use the GPU.

Get started in one line

sudo apt install xvfb          # Debian / Ubuntu
xvfb-run -a -s "-screen 0 1920x1080x24" npx playwright test
  • -a automatically picks a free display number (handy for parallel CI);
  • -screen 0 1920x1080x24 sets the resolution and color depth, so screenshots are identical from one run to the next.

To keep a display running in the background:

Xvfb :99 -screen 0 1920x1080x24 &
export DISPLAY=:99

The catch: Xvfb renders on the CPU

Xvfb has no access to the GPU. Any OpenGL application running on it is rendered by the CPU, using Mesa’s llvmpipe software driver:

$ xvfb-run -a glxinfo -B | grep renderer
OpenGL renderer string: llvmpipe (LLVM 19.1.7, 256 bits)

With Chrome and Chromium it is even more obvious. Under Xvfb with default settings, WebGL is simply disabled; in --headless mode with default settings, Chrome uses SwiftShader, a GPU emulated on the CPU. On a 1080p WebGL test, that gives roughly 13 frames/s.

Make Chrome use the GPU, with or without Xvfb

Chrome can render directly on the GPU through ANGLE, bypassing the X server. You just have to ask:

chromium --headless=new --use-angle=vulkan --ignore-gpu-blocklist ...

Measured on 2026-10-29 on a Linux GPU server (Intel UHD 770, 4 vCPU, Chromium 156, same 1080p WebGL shader):

ConfigurationWebGL rendererFrames/s
--headless=new aloneSwiftShader (CPU)13
Xvfb aloneWebGL disabled—
--headless=new --use-angle=vulkanUHD 770 (Vulkan)~260
--headless=new --use-angle=gl-eglUHD 770 (OpenGL ES 3.2)~230
Xvfb + --use-angle=vulkanUHD 770 (Vulkan)GPU, same as above

About 20 times faster, and the CPU stays free for your tests. The same flags work under Xvfb, which is useful if you keep Xvfb for an extension or an application that needs a real X display.

The details (Playwright, Puppeteer, Selenium, Docker, verification) are in our guide Running Chrome with the GPU on a Linux server.

Do I still need Xvfb?

Use caseIs Xvfb useful?
Recent Playwright / Puppeteer / SeleniumNo: --headless=new is enough
Chrome extensions, headed-mode testsYes
X11 applications (Electron, Java Swing, legacy tools)Yes
Accelerated OpenGL for a non-browser appNo: use display-less EGL, or VirtualGL

FAQ

Why are my WebGL screenshots black or very slow under Xvfb? Because Chrome disables WebGL (or falls back to SwiftShader) when it can’t find a GPU. Add --use-angle=vulkan --ignore-gpu-blocklist.

Can I get hardware OpenGL under Xvfb? Not directly: Xvfb can’t use the GPU. Applications that can render through EGL (eglinfo -B -p surfaceless shows the card) or VirtualGL work around the problem.

Is it reproducible in CI? Yes: resolution and depth are fixed by the command, and the GPU produces the same output on every run.

Try it on a Linux GPU server

Our servers have an Intel UHD 770 GPU available inside the VM, with Mesa, Vulkan and VAAPI already installed: install Chromium (apt install chromium) and the commands above work right away. From €14.99 excl. VAT/month, root access, dedicated IPv6, optional k3s cluster.