WebDriverManager in Selenium

If you've worked with Selenium for more than a few months, you've probably hit the same wall every automation engineer eventually hits: a test suite that runs perfectly on your machine but throws a SessionNotCreatedException the moment someone else runs it, or the moment Chrome auto-updates overnight. Nine times out of ten, the culprit is a browser driver binary that no longer matches the installed browser version.

WebDriverManager exists to make that entire class of problem disappear. It's a small Java library, but it quietly removes one of the more tedious parts of maintaining a Selenium framework: keeping driver binaries in sync with browser versions across every machine that runs your tests.

This guide walks through what WebDriverManager actually does, how to wire it into a Java project, working examples for Chrome and Firefox, and the practical issues you'll run into once you use it in a real framework rather than a toy script.

Advertisement

What Is WebDriverManager?

WebDriverManager is an open-source Java library, created and maintained by Boni Garcia, that automates the download, installation, and configuration of the driver executables Selenium WebDriver needs to talk to a browser — things like chromedriver, geckodriver, and msedgedriver.

Before WebDriverManager existed, a Selenium test had to point explicitly at a driver binary sitting somewhere on disk, using a system property such as:

 
java
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");

That approach works, but it's brittle. Every time Chrome updates, you may need a new matching version of chromedriver. Every developer on the team needs the correct binary for their own operating system. And CI servers need the same thing kept up to date, usually through some ad-hoc shell script.

WebDriverManager handles all of that at runtime: it detects the browser version installed on the machine, downloads the matching driver if it isn't already cached locally, and configures the correct system property automatically — no manual downloads, no hardcoded paths.

Why Is WebDriverManager Used?

The core problem WebDriverManager solves is driver-to-browser version compatibility, multiplied across however many machines run your tests: developer laptops, CI agents, and sometimes Docker containers.

In practice, teams reach for WebDriverManager because it:

  • Removes manual driver downloads from onboarding and CI setup
  • Automatically resolves the driver version that matches the locally installed browser
  • Caches drivers locally so repeated test runs don't re-download them
  • Supports multiple browsers (Chrome, Firefox, Edge, Opera, and others) through one consistent API
  • Reduces "works on my machine" failures caused by driver mismatches

It's worth being direct about scope here: WebDriverManager doesn't install browsers, and it doesn't replace Selenium — it only manages the driver layer that sits between your test code and the browser.

How WebDriverManager Works

At a basic level, the workflow looks like this:

  1. Your test code calls a manager for a specific browser, e.g. WebDriverManager.chromedriver().setup();
  2. WebDriverManager detects the browser version installed on the current machine (where possible).
  3. It checks its local cache for a matching driver version.
  4. If the correct driver isn't cached, it downloads it from the appropriate official source.
  5. It sets the relevant system property (e.g. webdriver.chrome.driver) so Selenium can locate the driver automatically.
  6. Your test then instantiates the browser normally, using new ChromeDriver() or the equivalent.

Everything in that sequence happens before you construct the WebDriver object — WebDriverManager's job ends once the correct binary is on disk and the system property is set.

WebDriverManager with Java and Selenium

Here's a minimal, realistic example using JUnit 5 and Selenium WebDriver:

 
java
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

class LoginPageTest {

    private WebDriver driver;

    @BeforeAll
    static void setupClass() {
        // Resolves and configures the correct chromedriver once per test class
        WebDriverManager.chromedriver().setup();
    }

    @BeforeEach
    void setupTest() {
        driver = new ChromeDriver();
        driver.get("https://example.com/login");
    }

    @Test
    void loginPageShouldDisplayFormFields() {
        // your actual assertions go here
    }

    @AfterEach
    void teardown() {
        if (driver != null) {
            driver.quit();
        }
    }
}

A few things worth noting about this example:

  • WebDriverManager.chromedriver().setup() is called once, in @BeforeAll, since it only needs to configure the system property, not create a driver instance per test.
  • new ChromeDriver() is created per test method, which keeps tests isolated from each other.
  • The example above shows expected code structure, not an actual executed test run — you'll need a real target application URL and assertions.

Maven Dependency

To bring WebDriverManager into a Maven project, add the dependency to your pom.xml:

 
xml
<dependency>
    <groupId>io.github.bonigarcia</groupId>
    <artifactId>webdrivermanager</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

