Skip to main content

Selenium Load Testing: What One Browser User Costs

Selenium load testing, measured: 20 headless Chrome users took 12.1 GiB and ran slower than 5, while k6 simulated 1,000 users in 296 MiB. When browsers belong.

Selenium Load Testing: What One Browser User Costs

You can run a load test with Selenium by starting many browser sessions at once, but each simulated user is a whole browser, so a test machine runs out of memory and CPU long before the server feels any load. The Selenium project itself says performance testing with WebDriver “is generally not advised”.

We measured how far it goes. On a 10-core Apple M1 Max with 64 GB of memory, 20 headless Chrome sessions used 12.1 GiB, kept six to seven cores busy, and served fewer page views a second than 5 sessions did. k6 sent the same page’s requests for 1,000 simulated users in 296 MiB. This guide shows those numbers, the caching effect that makes a Selenium user send a quarter of a new visitor’s requests, and the setups where a browser does belong in a load test.

Key Takeaways

  • Every Selenium user is a full browser: about 620 to 680 MiB of process memory each in our runs, and more than one CPU core while it loads pages.
  • Past 5 browsers, page views per second went down, not up, and the client-side load time grew from 12 ms with 5 browsers to 120 ms with 20 at p95 because the test machine ran out of CPU while the server’s work stayed trivial.
  • A browser that loads the same page again uses its cache: our repeat visits sent 2 requests per page view, a first visit sent 8.
  • Protocol-level tools such as JMeter and k6 simulate users with requests, not browsers. k6 ran 1,000 users in 296 MiB.
  • Use a few real browsers alongside a protocol-level load test to measure what users see, not as the source of the load.

Can you use Selenium for load testing?

Technically yes, practically only at very small scale. Selenium drives real browsers, so running many sessions at once does put load on a server, and each session behaves like a real visitor: it runs JavaScript, loads images and fires API calls. The cost is that every simulated user needs its own browser process, which limits a test machine to dozens of users rather than thousands.

The Selenium documentation lists performance testing under discouraged practices, “not because it is incapable, but because it is not optimised for the job and you are unlikely to get good results”. It names the reasons: browser start-up time, third-party scripts and WebDriver’s own overhead all change the timings, and functional and performance tests “have opposing objectives”. It points to dedicated tools and names JMeter as an example. Selenium Grid does not change the picture either: its documentation describes it as a way to run tests in parallel on several machines and across browsers, and it does not mention load testing.

How we measured it

We served a small shop page from a local Node.js server that counted every request: the HTML, one stylesheet, one script, three 40 KB images, and an API call the script makes after the page loads. The static files allowed caching for an hour. A Python script started N headless Chrome sessions with Selenium 4.52.0 and Chrome 157, each loading the page in a loop for 20 seconds (15 for the single-browser run), and read the page’s navigation timing after every load.

Once a second, the script added up the memory (resident set size, in MiB) and CPU use of every process under it: the chromedriver processes and each Chrome’s browser, renderer and helper processes. Adding up resident memory counts shared pages more than once, so treat the totals as an upper bound. The page and the server were deliberately trivial, so any slowdown came from the test machine, not from the application.

How much does one Selenium user cost?

About 620 to 680 MiB of memory per browser when several run together (725 MiB for one alone), and more than one CPU core while it is busy. One headless Chrome with its chromedriver took 725 MiB and 2.5 cores on its own, and 20 of them took 12.1 GiB across 173 processes. CPU stopped growing at about 6.4 cores once 5 browsers were running: from there on, browsers waited for the CPU instead of loading pages.

Concurrent browsersPage views/sMemory (total)Memory per userCPU in useLoad time p95Processes
191725 MiB725 MiB2.5 cores5.4 ms10
51633.3 GiB682 MiB6.5 cores12.3 ms51
101456.5 GiB670 MiB6.4 cores34.2 ms89
2013412.1 GiB620 MiB6.4 cores119.6 ms173

The page views per second are high because the page was tiny and local; a real page with real network time would give far fewer. The shape is what carries over: one browser per user, hundreds of megabytes each, and a ceiling set by the test machine’s cores.

Why did more browsers give fewer page views?

