# xvfbwrapper

### Manage headless displays with Xvfb (X virtual framebuffer)

----

## About

`xvfbwrapper` is a Python library for controlling X11 virtual displays with Xvfb.

- Copyright (c) 2012-2026 [Corey Goldberg][github-profile]
- Development: [GitHub][github-repo]
- Releases: [PyPI][pypi-home]
- License: [MIT][mit-license]

The package provides the `xvfvwrapper.Xvfb` class that is used to interact with
an Xvfb server.

See the [module API documentation][api-docs] for more information.

----

## Status

<table>
  <tr>
    <td>Latest Version</td>
    <td>
      <a href="https://pypi.org/project/xvfbwrapper">
        <img src="https://img.shields.io/pypi/v/xvfbwrapper.svg">
      </a>
    </td>
  </tr>
  <tr>
    <td>Build/Tests (CI)</td>
    <td>
      <a href="https://github.com/cgoldberg/xvfbwrapper/actions/workflows/test.yml">
        <img src="https://github.com/cgoldberg/xvfbwrapper/actions/workflows/test.yml/badge.svg">
      </a>
    </td>
  </tr>
  <tr>
    <td>Supported Python Versions</td>
    <td>
      <a href="https://pypi.org/project/xvfbwrapper">
        <img src="https://img.shields.io/pypi/pyversions/xvfbwrapper">
      </a>
    </td>
  </tr>
  <tr>
    <td>OSS Sponsorship</td>
    <td>
      <a href="https://tidelift.com/lifter/search/pypi/xvfbwrapper">
        <img src="https://tidelift.com/badges/package/pypi/xvfbwrapper">
      </a>
    </td>
  </tr>
</table>

----

## What is Xvfb?


`Xvfb` (X virtual framebuffer) is a display server implementing the X11
display server protocol. It runs in memory and does not require a physical
display or input device. Only a network layer is necessary.

`Xvfb` allows GUI applications that use X Windows to run on a headless system.

----

## Installation

Official releases are published on [PyPI][pypi-home]:

```
pip install xvfbwrapper
```

----

## System Requirements

- Python 3.10+
- X Window System
- Xvfb (`sudo apt-get install xvfb`, `yum install xorg-x11-server-Xvfb`, etc)
- Support for locking with `fcntl` system call (non-Windows systems)

----

## Examples

#### Basic Usage:

Note: Always either wrap your usage of `Xvfb()` with try/finally, or use it as
a context manager to ensure the display is stopped. If you don't, you'll end up
with a bunch of junk in `/tmp` if errors occur.

```python
from xvfbwrapper import Xvfb

xvfb = Xvfb()
xvfb.start()
try:
    # launch stuff inside virtual display here
finally:
    xvfb.stop()
```

#### Usage as a context manager:

```python
from xvfbwrapper import Xvfb

with Xvfb():
    # launch stuff inside virtual display here
    # (Xvfb will stop when this block completes)
```

#### Specifying display geometry:

```python
from xvfbwrapper import Xvfb

xvfb = Xvfb(width=1280, height=720)
xvfb.start()
```

#### Specifying display number:

```python
from xvfbwrapper import Xvfb

xvfb = Xvfb(display=23)
xvfb.start() # Xvfb will start on display :23
```

#### Setting XDG_SESSION_TYPE:

When running `Xvfb` in a Wayland session, GUI toolkits may try to use the
Wayland backend instead of connecting to `Xvfb`. Setting
`set_xdg_session_type=True` forces `XDG_SESSION_TYPE=x11` in the Python process
and all child processes, ensuring that GUI apps use the X11 backend and can
render on the virtual display.

```python
from xvfbwrapper import Xvfb

xvfb = Xvfb(set_xdg_session_type=True)
xvfb.start()
```

#### Specifying other Xvfb options:

The `Xvfb` executable accepts several types of command line arguments.

The most common is an argument with a `-` prefix and a parameter
(i.e. `-nolisten tcp`). These can be added as keyword arguments when
creating an `xvfbwrapper.Xvfb` instance. For example:

```python
from xvfbwrapper import Xvfb

xvfb = Xvfb(nolisten="tcp")
xvfb.start() # Xvfb will be called with the `-nolisten tcp` argument
```

However, there are other possible types of arguments:

- unary argument (i.e. `ttyxx`)
- unary argument with a `+` prefix (i.e. `+xinerama`)
- unary argument with a `-` prefix (i.e. `-nocursor`)
- argument with a parameter (i.e. `c 100`)
- argument with a `+` prefix and a parameter (i.e. `+extension RANDR`)

Any type of argument can be added as an `extra_args` sequence when creating
an `xvfbwrapper.Xvfb` instance. For example:

```python
from xvfbwrapper import Xvfb

xvfb = Xvfb(extra_args=("ttyxx", "-nocursor", "+extension", "RANDR"))
xvfb.start() # Xvfb will be called with the `ttyxx -nocursor +extension RANDR` arguments
```

#### Multithreaded execution:

To run several Xvfb displays at the same time, you can use the `environ`
keyword when starting the `Xvfb` instances. This provides isolation between
processes or threads. Be sure to use the environment dictionary you initialize
`Xvfb` with in your subsequent calls. Also, if you wish to inherit your current
environment, you must use the copy method of `os.environ` and not simply
assign a new variable to `os.environ`:

```python
import os

from xvfbwrapper import Xvfb

isolated_environment1 = os.environ.copy()
xvfb1 = Xvfb(environ=isolated_environment1)
xvfb1.start()

isolated_environment2 = os.environ.copy()
xvfb2 = Xvfb(environ=isolated_environment2)
xvfb2.start()

try:
    # launch stuff inside virtual displays here
finally:
    xvfb1.stop()
    xvfb2.stop()
```

#### Usage in testing - headless Selenium WebDriver tests:

This is a test using `selenium` and `xvfbwrapper` to run tests
on Chrome with a headless display. (see: [selenium docs][selenium-docs])

[selenium-docs]: https://www.selenium.dev/selenium/docs/api/py

```python
import os
import unittest

from selenium import webdriver
from xvfbwrapper import Xvfb


class TestPage(unittest.TestCase):

    def setUp(self):
        xvfb = Xvfb(set_xdg_session_type=True)
        xvfb.start()
        self.driver = webdriver.Chrome()
        self.addCleanup(xvfb.stop)
        self.addCleanup(self.driver.quit)

    def test_selenium_homepage(self):
        self.driver.get("https://www.selenium.dev")
        self.assertIn("Selenium", self.driver.title)


if __name__ == "__main__":
    unittest.main()
```

- virtual display is launched
- browser launches inside virtual display (headless)
- browser quits during cleanup
- virtual display stops during cleanup

----

## Development

- Git: [github.com/cgoldberg/xvfbwrapper.git][github-repo]

- Create a virtual env and install required testing packages:

    ```
    python -m venv venv
    source ./venv/bin/activate
    pip install --editable --group dev --group test .
    ```

- Run all tests in the default Python environment:

    ```
    pytest
    ```

- Run all tests, linting, and type checking across all supported/installed
  Python environments:

    ```
    tox
    ```

[github-profile]: https://github.com/cgoldberg
[github-repo]: https://github.com/cgoldberg/xvfbwrapper
[pypi-home]: https://pypi.org/project/xvfbwrapper
[mit-license]: https://raw.githubusercontent.com/cgoldberg/xvfbwrapper/refs/heads/master/LICENSE
[api-docs]: https://coreygoldberg.com/xvfbwrapper
