Selenium WebDriver Architecture

When you call driver.findElement(By.id("email")).click() in a Java test, that call doesn't reach into the browser directly. It travels through several layers, each with a specific job. Understanding this chain matters because it explains error messages you'll see constantly in real automation work — things like "chromedriver executable needs to be in PATH" or "session not created" — and it explains why Selenium can automate Chrome, Firefox, and Edge with the (almost) same Java code.

The Four Layers

LayerWhat it isExample
1. Test ScriptThe Java code you write, using JUnit/TestNG + Selenium API callsdriver.findElement(...).click();
2. Selenium Client LibraryThe selenium-java library. Turns Java method calls into WebDriver protocol commandsorg.openqa.selenium.WebDriver interface
3. Browser DriverA small executable that receives commands and translates them into browser-specific instructionschromedriver.exe, geckodriver.exe, msedgedriver.exe
4. BrowserThe actual browser, controlled by its driver via the browser's own automation APIsChrome, Firefox, Edge

How a Single Command Actually Travels

Take driver.get("https://recipebox.example.com/login"). Here's the real path that command takes:

Java Test Script | driver.get("https://recipebox.example.com/login") v Selenium Client Library (Java bindings) | builds a W3C WebDriver command v JSON over HTTP ----> POST /session/{id}/url { "url": "https://recipebox.example.com/login" } v Browser Driver (chromedriver.exe) | listens on localhost, translates the JSON command | into the browser's native automation protocol (DevTools Protocol for Chrome) v Browser (Chrome) | actually navigates to the URL v Result flows back up the same chain as an HTTP response
Note: The browser driver runs as its own local process, listening on a port on your machine. Your Java test talks to it over plain HTTP, exactly like a REST API client talking to a server — except the "server" here is a small program sitting between your test and the browser.

Why Every Browser Needs Its Own Driver

Chrome, Firefox, and Edge each expose completely different internal automation hooks (Chrome uses the Chrome DevTools Protocol; Firefox uses Marionette internally). The browser driver's whole job is to hide those differences behind one standard interface, so your Java code never has to know or care which browser is running underneath. That's why:

  • Chrome needs chromedriver, matched to your installed Chrome version.
  • Firefox needs geckodriver.
  • Edge needs msedgedriver.
  • Your Java test code (driver.findElement(...), driver.get(...)) stays identical no matter which of the three you point it at — only the line that creates the WebDriver object changes (new ChromeDriver() vs new FirefoxDriver()).

Selenium 4 and the W3C WebDriver Standard

In Selenium 3 and earlier, each browser vendor implemented a slightly different flavor of the "JSON Wire Protocol," which caused subtle cross-browser inconsistencies. Selenium 4 is built entirely on the W3C WebDriver specification — a formal web standard, the same one browser vendors themselves helped write. In practice this means:

  • Commands are now standardized JSON payloads sent over HTTP to the driver, following the official W3C spec rather than a Selenium-specific dialect.
  • Behavior is more consistent across Chrome, Firefox, and Edge, since all three vendors implement the same standard directly in their driver executables.
  • Selenium 4 added native support for Chrome DevTools Protocol (CDP) features (like network interception) on top of the standard WebDriver commands.
Next up: now that you know the pieces involved, let's set up an actual Maven project so your Java code can talk to the selenium-java client library. Head to Project Setup with Maven.