Because the test machine became the bottleneck. With 5 browsers, the browsers and their drivers used about 6.5 of the 10 cores and the page views peaked at 163 a second. Adding more browsers only split the same CPU between more sessions, so throughput fell to 145 with 10 and 134 with 20, while each browser waited longer for its turn.

The load time the browsers reported shows the trap. The page took 5.4 ms at p95 with one browser and 119.6 ms with 20, a 22-fold slowdown, while the server had nothing harder to do than return a small page and a short JSON list a few hundred times a second. A browser load test on one machine measures the machine running it as much as the application. Spreading the browsers over a Selenium Grid adds capacity, but each node still pays the same cost per user, so a test of 1,000 users needs dozens of large machines.

Does a Selenium user send the same requests as a real visitor?

Only on its first visit. A browser keeps its cache between page loads, so after the first load our browser sessions fetched only the HTML and the API call: 2.0 to 2.4 requests per page view instead of 8. Starting a new browser for every page view brought it back to 8 requests (HTML, stylesheet, script, three images, API call and favicon) but cut throughput to 3.9 page views a second with 5 users.

Browser setupRequests per page viewPage views/s (5 users)
One browser per user, reused (warm cache)2.1163
New browser for every page view (cold cache)8.03.9

Both are realistic for some visitors. Returning visitors have a warm cache, first-time visitors and those arriving from search do not. The point is to choose on purpose: a browser loop left at its defaults simulates the most cache-friendly user there is, and quietly takes static files, and often the CDN, out of the test. Protocol-level scripts have the same choice to make, but there it is explicit, because you list the requests yourself.

How does a protocol-level tool compare?

A protocol-level tool sends the HTTP requests a browser would send, without rendering anything, so each simulated user costs kilobytes instead of hundreds of megabytes. We wrote the warm-cache page view as a k6 script: the HTML, then the API call. With 20 users and no pauses, k6 ran 22,459 page views a second in 237 MiB. With 1,000 users each pausing one second between views, it used 296 MiB.

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = { vus: 1000, duration: '20s' };

export default function () {
  const page = http.get('http://127.0.0.1:8098/');
  check(page, { 'page 200': (r) => r.status === 200 });
  http.get('http://127.0.0.1:8098/api/products');
  sleep(1);
}
ToolUsersPage views/sMemory
Selenium + headless Chrome2013412.1 GiB
k6 v2.3.0, no pauses2022,459237 MiB
k6 v2.3.0, 1 s pause per view1,000990296 MiB

The price is that a protocol-level script does not run the page’s JavaScript. If the page makes an API call, the script has to make it too, which is why the k6 script above lists /api/products by hand. Recording a browser session and converting it, or starting from the HAR file of a real visit, saves most of that work. What protocol-level tests cannot tell you is how long the page takes to become usable in the browser, which is where a small number of real browsers comes back in.

JMeter vs Selenium: which one should you use for load testing?

Use JMeter, or another protocol-level tool such as k6, to generate the load, and Selenium to test that the application works. JMeter sends HTTP requests from threads that cost little memory each, so one machine can simulate thousands of users. Selenium drives a real browser for each user, which is right for checking behaviour and wrong for producing load. They answer different questions, so many teams run both.

JMeterSelenium
What it drivesHTTP and other protocolsA real browser
Cost per simulated userOne threadOne browser and its helper processes (about 620-680 MiB in our runs)
Runs page JavaScriptNoYes
Built forLoad and performance testingFunctional browser testing
Typical users per machineThousandsAbout 5 busy browsers per 10 cores in our test

The two meet in JMeter’s WebDriver Sampler, a plugin that runs Selenium code inside a JMeter test, which is useful for measuring a few browser sessions while JMeter’s normal samplers produce the load. Our older guide to load testing the UI with the WebDriver Sampler shows the setup. The same per-browser cost applies there, so keep the browser threads few.

When does a browser belong in a load test?

When you want to know what the page feels like while the server is under load. A protocol-level test tells you the API answered in 300 ms at peak; it cannot tell you whether the page rendered in two seconds or eight, because rendering, scripts and third-party tags happen in the browser. A handful of browser sessions running alongside the load answers that.

