How Selenium WebDriver Works: The Architecture, Explained

9 min readupdated July 24, 2026

command goes right, the answer comes back. tap a box to read it

Selenium is three programs, not one. Every command is a message from your test to the driver to the browser, and the answer travels all the way back before your next line runs. That round trip is why Selenium is slower than a tool that runs inside the browser, and why you decide what to wait for.

Three things confuse almost everyone new to Selenium. Tests feel slower than they expect. They have to write waits by hand, and forgetting one makes a test flaky. And a plain click sometimes throws StaleElementReferenceException.

These are not three separate problems. They are one picture you have not seen yet. The diagram above is that picture. Turn it over in your head, then read on, because once you hold it the three problems stop being surprises.

Selenium is three programs, not one

When you run a Selenium test, three separate programs are involved.

  • Your test. A program you wrote, here in Node.js. It never touches the browser directly.
  • The driver. A separate program, such as ChromeDriver. It receives instructions and carries them out.
  • The browser. A real Chrome, Firefox or Safari, doing what the driver tells it.

Your test does not click anything. It sends a message that says "click this", the driver performs the click in the browser, and the browser sends back what happened. Every command makes that trip out and back.

WebDriver is the name of the rules these messages follow. It is a published web standard, so any driver that implements it can be controlled the same way. Hold onto that word; it explains the best thing about Selenium later.

Why your tests feel slower

Look at the diagram again. Every command is a message to another program and a message back.

On your own machine that round trip is a millisecond or two, and you never notice it. But a single test can make hundreds of these calls, and against a driver running on another machine, a Selenium Grid, each call might take 30 milliseconds instead of one. A Grid is a setup where the browsers run on remote machines rather than your laptop. Now a hundred calls cost three seconds of pure travel time, before the browser has done any real work.

This is why tools that run inside the browser, like Cypress, feel faster for a single test. They are not sending messages to another program. Selenium's design trades that speed for something else, which is coming up.

The practical lesson: the fewer commands, the faster the test. Finding an element once and reusing it beats finding it five times, because each find is a round trip.

Why waiting is your job

Here is the one that catches every beginner. This looks correct and fails on a slow day:

await driver.findElement(By.id("submit")).click();
await driver.findElement(By.css(".toast")).getText(); // throws: no such element

The click starts something that takes a moment, a save, a network call, an animation. Your test does not know that. From its side, it sent "click", got "done", and immediately sent "find the toast". The toast has not appeared yet, so the driver reports back: no such element.

Selenium does almost nothing for you here. It sends what you say, when you say it. So you have to say "wait until the toast is there":

await driver.wait(until.elementLocated(By.css(".toast")), 5000);

Newer tools watch the page and wait on your behalf. Selenium does not, and this is deliberate. Because your test is a separate program that only sends and receives messages, it has no live view of the page to watch. Waiting has to be something you ask for.

That sounds like a weakness, and in daily work it is more typing. But it is also why Selenium interview questions are so common. Nothing is hidden, so how you handle waiting shows whether you actually understand what the test is doing.

Why elements go stale

The separate-programs model also explains StaleElementReferenceException.

When you find an element, the driver hands your test a reference to a specific element in the browser, like a numbered ticket. Your test holds the ticket, not the element.

const row = await driver.findElement(By.css(".row")); // ticket #14
await refreshOrReRenderTheList();                       // browser rebuilds the list
await row.click();                                      // ticket #14 is no longer valid

If the page re-renders that part of the DOM, the browser throws the old element away and builds a new one. Your ticket now points at something that no longer exists. The driver tells you so: the element reference is stale.

The fix is to find the element again after the page changes, so you get a fresh ticket. We go deeper on this in the stale element guide.

The payoff: it runs almost anywhere

Now the word from earlier pays off. Because WebDriver is a standard that browser makers implement, and because your test only sends standard messages, the test can be written in almost any language.

Java, Python, C#, Ruby, JavaScript and more all speak the same WebDriver protocol to the same drivers. That is why Selenium works across more languages, more browsers and more operating systems than any other tool, including real Safari and older browsers that newer tools do not reach.

For a team whose language is not JavaScript, this is often the deciding reason to choose Selenium. The architecture that makes it slower is the same architecture that makes it universal.

One myth to drop

Older tutorials tell you to download ChromeDriver by hand, match its version to your browser, and set a path. That advice is out of date.

Modern Selenium ships Selenium Manager, which finds the right driver and fetches it for you. If a guide has you managing driver binaries manually, it predates that, and you can skip those steps.

What an interviewer is really asking

"How does Selenium work" is one of the most common opening questions in a QA interview, and the diagram above is the answer they want to hear. Say it in your own words: your test talks to a driver, the driver drives a real browser, and every command is a message that makes a round trip.

Then connect it, because that is what separates a memorised answer from an understood one. The round trip is why it is slower. The separation is why waiting is your job. The reference passed back is why elements go stale. The standard protocol is why it runs in any language. One picture, four answers.

Remember this

Selenium is three programs passing messages: your test, the driver, and the browser. Almost everything that surprises people follows from that. Commands cost a round trip, so fewer is faster. Your test cannot see the page, so you handle the waiting. It holds a reference, so elements go stale when the page re-renders. And the messages are a web standard, so the test runs in nearly any language.

Next: start writing real tests in the Selenium WebDriver tutorial, or see how the three tools compare in Playwright vs Selenium.

Reference: the W3C WebDriver standard.

Put it into practice

Solve a graded problem: write a test, and we check it would catch a real bug.

Browse the problems →

Keep reading