Skip to main content
SeleniumDecoded

Pick the Browser, Headless Mode and Grid From Environment Variables

Run the same suite on Chrome, Firefox or Edge, locally or on a Grid, headed or headless, by changing environment variables instead of code.

Stable Verified against Selenium 4.48.0

Problem

Switching from Chrome to Firefox, or from local to Grid, means editing code and remembering to change it back. CI needs headless; developers debugging need headed.

Solution

A compact factory that reads BROWSER, HEADLESS and GRID_URL. The full version with thread safety is in the Driver Factory lesson; this is the minimal copy-paste form.

Environment-driven driver creation
Selenium 4 Stable
public static WebDriver createDriver() throws MalformedURLException {
String browser = System.getenv().getOrDefault("BROWSER", "chrome");
boolean headless = !"false".equalsIgnoreCase(System.getenv().getOrDefault("HEADLESS", "true"));
String grid = System.getenv("GRID_URL");
AbstractDriverOptions<?> options = switch (browser) {
case "firefox" -> { FirefoxOptions o = new FirefoxOptions(); if (headless) o.addArguments("-headless"); yield o; }
case "edge" -> { EdgeOptions o = new EdgeOptions(); if (headless) o.addArguments("--headless=new"); yield o; }
default -> { ChromeOptions o = new ChromeOptions(); if (headless) o.addArguments("--headless=new"); o.addArguments("--window-size=1366,768"); yield o; }
};
if (grid != null && !grid.isBlank()) return new RemoteWebDriver(new URL(grid), options);
return switch (browser) {
case "firefox" -> new FirefoxDriver((FirefoxOptions) options);
case "edge" -> new EdgeDriver((EdgeOptions) options);
default -> new ChromeDriver((ChromeOptions) options);
};
}
// BROWSER=firefox HEADLESS=false mvn test
// GRID_URL=http://grid:4444 mvn test
import os
from selenium import webdriver
def create_driver():
browser = os.getenv("BROWSER", "chrome")
headless = os.getenv("HEADLESS", "true").lower() != "false"
grid = os.getenv("GRID_URL")
if browser == "firefox":
options = webdriver.FirefoxOptions()
if headless: options.add_argument("-headless")
elif browser == "edge":
options = webdriver.EdgeOptions()
if headless: options.add_argument("--headless=new")
else:
options = webdriver.ChromeOptions()
if headless: options.add_argument("--headless=new")
options.add_argument("--window-size=1366,768")
if grid:
return webdriver.Remote(command_executor=grid, options=options)
return {"firefox": webdriver.Firefox, "edge": webdriver.Edge}.get(browser, webdriver.Chrome)(options=options)
# BROWSER=firefox HEADLESS=false pytest
# GRID_URL=http://grid:4444 pytest
const { Builder } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
const firefox = require('selenium-webdriver/firefox');
const edge = require('selenium-webdriver/edge');
async function createDriver() {
const browser = process.env.BROWSER ?? 'chrome';
const headless = (process.env.HEADLESS ?? 'true') !== 'false';
const grid = process.env.GRID_URL;
const chromeOpts = new chrome.Options().addArguments('--window-size=1366,768');
const firefoxOpts = new firefox.Options();
const edgeOpts = new edge.Options();
if (headless) {
chromeOpts.addArguments('--headless=new');
firefoxOpts.addArguments('-headless');
edgeOpts.addArguments('--headless=new');
}
const builder = new Builder().forBrowser(browser)
.setChromeOptions(chromeOpts).setFirefoxOptions(firefoxOpts).setEdgeOptions(edgeOpts);
if (grid) builder.usingServer(grid);
return builder.build();
}
// BROWSER=firefox HEADLESS=false npm test
// GRID_URL=http://grid:4444 npm test
public static IWebDriver CreateDriver()
{
var browser = Environment.GetEnvironmentVariable("BROWSER") ?? "chrome";
var headless = !string.Equals(Environment.GetEnvironmentVariable("HEADLESS") ?? "true", "false", StringComparison.OrdinalIgnoreCase);
var grid = Environment.GetEnvironmentVariable("GRID_URL");
DriverOptions options;
switch (browser)
{
case "firefox": { var o = new FirefoxOptions(); if (headless) o.AddArgument("-headless"); options = o; break; }
case "edge": { var o = new EdgeOptions(); if (headless) o.AddArgument("--headless=new"); options = o; break; }
default: { var o = new ChromeOptions(); if (headless) o.AddArgument("--headless=new"); o.AddArgument("--window-size=1366,768"); options = o; break; }
}
if (!string.IsNullOrWhiteSpace(grid)) return new RemoteWebDriver(new Uri(grid), options);
return browser switch
{
"firefox" => new FirefoxDriver((FirefoxOptions)options),
"edge" => new EdgeDriver((EdgeOptions)options),
_ => new ChromeDriver((ChromeOptions)options),
};
}
// $env:BROWSER="firefox"; $env:HEADLESS="false"; dotnet test

Why It Works

Environment variables are the one configuration channel every CI system, container and shell supports. Defaults favour the CI case (Chrome, headless); developers override for debugging. Selenium Manager resolves whichever driver is needed.

Gotchas

  • Firefox’s headless flag is -headless (one dash); Chromium’s is --headless=new.
  • When GRID_URL is set, the browser runs remotely: uploads need LocalFileDetector, downloads need managed downloads, and localhost in URLs refers to the Grid node.
  • Validate the BROWSER value and fail early with a clear message; a typo silently falling back to Chrome hides misconfiguration.

Learn the theory