The pattern is to generate the load at the protocol level and add one to five real browsers that walk through the important pages and record their timings. k6 has a browser module for this, whose documentation describes its main use as testing “performance on the browser level”, with the question “when my application is receiving thousands of simultaneous requests from the protocol-level, what happens to the frontend?”. The Selenium tests you already have can play the same part, as long as they are a small number of observers and not the load itself. Keep the browsers on a separate machine from the load generator so their CPU use does not distort either measurement.

How to load test without browsers on LoadFocus

LoadFocus load tests run at the protocol level from 25 cloud regions, with your own JMeter or k6 scripts or a test built in the browser, so the load comes from cloud machines rather than a fleet of browsers. To capture the browser side at the same time, run a page speed check on the same page while the load test is running: it measures load times with Lighthouse from several locations.

Set up the load as a cloud load test and the browser side with page speed monitoring. If you already have Selenium tests, keep them for checking that user journeys work, and turn those journeys into protocol-level scripts for the load, by importing a HAR file of the journey or writing the requests in k6 or JMeter.

Frequently Asked Questions

Is Selenium good for load testing?

Not as the source of the load. Each simulated user is a full browser, which in our tests took about 620 to 680 MiB of memory and more than a CPU core, so one 10-core machine handled about 5 busy browsers before getting slower. The Selenium documentation advises against using it for performance testing and points to dedicated tools such as JMeter.

How many users can Selenium simulate on one machine?

Far fewer than a protocol-level tool. On a 10-core machine with 64 GB of memory, we tried 1, 5, 10 and 20 headless Chrome sessions: page views per second were highest with 5 and dropped with 10 and 20, while 20 sessions used 12.1 GiB. A realistic page with heavier scripts would lower that further. Plan on about five busy browsers per 10 cores, or a few dozen if each pauses between pages, not hundreds.

Can Selenium Grid be used for load testing?

Selenium Grid runs browser tests in parallel across several machines and browser versions, and its documentation does not mention load testing. It adds capacity by adding machines, but every simulated user still needs its own browser, so the cost per user stays the same. It suits running a functional test suite faster, not generating thousands of users.

What is the difference between JMeter and Selenium?

JMeter sends protocol-level requests such as HTTP from lightweight threads and is built for load and performance testing, so one machine can simulate thousands of users. Selenium automates a real browser and is built for functional testing of what users see and do. JMeter’s WebDriver Sampler plugin can run a few Selenium sessions inside a JMeter load test.

How do you measure front-end performance during a load test?

Generate the load with a protocol-level tool and run a small number of real browsers against the important pages at the same time, recording their load and rendering times. Compare those timings with a run at normal load. Keep the browsers on a different machine from the load generator so they do not compete for the same CPU.

Sources

  • Selenium documentation, read 7 November 2026: Performance testing (discouraged practices) and Grid.
  • k6 browser module purpose: Grafana k6 documentation, grafana.com/docs/k6/latest/using-k6-browser/, read 7 November 2026.
  • LoadFocus regions and page speed monitoring: loadfocus.com/index.md and loadfocus.com/page-speed-monitoring, read 7 November 2026.
  • Test runs: Selenium 4.52.0 (Python 3.12) with headless Chrome 157.0.8103.38 and chromedriver from Selenium Manager, and k6 v2.3.0 (official macOS arm64 release, checksum-verified), against a local Node.js 23.11.1 server, on an Apple M1 Max (10 cores, 64 GB), 7 November 2026. Memory is the summed resident set size of each process tree, which counts shared pages more than once. Timings show patterns, not benchmarks.

Bogdan

Founder at LoadFocus

Bogdan builds and runs the tools this blog is about. He writes from what the products actually do in production, including the parts that break.

Weekly tips right in your inbox.

Don’t miss out on the latest testing tips and tricks, tools and news related to software testing.

Already +20,000 members in the list.

The Load Testing Platform with AI That Explains Your Results

Load test websites and APIs from 25 cloud regions, monitor page speed and uptime, and get AI analysis that explains your results in plain English.

Cloud load testing, website speed and API monitoring in one place.

Hi there! Can I share a cool thing I'm working on with you?

A software testing newsletter that sparks joy.

Our goal is to create helpful content for software developers and testers.

If you're not into it, you can unsubscribe instantly.