How to Troubleshoot Selenium Screenshots When Chrome Runs Out of Memory
Diagnose Chrome memory failures during Selenium screenshots by identifying the memory layer, reproducing growth, and testing targeted fixes.
When Chrome runs out of memory during a Selenium screenshot job, first identify which memory layer is growing. The cause may be JavaScript heap or retained DOM objects, native allocations, GPU use, other Chrome processes, oversized captures, or too many concurrent sessions. A heap snapshot can reveal retained JavaScript and DOM objects, but it cannot account for all Chrome memory. Headless mode, a Chrome flag, or more RAM is not a universal fix.
Use this sequence: record versions and resource limits, reproduce the failure with one controlled variable at a time, compare heap snapshots around repeated work, and use process or native profiling if the heap does not explain the growth. Selenium’s Chrome guidance says the Chrome and ChromeDriver major versions should match. Selenium: Chrome-specific functionality.
1. Record the failure before changing anything
Collect enough context to distinguish a page leak from a capacity or capture-size issue. Record:
- Chrome and ChromeDriver versions, including the actual browser binary and driver executable used.
- Operating system, container memory limit, shared-memory limit if applicable, and whether the process is running in a container.
- Selenium version, headless or headed mode, command-line arguments, and whether sessions share a profile.
- Viewport width and height, whether you capture the viewport or a full page, and the frequency of captures.
- Number of simultaneous Chrome sessions and the number of tabs or windows per session.
- Whether memory rises after each navigation, after each screenshot, only on particular pages, or only as concurrency increases.
- The exact failure signal: Selenium exception, Chrome crash, operating-system/container out-of-memory termination, or a screenshot that is missing or incomplete.
Track Chrome’s process tree and host/container memory over time, alongside job number and capture dimensions. Use the same page set and workload for each comparison. A single high reading does not establish a leak; a repeatable upward trend that persists after returning to a clean page is more useful evidence.
2. Verify the Selenium and Chrome setup
Confirm the browser and ChromeDriver major versions match. Also confirm the binary path and arguments that Selenium actually starts; a locally installed Chrome may differ from the browser in a CI image or container. Selenium documents Chrome options such as headless mode and a custom user data directory in its Chrome documentation.
This Python example creates a fresh driver, records browser capabilities, sets a controlled viewport, waits for the document, saves a screenshot, and always quits Chrome. Install Selenium with python -m pip install selenium; Selenium Manager can resolve a driver in supported setups. If your environment pins ChromeDriver separately, ensure its major version matches Chrome.
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
url = "https://example.com"
out = Path("shot.png")
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--window-size=1280,900")
# Set this only when you intentionally need an isolated, persistent profile:
# options.add_argument("--user-data-dir=/tmp/selenium-profile")
driver = webdriver.Chrome(options=options)
try:
print("Chrome:", driver.capabilities.get("browserVersion"))
print("Driver:", driver.capabilities.get("chrome", {}).get("chromedriverVersion"))
driver.set_window_size(1280, 900)
driver.get(url)
WebDriverWait(driver, 30).until(
lambda d: d.execute_script("return document.readyState") == "complete"
)
if not driver.save_screenshot(str(out)):
raise RuntimeError("Chrome did not save the screenshot")
print("Saved", out.resolve())
finally:
driver.quit()
Headless Chromium supports server-side bitmap generation, but that fact does not establish that headless mode uses less memory or fixes an out-of-memory failure. Treat headed versus headless as a workload comparison, not as a presumed remedy. The current Chromium headless documentation also describes version-specific migration from the old headless implementation; check it against the Chrome version you deploy: Chromium: Headless Chromium.
3. Determine whether JavaScript or DOM objects are retained
For a suspected renderer leak, take heap snapshots around the repeated operation. In Chrome DevTools, open the Memory panel and record a snapshot before the operation. Run a representative navigation-and-capture cycle, return to a clean state or perform the inverse action, repeat the cycle several times, and take another snapshot. Compare the snapshots for objects that remain reachable, detached DOM trees, and their retaining paths. The Chrome DevTools heap snapshot guide describes snapshot comparison.
- Use a small, repeatable page sequence rather than a broad production batch.
- Capture the baseline after the browser has settled, not during initial startup.
- Repeat the same navigation and screenshot sequence several times.
- Return to the same clean state between runs where possible.
- Compare snapshots and inspect retaining paths for objects or DOM subtrees that accumulate.
- Change cleanup or references only when the snapshots implicate them, then repeat the same comparison.
A heap snapshot is not a complete Chrome memory report. It observes reachable JavaScript and related DOM data in a context; it does not explain every native allocation, GPU resource, browser process, or other subsystem. Chromium’s memory documentation explicitly cautions that “No single tool can give a full view of memory usage in Chrome.” See Chromium memory tools.
4. Match the diagnostic tool to the memory layer
| Evidence or suspected layer | Useful next step | What it can establish | Limit |
|---|---|---|---|
| Heap grows and objects remain reachable | DevTools heap snapshots; inspect retaining paths and detached DOM trees | JavaScript/DOM objects retained between comparable points | Does not cover all process, native, or GPU memory |
| One Chrome process or subsystem grows | Chromium Global Memory Dumps or memory-infra trace | Per-process and subsystem allocation patterns | Self-reported subsystem statistics can omit resources; tracing data can be large |
| Native allocations change over time | Native heap dumps and Chromium’s diff_heap_profiler.py workflow | Changes in native heap allocations | Requires profiling setup and still does not represent every memory category |
| Growth appears only at larger screenshots | Hold workload constant and reduce viewport or full-page dimensions | Whether capture dimensions correlate with the failure | Correlation does not by itself identify the allocator or prove a retained buffer |
| Growth appears only with more sessions | Compare one session with current concurrency | Whether aggregate workload or concurrency is a trigger | Does not define a universal safe concurrency level |
Chromium describes the strengths and blind spots of its memory profiling tools. Large traces and dumps can burden the tools used to inspect them. Start with the narrowest measurement that can answer the question, and preserve the same workload while comparing results.
5. Check screenshot-specific dimensions and capture frequency
Keep viewport size, page set, and capture frequency fixed while diagnosing. Compare viewport screenshots with full-page screenshots only as a deliberate experiment. A full-page capture can involve much larger image dimensions than a viewport capture, but the dossier provides no universal memory multiplier or safe size threshold.
Chrome DevTools Protocol tracing has parameters named screenshotMaxSize and screenshotMaxCount; their combined tracing screenshot footprint is constrained by a per-session budget. That setting applies to screenshots recorded as part of tracing. It does not prove that Selenium’s ordinary save_screenshot call holds the same buffers or follows the same limits. See the protocol’s Tracing domain.
The HeadlessExperimental protocol describes screenshots returned as base64 image data and notes that capture can fail, for example during renderer initialization. This is protocol-specific behavior, not proof that Selenium’s standard screenshot command has the same failure mode. See HeadlessExperimental.
6. Test one mitigation at a time
Run a controlled comparison and change only one factor per run. Start with the factor that matches your measurements:
- Concurrency: compare one Chrome session with the failing session count. If only the parallel run fails, reduce concurrent work and measure aggregate process/container memory before setting a new limit.
- Capture size: keep the page and frequency fixed, then reduce viewport dimensions or capture only the viewport instead of the full page. Check whether the failure tracks the dimensions.
- Capture frequency: space out captures while preserving the same pages. This tests whether repeated operations correlate with growth or a resource that has not been released.
- Page cleanup: when snapshots identify retained objects or DOM subtrees, remove the retaining references or reset the page/session as appropriate, then compare snapshots again.
- Session lifetime: compare a long-lived session with a fresh session for each bounded unit of work. A fresh session can limit accumulated state, but it also adds browser startup overhead; measure both memory and throughput.
- Host/container capacity: if process or subsystem profiling shows genuine capacity pressure without a page-level retention pattern, adjust workload or host/container resources based on measured peak use and operational headroom.
Do not treat --headless, --disable-dev-shm-usage, --no-sandbox, or a larger memory allocation as a general memory fix. These options address different runtime or environment concerns and are not established by the cited sources as universal remedies for Chrome memory exhaustion. Use an option only when the observed failure and deployment environment support it; changing multiple flags at once makes the result hard to interpret.
7. Troubleshooting common symptoms
| Symptom | Likely interpretation | Next action |
|---|---|---|
| Chrome exits or the container reports an out-of-memory kill | Aggregate process or container usage exceeded a limit; the JS heap may or may not be responsible | Inspect process-level memory and container limits during a controlled run; compare one session with the failing concurrency |
| Heap grows after every repeated page action | Reachable objects or DOM structures may be retained | Compare snapshots and inspect retaining paths; validate cleanup with another snapshot pair |
| Heap looks stable but total memory rises | Growth may be native, GPU, another Chrome process, or outside the heap snapshot’s coverage | Use Global Memory Dumps, memory-infra, or native heap profiling as appropriate |
| Only full-page or large viewport captures fail | Capture dimensions may correlate with peak resource use | Hold other variables constant and lower dimensions; do not infer an exact buffer allocation from correlation alone |
| Only parallel jobs fail | Aggregate concurrent demand may exceed available capacity | Measure aggregate process-tree and container memory at one session and at current concurrency; set limits from the measurements |
| ChromeDriver cannot start Chrome or commands fail immediately | Browser/driver mismatch, wrong binary, or invalid startup arguments are possible | Print capabilities and startup configuration; verify Chrome and ChromeDriver major versions match |
| Screenshot is absent during renderer startup | Capture can fail while the renderer initializes in the HeadlessExperimental protocol | Wait for the page’s required state and retry only under a bounded policy; distinguish startup/capture failure from a memory diagnosis |
| Profiling trace becomes huge or the inspector struggles | Collection or trace size may burden the analysis tools | Shorten the recording and narrow categories/workload; use a smaller reproducible case |
8. Performance, reliability, and cost considerations
Heap snapshots, memory dumps, and traces add collection and analysis work. Use short, representative runs and compare like with like. A fresh browser per unit of work can bound retained state but increases startup work. Lower concurrency can improve stability when aggregate demand is the trigger, while reducing capture dimensions may address only workloads correlated with large images. Measure wall time, failure rate, peak memory, and screenshot dimensions together before choosing a production trade-off.
No official source in the dossier establishes a universal RAM allocation, concurrency ceiling, or memory saving from headless mode. Capacity planning should therefore use the limits and representative peak measurements from the actual host or container. Profiling overhead and large artifacts also have a cost: collect only enough data to identify the responsible layer.
Or skip the browser setup
If the job is to capture web pages rather than exercise Selenium-specific browser behavior, ScreenshotNeo is a website screenshot API and MCP server. Its one-call API can return a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
- Cookie and consent banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off.
- Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools 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; every feature is available on every plan.
Sign up for 1,000 free screenshots a month, with no card.
FAQ
Does a JavaScript heap snapshot show all Chrome memory?
No. It helps find reachable JavaScript and DOM retention. Use process, subsystem, or native profiling for memory outside that view.
Will headless mode fix Chrome running out of memory?
Not by itself. Headless Chromium supports server-side bitmap generation, but the cited guidance does not say it inherently reduces memory use or resolves out-of-memory failures.
Do tracing screenshot limits apply to Selenium screenshots?
The documented screenshot buffer budget is for screenshots captured by DevTools tracing. Do not assume it describes Selenium’s ordinary screenshot command.
When should I add more memory?
When measurements show process or subsystem demand approaching the host/container limit and profiling does not point to avoidable retention. The sources establish no universal allocation.
What if I need Selenium interactions as well as screenshots?
Keep Selenium for interaction and browser automation. The API alternative is for capture workflows where managing a local Chrome session is not needed.


