Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Short answer: Use Selenium to measure a small set of realistic, browser-visible journeys and to collect browser diagnostics. Do not use it as your primary high-concurrency load generator. Pair a controlled protocol tool such as Apache JMeter with a smaller Selenium cohort that verifies the experience real users see.

What Selenium can—and cannot—measure

Selenium WebDriver is a language-neutral API and protocol that drives a real browser through a browser-specific driver. A test framework around WebDriver supplies assertions, setup, teardown and reporting; WebDriver itself does not provide those functions.

The Selenium project describes its scope simply: “Selenium automates browsers. That’s it!” Its performance guidance also says that “Performance testing using Selenium and WebDriver is generally not advised.” That warning is about methodology, not an inability to record timings. A browser run is affected by browser startup, rendering, third-party JavaScript and CSS, HTTP-server behavior, the driver, and WebDriver instrumentation. Those factors can vary independently of the application you want to evaluate.

Good questions for Selenium

  • Can a representative user sign in, search, check out or open a dashboard successfully?
  • How long does each browser-visible step take?
  • Which request, console error or JavaScript exception accompanies a slowdown?
  • Does the journey work across the browsers and devices your users actually use?

Questions for a protocol-level load tool

  • How many concurrent requests can the service sustain?
  • What throughput, latency distribution and error rate occur as traffic rises?
  • When do CPU, memory, database connections or queues saturate?

Apache JMeter is an open-source Java application for load testing and performance measurement across web, API, database, messaging, FTP and other protocols. It does not render pages or execute page JavaScript, which makes it far more efficient for large virtual-user populations.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a representative browser journey

  1. Define one business-critical path. Start with sign-in, product search, checkout or a key dashboard rather than a large regression suite.
  2. Freeze the context. Record browser and version, operating system, viewport, geography, network conditions, test-data identifiers and application build.
  3. Define readiness. Decide which visible state means a step is complete: a results container populated, a confirmation heading displayed or a dashboard widget containing data.
  4. Define outputs. Capture step duration, navigation and resource timing where available, failed requests, console errors, JavaScript exceptions and the final pass/fail result.

Keep the journey small and stable. Every extra click increases the number of unrelated variables and makes a performance regression harder to attribute.

Set up Selenium for repeatable measurements

Prerequisites

  • A supported Selenium language binding and test runner.
  • The target browser installed on the test host.
  • A compatible browser driver, or Selenium Manager where your binding supports automatic driver management.
  • Stable test accounts and data that can be reset between runs.
  • A machine or CI worker whose CPU, memory, network and screen configuration you can record.

Use explicit waits for application state instead of arbitrary sleeps. Keep browser options, window size, authentication setup and cleanup identical for every repetition. A headless browser can be useful for CI, but do not compare headless and headed results as though they were the same environment.

Python example: time a journey and retain browser evidence

The following example uses Selenium with Python. It measures navigation and individual steps, waits for a meaningful state, and records browser logs when the driver exposes them. Replace the URLs, selectors and credentials with values from your test environment.

from time import perf_counter
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

URL = "https://example.test/login"
TIMEOUT = 20

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--window-size=1440,1000")
# Keep the same options for every run in a comparison.

driver = webdriver.Chrome(options=options)
wait = WebDriverWait(driver, TIMEOUT)
marks = {}

try:
    start = perf_counter()
    driver.get(URL)
    wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "form#login")))
    marks["login_page_ready_s"] = perf_counter() - start

    step = perf_counter()
    driver.find_element(By.NAME, "email").send_keys("load-test@example.test")
    driver.find_element(By.NAME, "password").send_keys("test-password")
    driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
    wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "main.dashboard")))
    marks["dashboard_ready_s"] = perf_counter() - step

    navigation = driver.execute_script("""
        const n = performance.getEntriesByType('navigation')[0];
        return n ? {domContentLoaded: n.domContentLoadedEventEnd,
                    loadEvent: n.loadEventEnd,
                    responseEnd: n.responseEnd} : null;
    """)
    print({"marks": marks, "navigation": navigation,
           "browser": driver.capabilities.get("browserName"),
           "browserVersion": driver.capabilities.get("browserVersion")})
finally:
    # Save screenshots, page source or logs here when a run fails.
    driver.quit()

perf_counter() measures elapsed time in the test process; the browser Performance API provides additional navigation timings. Neither is a universal “page speed” number. State exactly which event starts and ends each measurement, and preserve the raw values rather than reporting only an average.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Collect network and console diagnostics with WebDriver BiDi

Where your binding and browser support it, enable WebDriver BiDi. BiDi uses a WebSocket connection to stream asynchronous network requests, console messages, JavaScript errors, script events and browser events. This gives you evidence to explain a slow step instead of only a duration.

BiDi is the standards-based direction Selenium documents as the cross-browser replacement path for Chrome DevTools Protocol, but implementation coverage is still evolving. Check the support level of your exact Selenium binding and browser combination before making a test dependent on a particular event.

At minimum, log request failures, console errors and uncaught exceptions with a timestamp and URL. Correlate those records with the step that was running; otherwise a background analytics request can be mistaken for the cause of a user-visible delay.

Run controlled repetitions and analyze variation

  1. Warm up. Launch the environment and perform several unrecorded runs so browser startup, caches and one-time application initialization do not dominate the sample.
  2. Repeat enough times to expose spread. Keep the number of repetitions, pauses and data reset procedure constant. A single run is an observation, not a baseline.
  3. Store raw results. Save every step duration, outcome, browser and driver version, operating system, viewport, location, build identifier and test-data key.
  4. Compare distributions. Use medians and percentiles, plus the number of failures, rather than treating one unusually fast or slow run as representative.
  5. Investigate outliers. Check CPU throttling, network changes, third-party resources, garbage collection, browser startup and driver logs before declaring an application regression.

