How to Run Selenium Tests in Docker
Run Selenium tests in Docker with a standalone browser, RemoteWebDriver, and a path to parallel Grid sessions. Includes runnable Python, Node.js, and cURL examples.
To run Selenium tests in Docker, start an official Selenium browser image in Standalone mode, publish port 4444, and point your test client’s RemoteWebDriver at http://localhost:4444. When the tests also run in Docker, put the test and browser containers on the same Docker network and use the browser service name as the Grid hostname. Pin an image version for repeatable browser behavior, and keep the Grid endpoint private.
1. Start with a standalone Selenium browser
Selenium Grid accepts WebDriver commands and routes them to browser instances. Standalone mode puts the Grid components in one process, which makes it the simplest starting point for local development, debugging, or a straightforward CI job. Its default WebDriver endpoint is http://localhost:4444. See the Selenium Grid overview and getting started guide.
Choose a real, versioned tag from the official docker-selenium project. Replace <pinned-tag> below with that tag; it is a placeholder, not a runnable image tag.
docker run -d --name selenium \
-p 4444:4444 \
selenium/standalone-chrome:<pinned-tag>
To use Firefox instead, select the corresponding official standalone Firefox image and a compatible pinned tag:
docker run -d --name selenium-firefox \
-p 4444:4444 \
selenium/standalone-firefox:<pinned-tag>
The Selenium project documents images on Docker Hub and a GHCR mirror under ghcr.io/seleniumhq. Check the official project and release information for current names, tags, and browser/driver compatibility before upgrading. A moving tag such as latest can change the browser environment between runs; versioned tags make it easier to reproduce and debug failures. The official downloads page lists current Selenium releases.
2. Connect a test client with RemoteWebDriver
The client sends WebDriver commands to Grid, which starts or assigns a browser session. This differs from starting a local browser in the test process. The examples below assume the Selenium container’s port is published on the same host as the tests.
Python example
Install the Selenium Python binding in the test environment with python -m pip install selenium. Save this as test_remote.py and run python test_remote.py after starting the container:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
# Add browser arguments here only when your environment requires them.
driver = webdriver.Remote(
command_executor="http://localhost:4444",
options=options,
)
try:
driver.get("https://example.com")
print("Title:", driver.title)
finally:
driver.quit()
Node.js example
Install the JavaScript binding with npm install selenium-webdriver. Save as test-remote.js and run node test-remote.js:
const { Builder, Browser } = require('selenium-webdriver');
(async () => {
const driver = await new Builder()
.usingServer('http://localhost:4444')
.forBrowser(Browser.CHROME)
.build();
try {
await driver.get('https://example.com');
console.log('Title:', await driver.getTitle());
} finally {
await driver.quit();
}
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});
For Firefox, select the Firefox browser in the client capabilities and start a compatible Firefox image. Keep the client binding and browser/Grid versions compatible when upgrading.
cURL: check Grid readiness
cURL is useful for checking whether the Grid status endpoint responds; it does not run a Selenium test. With the published local port, request:
curl --fail --show-error http://localhost:4444/status
A successful status response helps distinguish an unavailable Grid from a problem in the test client or application. It is not proof that a particular browser session will start successfully.
3. Run the test and browser in separate containers
When the test runner itself is in Docker, localhost means the test runner container. It does not point to the Selenium container. Put both services on the same Docker network and connect to the Selenium service name.
Example Compose file, with a placeholder image tag to replace using a tag available in the official registry:
services:
selenium:
image: selenium/standalone-chrome:<pinned-tag>
shm_size: 2gb
expose:
- "4444"
tests:
build: .
depends_on:
- selenium
environment:
SELENIUM_URL: http://selenium:4444
In this layout, the test code should read SELENIUM_URL and use http://selenium:4444 as its RemoteWebDriver endpoint. For example, change the Python executor argument to os.environ.get("SELENIUM_URL", "http://localhost:4444") after importing os. Compose gives the services network access by service name. The shm_size setting allocates shared memory to the browser container; adjust it to your environment’s needs. This sample is a starting point, not a universal CI configuration.
If tests and Grid run on different machines, use a private, reachable endpoint appropriate to that network. Do not assume a container’s internal port is reachable from another host without network routing and access rules.
4. Configure the setup for your workload
| Choice | When to use it | What to check |
|---|---|---|
| Standalone | One browser environment, a local run, or a modest CI job | Published port, correct endpoint, available CPU and memory |
| Browser image | Chrome or Firefox coverage | Image tag and browser/driver compatibility with the client binding |
| Versioned image tag | Repeatable runs and easier failure investigation | Update deliberately; verify current official tags |
| Multiple Grid nodes | More browser types or versions, or concurrent sessions | Host capacity, session capacity, test isolation, and network access |
| Private Grid endpoint | Local, team, or CI use | Only intended test clients can reach the WebDriver endpoint |
Grid is useful for remote execution, parallel sessions, multiple browsers, browser versions, or platform coverage. Begin with one Standalone container, then add nodes when the coverage or elapsed-time need warrants the extra setup. Parallel browser capacity does not make tests safe to parallelize automatically: tests that modify the same accounts, records, or shared environment can interfere with each other. Selenium describes Grid’s role in its documentation and its guide to when to use Grid.
5. Size resources and protect the endpoint
Browser resource needs depend on the host, page, and workload. Selenium’s getting-started guidance offers 1 CPU and 1 GB of RAM per browser as a recommendation, while noting that it may not fit every context and advising ongoing measurement. Use that as an initial planning reference, not a guarantee. Observe CPU, memory, browser startup failures, and test duration under your own workload.
Keep port 4444 reachable only by intended clients. Selenium warns that an inadequately protected Grid can expose infrastructure and internal web applications or files, and may allow third parties to run custom binaries. Bind or route the endpoint privately and apply network or firewall rules appropriate to the deployment. See the security guidance in the Grid getting-started documentation.
6. Troubleshoot common failures
| Symptom | Likely cause | Fix |
|---|---|---|
Connection refused at localhost:4444 |
Container is stopped, port is not published, or the test runs in another container | Check the container state and port mapping. From a test container, use the Selenium service name on the shared Docker network. |
| Remote session creation fails | Requested browser is not available, or image/browser/driver and client capabilities do not match | Use the browser image that matches the requested browser and check the official compatibility information and pinned tag. |
| Tests time out before a session starts | Grid is still starting, host resources are constrained, or the endpoint is unreachable | Check /status, container logs, network reachability, and measured resource use. Allow startup time appropriate to the environment. |
| Works locally but not in CI | Different endpoint, unavailable port mapping, network isolation, or different image tag | Use the CI service hostname and network arrangement, confirm the actual image tag, and inspect the CI job’s container logs. |
| Browser crashes or pages load inconsistently | Resource pressure or workload-specific browser behavior | Measure CPU and memory, reduce simultaneous sessions, and reproduce against a pinned image before changing versions. |
| Tests pass alone but fail in parallel | Tests share mutable accounts or application data | Isolate test data and external resources, or reduce concurrency until the shared-state conflict is fixed. |
| Grid is reachable from an unintended network | Published or routed endpoint is too broad | Restrict binding and network/firewall access to intended test clients. |
7. Performance, reliability, and cost
Standalone mode minimizes topology and operational overhead, but one browser environment limits browser diversity and concurrent work. Multiple nodes can route sessions across browsers and may shorten elapsed suite time when tests are independent and the host has capacity. Estimate capacity with measurements from your own suite; Selenium’s examples are explanatory arithmetic, not benchmark results.
Pinning the image tag improves repeatability, while deliberate upgrades let you take browser and Selenium updates with a known change boundary. Record the image tag used in CI and review it when investigating browser-specific failures. For reliability, check Grid readiness before launching a large test batch, collect container logs on failure, and ensure each test closes its session even when assertions fail.
Docker itself does not set a Selenium service price in this setup; compute and CI costs depend on where containers run and how long they run. Parallelism can reduce elapsed time while increasing simultaneous resource demand. Measure both runtime and resource consumption before deciding whether more nodes save money or time for your workload.
Or skip the browser setup
If the goal is a screenshot rather than interactive browser testing, ScreenshotNeo provides a website screenshot API and MCP server. One GET request can return an image or PDF; see the API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Can I run Selenium tests in Docker without Selenium Grid?
You can run a browser and WebDriver in a container, but the official Selenium Standalone image provides a simple remote Grid endpoint for a test client to connect to. This keeps the browser environment separate from the test process.
Can I use Chrome and Firefox in parallel?
Yes, with browser environments and Grid capacity that support the requested sessions. Configure separate compatible browser images or nodes, then ensure the tests and their application data are safe to run concurrently.
Should I use the latest image tag?
Use an explicit versioned tag when reproducibility matters. Check the official project’s current image tags and compatibility information before updating.
What endpoint should a test container use?
Use the Selenium service or container name and port on the shared Docker network, such as http://selenium:4444. Inside the test container, localhost points back to that test container.


