ScreenshotNeo

BlogHow-to

How to Run Selenium Screenshot Tests on a Low-RAM Linux Server in India

Run Selenium screenshot tests on a memory-constrained Linux server with a pinned Docker image, headless Chrome, and measured concurrency.

By the ScreenshotNeo team4 October 20269 min read

Start with one headless Selenium browser in a pinned standalone Docker image, capture screenshots serially, and measure memory use on your actual pages before increasing concurrency. There is no India-specific Selenium command or universal minimum RAM figure. The right capacity depends on the host’s architecture and limits, browser, page assets, viewport, and test workload. Docker Selenium’s --shm-size=2g is a shared-memory configuration recommendation, not a requirement that the server have exactly 2 GB of physical RAM.

This guide uses Python with Remote WebDriver and Chrome. It covers architecture checks, container setup, repeatable screenshot capture, resource monitoring, troubleshooting, and when a screenshot API can avoid operating a browser container.

1. Check the server before choosing a browser image

Before starting, record the Linux distribution, CPU architecture, memory and container limits, and free disk space. Common architecture names are x86_64 or amd64 and aarch64 or arm64. Confirm that the Selenium Docker image and browser version you plan to use are published for that architecture; availability varies by image and version. The [Docker Selenium README](https://github.com/SeleniumHQ/docker-selenium/blob/trunk/README.md) maintains the image and architecture guidance.

uname -a
uname -m
free -h
df -h
docker version

If Docker has a memory limit configured, inspect that limit too. A host can have available memory while a container is restricted to less. Check the hosting environment’s current resource settings rather than assuming the VM’s advertised memory is all available to the browser.

The official Selenium materials do not give a universal minimum RAM amount for capturing a particular site. Establish a safe session count by observing representative pages on the actual server.

2. Start one pinned standalone Selenium browser

Choose a currently supported, fully specified Selenium image tag for your architecture. Avoid latest in repeatable CI because a floating tag can change the browser and Grid versions between runs. Check the project’s live README for current tags; they change over time.

docker run --rm \
  --shm-size=2g \
  -p 4444:4444 \
  selenium/standalone-chrome:<pinned-full-tag>

Replace <pinned-full-tag> with the exact supported tag you selected. Docker Selenium documents --shm-size=2g as a known browser-container workaround and describes the value as arbitrary and subject to tuning. It sets container shared memory; it does not promise that a host with any particular physical RAM amount will work for every workload. If the host cannot provide that shared-memory allocation, consult the project’s current guidance and monitor the actual workload rather than treating the example as a universal minimum.

The container exposes the Grid endpoint on port 4444. When your test client runs on the host, it can connect to http://localhost:4444. If the client runs in another container, put both containers on a reachable Docker network and use the browser service’s network hostname; localhost inside the client container refers to that client container.

3. Run the browser headlessly and save a screenshot

Headless mode removes the need for a graphical display. SeleniumHQ says headless browser containers do not need Xvfb; this removes a display-server component, but it does not make browser memory use negligible. Follow the current Docker Selenium README for version-specific headless and Xvfb settings. Do not disable Xvfb unless the browser is actually configured to run headlessly.

Install the Selenium Python package in the test environment using your normal dependency-management process. The following example uses Remote WebDriver to connect to the standalone container, sets a viewport, waits for the document to load, saves a PNG, and closes the session even if capture fails:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait

options = Options()
options.add_argument("--headless")

# Set a deliberate viewport for repeatable visual comparisons.
options.add_argument("--window-size=1440,1000")

driver = webdriver.Remote(
    command_executor="http://localhost:4444",
    options=options,
)

try:
    driver.set_page_load_timeout(60)
    driver.get("https://example.com")

    WebDriverWait(driver, 30).until(
        lambda browser: browser.execute_script(
            "return document.readyState"
        ) == "complete"
    )

    if not driver.save_screenshot("screenshot.png"):
        raise RuntimeError("Selenium did not save the screenshot")
finally:
    driver.quit()

Install a compatible Selenium Python client in a virtual environment or pinned project dependency, and make sure the test runner can reach the Grid endpoint. The example combines the documented Remote WebDriver and screenshot patterns; adjust timeouts and readiness checks to the application. document.readyState == 'complete' does not guarantee that a single-page app, delayed image, animation, or API request has finished. Wait for an application-specific selector or state when that matters.

Selenium can also save an element screenshot after locating the element:

element = driver.find_element("css selector", "main")
if not element.screenshot("main.png"):
    raise RuntimeError("Selenium did not save the element screenshot")

For browser and element screenshot methods, see [Selenium’s WebDriver interactions documentation](https://www.selenium.dev/documentation/webdriver/interactions/windows/). For Remote WebDriver and Grid health, see [Grid getting started](https://www.selenium.dev/documentation/grid/getting_started/).

4. Keep memory use bounded and measure before scaling

On a low-memory server, run one browser session at a time first. Exercise the real pages and test steps, then observe host memory, swap activity, CPU, container restarts, and test duration. A page with large images, heavy JavaScript, or multiple tabs may behave differently from a lightweight test page, so use a representative workload.

# In another shell, observe the host while the test runs:
free -h

# Inspect running containers and resource use:
docker stats

Repeat the run enough to notice whether memory use rises across sessions or whether browser processes remain after tests finish. Keep the driver.quit() cleanup in a finally block so exceptions do not leave sessions open. If the runner container is disposable, mount a persistent directory for screenshots and logs; confirm that the container user can write there and that disk space is available.

Increase concurrency only after monitoring the representative workload at the current session count. Compare the saved wall-clock time with peak memory and CPU use. If serial execution is reliable and parallel sessions cause instability, keep the tests serialized or use a host with more suitable resources. A larger Selenium Grid topology adds operational components; introduce it when parallelism needs justify it. Grid configuration controls are documented in the [Selenium Grid CLI options](https://www.selenium.dev/documentation/grid/configuration/cli_options/).

5. Make screenshot results repeatable

  • Pin the browser environment. Use a full Selenium image tag and keep the test dependencies controlled so browser changes do not arrive unexpectedly.
  • Match the viewport. Set a deliberate window size for visual comparisons; responsive layouts change with the viewport.
  • Wait for the page state you need. A navigation completing does not necessarily mean client-side data, lazy images, fonts, or animations are settled.
  • Choose the capture target. Use a full browser screenshot for the visible page or an element screenshot for a specific component.
  • Close every session. Call quit() on success and failure.
  • Check browser compatibility. Selenium’s Chrome documentation says Chrome and ChromeDriver should match at the major-version level. Recheck current compatibility guidance when updating browser versions: [Selenium Chrome documentation](https://www.selenium.dev/documentation/webdriver/browsers/chrome/).

Selenium screenshots capture the browser’s current state; they do not automatically make two runs visually identical. Page data, fonts, network timing, animation, browser version, and viewport can all affect the result. Control or wait for those inputs when the test requires stable comparisons.

6. Troubleshoot common low-memory and capture failures

Symptom Likely cause What to check or change
Chrome exits or crashes in Docker Memory pressure, container memory limits, shared-memory constraints, or browser/driver incompatibility. Check host and container memory, swap, container restarts, and browser compatibility. Review Docker Selenium’s shared-memory guidance; --shm-size=2g is a documented workaround to tune, not a universal total-RAM requirement.
Browser does not start after Xvfb is disabled The browser may not actually be running headlessly. Enable the appropriate headless option for the browser version and follow the image’s current Xvfb instructions. Do not disable the display server without headless mode.
Image fails to start on an ARM server The selected tag may not publish a compatible browser image for that architecture. Check uname -m and the current Docker Selenium architecture matrix. Do not assume AMD64 emulation on ARM64 has normal performance or stability.
Tests fail or become unstable when run together Concurrent sessions may exceed available memory or CPU, or previous sessions may still be running. Serialize tests temporarily, confirm cleanup with quit(), and watch memory and CPU before raising concurrency again.
Remote WebDriver cannot connect The client may be using the wrong endpoint or an unreachable hostname. Check that the browser container is running and port 4444 is reachable. From another container, use the browser service’s network hostname rather than that client’s localhost. Check Grid health at the endpoint documented by the [Grid getting-started guide](https://www.selenium.dev/documentation/grid/getting_started/).
Screenshot is blank, stale, or incomplete Capture may occur before the relevant page content is ready, or the viewport may not match the intended layout. Set the viewport explicitly, wait for an application-specific selector or state, and inspect whether delayed network content, lazy loading, or animation affects the page.
Screenshot file is missing or empty The save call may have failed, the process may lack write access, or the output directory may not persist. Check the method’s boolean return value, output path permissions, free disk, and volume mounts. Save artifacts to a mounted directory when the runner container is temporary.

Chrome’s official guidance covers browser options and version compatibility in the [Selenium Chrome documentation](https://www.selenium.dev/documentation/webdriver/browsers/chrome/). Avoid treating --disable-dev-shm-usage as a universal memory fix: it changes where shared-memory files are used and may shift the constraint rather than remove it.

7. Account for the India hosting context

Selenium’s screenshot API does not change for an India-hosted server. India matters when you choose where the machine runs and what constraints apply to it. Consider the team’s latency and data-location needs, then verify the actual region, CPU architecture, memory limit, bandwidth, and disk available on the selected host. This guide does not establish a provider, region, price, or legal requirement.

For the browser itself, architecture and resource limits are the practical checks: confirm that the exact image tag supports the server’s CPU architecture, and measure the workload on the machine where tests will run.

Or skip the browser setup

If you need website screenshots through an API rather than a Selenium-managed browser, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. One GET request returns an image or PDF; see the ScreenshotNeo API documentation for request options.

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

With Selenium, you manage the browser container, session cleanup, and server resources. ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing status. Its MCP server includes take_screenshot, get_page_info, and capture_pdf tools for AI agents and MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up free for 1,000 screenshots a month, with no card required.

FAQ

How much RAM does Selenium need?

There is no universal minimum in the reviewed Selenium documentation. Measure the target browser and pages under the server’s actual limits, starting with one session.

Can I run Selenium in Docker on a VPS?

Yes, if Docker and a compatible browser image are available for the VPS architecture and resource limits. Start with a standalone image and verify network access, memory, and disk.

Does headless Chrome use almost no memory?

No such guarantee follows from headless mode. It avoids the need for Xvfb in the documented browser-container setup, but the browser and page still use resources.

Should I use Chrome or Firefox?

Choose based on the browser coverage your application needs and the image support for your host architecture. Do not assume one uses less RAM without measuring the same workload.

Can I add parallel tests later?

Yes. Measure peak memory and CPU with representative pages first, then raise concurrency gradually and check reliability at each step.