For a useful baseline, compare the same journey on the same class of worker. If the environment changes, mark the comparison accordingly; a faster result on a different machine is not proof that the application improved.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use JMeter for concurrency, Selenium for user-visible checks

Build the high-volume portion of the test in JMeter or another protocol-level tool. Model the HTTP or API requests, authentication, test data and ramp-up pattern there. Measure throughput, response-time percentiles, error rates and server-side resource behavior under a controlled load.

Run a small Selenium cohort at the same time. Its job is to answer whether the critical journey still completes in a real browser while JMeter applies pressure. This two-layer design separates capacity measurement from browser fidelity:

Concern Selenium JMeter or similar protocol tool
Browser fidelity Real browser, driver and page JavaScript HTTP/protocol requests; no rendering or page JavaScript
Concurrency efficiency Each session consumes substantial CPU, memory and startup time Many lightweight virtual users
Diagnostics Browser timings, network events, console and script errors Request-level results and server-side observations
Cross-browser coverage Directly exercises browser/driver combinations Does not validate browser rendering
Repeatability Requires tight control of machine, browser and network variables Request generation is easier to control

Do not turn a Selenium regression suite into a synthetic load test by multiplying browser processes. That usually measures the limits of the test workers and the browser fleet before it measures application capacity.

Parallel and remote execution with Grid

Selenium Grid and RemoteWebDriver place browser sessions on remote machines and allow parallel execution across browser and operating-system combinations. Use them when you need cross-browser coverage or faster completion of a bounded set of journeys.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A practical Grid architecture

  • The test runner defines the journey and sends WebDriver commands.
  • Selenium Server or Grid routes each session to a node with the requested browser.
  • Each node reports browser results, logs and artifacts back to the test system.
  • CI stores timing data alongside the node, browser, driver and build metadata.

Grid increases browser-check throughput; it does not remove browser startup, rendering, third-party-resource or WebDriver variability, and it is not a replacement for a lightweight load generator. Hosted Grid capacity, CI workers and observability storage can add operational cost, so account for those separately from the Selenium software itself.

What to record for every result

  • Journey and step names, start/end event definitions and pass/fail status.
  • Browser name and version, driver version, Selenium binding version and operating system.
  • Viewport, device scale factor, headless or headed mode, location and network profile.
  • Application build, feature flags, account or fixture identifier and cache state.
  • Navigation/resource timings, failed requests, console messages, JavaScript exceptions and screenshots or page source for failures.

Without this context, a timing is difficult to reproduce and unsafe to compare with another run.

Troubleshooting common failures

The driver cannot start

Cause: The browser and driver are incompatible, the executable is missing from the environment, or a CI sandbox blocks startup. Fix: Record both versions, use a supported driver-management method, verify the executable path, and run a minimal local smoke test before adding performance instrumentation.

Results fluctuate wildly

Cause: Shared CPU, changing network conditions, cold caches, browser startup, third-party calls or background CI jobs. Fix: Warm up, isolate or reserve workers, keep the environment constant, control caching deliberately and inspect raw events before calculating percentiles.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The test times out although the page eventually works

Cause: The wait targets the wrong selector, a single-page application has not reached its ready state, or a request failed silently. Fix: Wait for a user-meaningful state, capture console and network errors, and distinguish a failed request from a slow but successful render.

Parallel sessions interfere with one another

Cause: Shared accounts, mutable fixtures, ports, downloads or server-side rate limits. Fix: Allocate isolated data and profiles, namespace files and accounts, and document any intentional rate limiting.

BiDi events are unavailable

Cause: The binding, browser or driver version does not implement the event you requested. Fix: Check the current support for that combination, upgrade consistently, and keep core timing assertions independent of optional diagnostics.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your requirement is simply a clean image or PDF of a page rather than an interactive Selenium journey, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers report the page verdict and billing status.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

One GET request is enough:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the complete parameter reference and options in the ScreenshotNeo documentation. The same request in Python is:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

And in Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets and custom viewports, retina scale, PDF paper sizes and page ranges, custom CSS and JavaScript, clicks before capture, selector waits, delay or network-idle waits, request and resource blocking, custom headers/cookies/user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, selectable-TTL caching, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Its MCP server exposes take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients. Parameter names used by other screenshot APIs also work, which can simplify migration.

The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account to try it.

FAQ

Can Selenium test concurrent users?

It can run multiple browser sessions, especially through Grid, but that is usually an inefficient way to model a large user population. Use a protocol-level load generator for concurrency and retain Selenium sessions for browser checks during the load.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How should page-load time be defined?

Define a start event and a user-meaningful end state, such as a results list or dashboard becoming usable. Record navigation timings separately so readers can distinguish network completion from application readiness.

Should functional and performance tests share one suite?

They may share page objects and fixtures, but keep measurement setup, assertions and reporting distinct. Functional waits prioritize correctness, while performance experiments require controlled timing and statistical comparison.

When is Selenium Grid worth using?

Use Grid when parallel browser coverage, remote machines or multiple browser and operating-system combinations are requirements. Do not adopt it merely to generate high-volume traffic; it does not replace a protocol-level load tool.

Frequently Asked Questions

Does Selenium itself provide performance reports?

No. WebDriver drives the browser; your language test framework and reporting or observability system must collect assertions, timings and artifacts.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Is headless mode always faster than headed mode?

Not necessarily, and results from the two modes are not directly interchangeable. Treat the mode as part of the test environment and compare like with like.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.