A couple of practical notes on this configuration:

  • groupId: io.github.bonigarcia — this is the current, correct group ID for the library on Maven Central. Older tutorials sometimes reference different coordinates; if you copy a dependency snippet from an old blog post, double-check it against Maven Central directly.
  • scope: test — WebDriverManager is only needed during test execution, so keeping it scoped to test avoids pulling it into your production artifact.
  • Version pinning — because WebDriverManager itself is updated periodically to support newer browser releases, it's common practice to manage the version through a Maven property (e.g. <wdm.version>) so it's easy to bump in one place. Since library versions change over time, check Maven Central for the current release before locking it into a shared framework.

If you're using Gradle instead:

 
groovy
testImplementation("io.github.bonigarcia:webdrivermanager:5.9.2")

WebDriverManager Chrome Example

Chrome is the most common target browser in Selenium suites, and it's also the browser most likely to auto-update outside your control — which is exactly the scenario WebDriverManager is designed for.

 
java
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();

For teams running headless Chrome in CI, you'll typically combine this with ChromeOptions:

 
java
import org.openqa.selenium.chrome.ChromeOptions;

WebDriverManager.chromedriver().setup();

ChromeOptions options = new ChromeOptions();
options.addArguments("--headless=new");
options.addArguments("--disable-gpu");
options.addArguments("--window-size=1920,1080");

WebDriver driver = new ChromeDriver(options);

WebDriverManager only handles resolving and configuring the driver binary — the ChromeOptions configuration for headless mode, window size, or sandboxing is entirely independent of it.

WebDriverManager Firefox Example

The pattern for Firefox mirrors Chrome closely, which is one of the practical benefits of using WebDriverManager across a multi-browser suite — the setup call changes, but the surrounding structure doesn't.

 
java
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

WebDriverManager.firefoxdriver().setup();

FirefoxOptions options = new FirefoxOptions();
WebDriver driver = new FirefoxDriver(options);

If your framework runs cross-browser tests, it's common to centralize this in a factory method rather than repeating the setup logic in every test class:

 
java
public class DriverFactory {

    public static WebDriver createDriver(String browser) {
        switch (browser.toLowerCase()) {
            case "firefox":
                WebDriverManager.firefoxdriver().setup();
                return new FirefoxDriver();
            case "chrome":
            default:
                WebDriverManager.chromedriver().setup();
                return new ChromeDriver();
        }
    }
}

Browser Driver Management

It helps to be clear on what "driver version compatibility" actually means. Selenium doesn't talk to a browser directly — it talks to a driver process (chromedriver, geckodriver, etc.), which in turn controls the browser through its native automation protocol. Each driver release is built and tested against a specific range of browser versions.

When the installed browser version and driver version fall out of sync — commonly because the browser auto-updated but the driver binary didn't — you'll typically see session creation failures or unexpected behavior mid-test, rather than a clear "version mismatch" error every time.

WebDriverManager reduces this friction by checking the installed browser version at runtime and resolving a compatible driver version automatically, rather than relying on a driver version someone hardcoded weeks or months earlier.

WebDriverManager vs Manual Driver Setup

Aspect Manual Driver Setup WebDriverManager
Initial setup effort Download driver manually per OS/browser One dependency, one line of setup code
Keeping drivers current Manual re-download on every browser update Automatic version resolution at runtime
Team onboarding Each developer sources their own driver Works out of the box after setup()
CI/CD maintenance Requires scripted driver installation steps Handled inline within the test run
Offline/air-gapped environments Works once drivers are in place Requires network access unless drivers are pre-cached
Fine-grained control Full manual control over exact driver version Slightly less direct control unless explicitly pinned

Neither approach is objectively "better" in every context. Manual setup can be preferable in strictly air-gapped environments where outbound network access isn't available at test time. For most teams running tests locally and in CI with normal internet access, WebDriverManager removes a recurring maintenance cost with very little trade-off.

It's also worth mentioning a related but distinct tool: since Selenium 4.6, Selenium itself ships with Selenium Manager, a built-in driver-resolution mechanism that activates automatically when no driver path is set. WebDriverManager predates Selenium Manager and offers more configuration options (explicit version pinning, proxy support, Docker-based browser execution, and finer control over caching), which is why many established frameworks continue to use it even on newer Selenium versions.

Common Errors and Troubleshooting

A few issues come up repeatedly when teams first introduce WebDriverManager into an existing framework:

"Could not find a version that satisfies…" or download failures in CI
This usually means the CI agent doesn't have outbound internet access to the driver download source, or a corporate proxy is blocking it. WebDriverManager supports proxy configuration via system properties (e.g. wdm.proxy) for exactly this case.

