Running Firefox in Headless Mode on CI Servers
This article explains how developers can execute the Firefox Web Browser in headless mode on Continuous Integration (CI) servers that lack a graphical display. It covers the essential system dependencies, the required command-line flags, how to configure popular automated testing frameworks like Selenium and Playwright, and how to implement these steps within a CI pipeline configuration.
Understanding Native Headless Mode
Modern versions of Firefox (version 56 and later) ship with a
built-in headless mode. Previously, developers had to use tools like
Xvfb (X virtual framebuffer) to simulate a display on Linux-based CI
servers. Today, passing the --headless flag tells Firefox
to run without rendering a Graphical User Interface (GUI), significantly
reducing memory overhead and execution time.
System Dependencies for CI Environments
Even when running without a display, Firefox requires certain underlying OS libraries to function on stripped-down Linux CI containers (like Ubuntu or Debian). Before running Firefox, ensure your CI environment installs the browser along with these required packages:
sudo apt-get update
sudo apt-get install -y firefox libgtk-3-0 libdbus-glib-1-2 libxt6If you are using Selenium, you must also install
geckodriver, which acts as the bridge between your tests
and the Firefox browser.
Running Headless Firefox via the Command Line
To run Firefox in headless mode directly from the CI server's
terminal, use the --headless flag. This is useful for quick
smoke tests or taking automated screenshots.
# Launch Firefox in headless mode and capture a screenshot of a URL
firefox --headless --screenshot https://example.com
# Specify a custom window size for the screenshot
firefox --headless --window-size=1920,1080 --screenshot https://example.comConfiguring Automated Testing Frameworks
Most developers run Firefox in CI through automated testing
frameworks. You must configure your framework's driver to pass the
--headless argument to the browser upon initialization.
Selenium (Python)
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
options = Options()
options.add_argument("--headless")
driver = webdriver.Firefox(options=options)
driver.get("https://example.com")
print(driver.title)
driver.quit()Selenium (Node.js)
const { Builder } = require('selenium-webdriver');
const firefox = require('selenium-webdriver/firefox');
(async function runTest() {
let options = new firefox.Options();
options.addArguments('--headless');
let driver = await new Builder()
.forBrowser('firefox')
.setFirefoxOptions(options)
.build();
try {
await driver.get('https://example.com');
} finally {
await driver.quit();
}
})();Selenium (Java)
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
public class HeadlessFirefox {
public static void main(String[] args) {
FirefoxOptions options = new FirefoxOptions();
options.addArguments("--headless");
WebDriver driver = new FirefoxDriver(options);
driver.get("https://example.com");
driver.quit();
}
}Playwright
Playwright runs browsers in headless mode by default. You only need to specify Firefox as the target browser in your script or configuration.
const { firefox } = require('playwright');
(async () => {
const browser = await firefox.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.close();
})();Example CI Pipeline Configuration
Below is an example of a GitHub Actions workflow that sets up a headless environment, installs Firefox, and runs a test suite without a graphical display.
name: Firefox Headless CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install Firefox and Geckodriver
run: |
sudo apt-get update
sudo apt-get install -y firefox
wget https://github.com/mozilla/geckodriver/releases/download/v0.33.0/geckodriver-v0.33.0-linux64.tar.gz
tar -xvzf geckodriver*
chmod +x geckodriver
sudo mv geckodriver /usr/local/bin/
- name: Install Python dependencies
run: pip install selenium pytest
- name: Run headless tests
run: pytestTroubleshooting Common CI Issues
- Viewport Size: Headless browsers often default to a
smaller window size (e.g., 800x600), which can cause responsive web
elements to hide and tests to fail. Always explicitly set the window
size using
--window-size=1920,1080in your options. - Shared Memory Crashes: Docker containers in CI
environments typically have a small
/dev/shm(shared memory) partition (64MB), which can cause Firefox to crash on heavy pages. Fix this by setting theMOZ_FORCE_DISABLE_E10S=1environment variable or mounting a larger shared memory volume (--shm-size=2g) in your Docker configuration.