Tests pass locally but fail in Docker
Headless browser execution inside containers often needs additional flags (--no-sandbox, --disable-dev-shm-usage) that have nothing to do with WebDriverManager itself — they're standard Chrome/Chromium container requirements, easy to mistake for a driver management problem.

Driver resolution is slow on every test run
By default, WebDriverManager caches resolved drivers locally, so repeated runs shouldn't re-download every time. If you're seeing repeated downloads, check whether your CI pipeline is wiping the cache directory between runs.

Version resolution seems "stuck" on an old driver
WebDriverManager caches resolution results for a period of time to avoid unnecessary network calls. If you need to force a fresh check, clearing the cache or forcing a version explicitly (.driverVersion("...")) resolves this.

Corporate environments where automatic browser detection fails
On some locked-down machines, WebDriverManager may not reliably detect the installed browser version. In that case, pinning both browser and driver versions explicitly is more reliable than relying on auto-detection.

Best Practices

A few practices tend to keep WebDriverManager-based setups maintainable as a framework grows:

  • Centralize the setup() call in one factory or base class rather than scattering it across test classes.
  • Pin the WebDriverManager version explicitly in your build file rather than always pulling the latest, so a library update doesn't unexpectedly change behavior mid-sprint.
  • In CI, make sure the driver cache directory persists between runs where possible, to avoid unnecessary repeated downloads.
  • If your organization runs behind a proxy, configure WebDriverManager's proxy settings once, centrally, rather than per developer machine.
  • Combine WebDriverManager with explicit browser options (headless mode, window size, sandboxing flags) rather than assuming defaults are sufficient for CI.
  • Log the resolved driver and browser versions during test setup — it makes diagnosing environment-specific failures considerably faster.

WebDriverManager in Automation Frameworks

In a typical Selenium framework built around the Page Object Model with TestNG or JUnit, WebDriverManager usually sits in a base test class or a dedicated driver factory, invoked once before test execution begins. From there, the rest of the framework — page objects, test logic, assertions — doesn't need to know or care how the driver binary was resolved.

For Maven-based projects running in Jenkins or another CI/CD pipeline, WebDriverManager removes what would otherwise be a separate pipeline step for downloading and staging driver binaries. This becomes particularly useful for parallel and cross-browser execution, where different threads or jobs might be running Chrome and Firefox simultaneously — each manager call resolves the correct driver independently, without manual coordination.

None of this requires disabling Selenium Manager or working around it; WebDriverManager can coexist in a project regardless of Selenium version, since it operates before the WebDriver object is even constructed.

Key Takeaways

  • WebDriverManager automates the download and configuration of Selenium driver binaries, eliminating manual driver management.
  • It resolves driver versions to match the installed browser automatically, reducing version-mismatch failures.
  • Setup is a single line of code per browser: WebDriverManager.chromedriver().setup();
  • It's added via Maven or Gradle using the io.github.bonigarcia group ID.
  • It complements, rather than replaces, browser-specific options like headless mode or sandboxing flags.
  • Selenium's built-in Selenium Manager (since 4.6) offers a lighter alternative, but WebDriverManager still provides more configuration control for larger frameworks.
  • Centralizing setup, pinning versions, and persisting the driver cache in CI are the main practices that keep it maintainable long-term.

Frequently Asked Questions

Is WebDriverManager necessary if I'm using Selenium 4.6 or later?
Not strictly — Selenium Manager, built into Selenium since 4.6, handles basic driver resolution automatically. WebDriverManager remains useful when you need more control: explicit version pinning, proxy configuration, or Docker-based browser execution.

Does WebDriverManager work with Edge and Opera, or only Chrome and Firefox?
It supports several browsers beyond Chrome and Firefox, including Edge, Opera, and Internet Explorer (for legacy environments), each through its own manager method (e.g. WebDriverManager.edgedriver().setup()).

Do I need internet access every time tests run?
Only when a new driver version needs to be downloaded. Once resolved, WebDriverManager caches the driver locally, so subsequent runs typically use the cached copy without a fresh download.

Can I pin an exact driver version instead of letting WebDriverManager auto-detect it?
Yes. You can specify an explicit version, for example WebDriverManager.chromedriver().driverVersion("versionNumber").setup();, which is useful when you need reproducible behavior across environments.

Will WebDriverManager install a browser if it's missing?
No. It manages driver binaries only; it does not install or update the browser itself. The browser must already be present on the machine running the tests.

Is WebDriverManager only for Java, or does it work with Python or JavaScript Selenium projects?
The library covered here is Java-specific. Python and JavaScript ecosystems have their own separate tooling and conventions for driver management.