How to Take a Selenium Screenshot When Chrome Runs in a Kubernetes Pod
Capture a Selenium screenshot from Kubernetes and get it to the right filesystem. Compare WebDriver bytes, shared volumes, and Grid asset storage.
Short answer: Take the screenshot through Selenium after the page reaches the state you need, then make the image available to the process that stores your test artifacts. For a remote Chrome session, the simplest portable approach is usually to return PNG bytes through WebDriver and write them on the test client. A path passed to Chrome or a remote browser process does not automatically refer to a path on your test runner.
This guide covers a remote Selenium session, which is common when Chrome runs in a Kubernetes pod managed by Selenium Grid. If your test process and Chrome run in the same container, a local file path can work directly. For durable artifacts, upload the screenshot to your CI artifact store or another persistent destination before the pod is removed.
1. Return screenshot bytes to the test client
Python’s get_screenshot_as_png() returns PNG bytes through the WebDriver session. Write those bytes from the test process, where the CI runner can collect them. Replace the Grid URL and artifact path with values for your deployment.
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless")
driver = webdriver.Remote(
command_executor="http://selenium-grid.example:4444",
options=options,
)
try:
driver.get("https://example.com")
# Capture the current browser window as PNG bytes.
png = driver.get_screenshot_as_png()
output = Path("artifacts/page.png")
output.parent.mkdir(parents=True, exist_ok=True)
output.write_bytes(png)
finally:
driver.quit()
The screenshot operation captures the current window. Do not assume it captures the whole document on a long page. Selenium also offers file and base64 screenshot APIs; for element-focused output, use an element screenshot where that better matches the artifact you need. See the Selenium Python Chromium WebDriver API and Selenium screenshot documentation.
Save directly to a file when the filesystem is shared
If the process that handles the screenshot command and the process that collects artifacts share a filesystem, save to an absolute path and check whether the write succeeded:
from pathlib import Path
output = Path("/tmp/artifacts/page.png")
output.parent.mkdir(parents=True, exist_ok=True)
saved = driver.get_screenshot_as_file(str(output))
if not saved:
raise RuntimeError(f"Selenium could not write screenshot to {output}")
Use a .png filename and ensure the destination directory exists and is writable. Selenium’s API describes get_screenshot_as_file as saving the current window to a PNG file and recommends a full path. With a remote driver, verify which machine or container owns that path before relying on it.
Capture an element instead of the window
For a chart, table, or component, capture that element rather than the whole browser window:
chart = driver.find_element("css selector", "#chart")
png = chart.screenshot_as_png
Path("artifacts/chart.png").write_bytes(png)
Wait until the target element exists and displays the intended content before capturing it. An element screenshot avoids unrelated page content, but it does not solve artifact transfer: the returned bytes still need to reach the process or storage location that retains them.
2. Choose where the screenshot should live
| Method | Use it when | Watch for |
|---|---|---|
| WebDriver returns bytes to the test client | You need one or a few screenshots and the test runner should collect them. | Write the returned bytes in the client process; do not expect a remote path to appear locally. |
Shared volume, such as emptyDir |
Cooperating containers in one Kubernetes pod need temporary file access. | emptyDir is shared within the pod but removed when the pod is removed from its node. Copy or upload files before cleanup. |
| Persistent volume or object storage | Artifacts must survive pod deletion or be available to later jobs. | Choose a destination and retention policy that fit your environment. |
| Selenium Grid session assets | Your Grid deployment has Kubernetes asset storage configured and exposes a retrieval mechanism. | Check your Grid version and deployment configuration; do not assume every setup exports files automatically. |
Kubernetes documents that emptyDir is shared among containers in a pod and lasts for the lifetime of the pod on its node. Its volume documentation also warns that hostPath carries security risks, so it is not a casual shortcut for artifact access. See Kubernetes volumes.
Selenium Grid’s CLI reference includes --kubernetes-assets-path, an absolute path where session assets are stored. Verify how your particular Grid version and deployment make those assets retrievable before building a workflow around them. See the Selenium Grid CLI options.
3. Wait for the page state you need
A screenshot taken too early may be blank or stale even when the transfer path is correct. Wait for a page-specific signal, such as the target element becoming visible, before capture. Avoid treating a fixed sleep as proof that the page is ready: network-dependent content can take a different amount of time on each run.
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
# After driver.get(...)
WebDriverWait(driver, 20).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "main h1"))
)
png = driver.get_screenshot_as_png()
Path("artifacts/page.png").write_bytes(png)
Choose a condition that represents the content your test needs. If the page changes after that condition—for example, a chart is rendered asynchronously—wait for a signal from that component too.
4. Copy a screenshot out of a Kubernetes pod
First identify where Chrome and the WebDriver command are running: in the test container, in a sidecar within the same pod, or in a separate Grid-created browser pod. Then pick a transfer method:
- Remote Grid browser: return screenshot bytes through WebDriver and write them in the test client. This avoids guessing where a remote file path points.
- Two containers in one pod: mount the same volume in both containers, write the file there, then let the artifact collector read or upload it. An
emptyDiris temporary. - Retention beyond pod lifetime: upload the file to a durable artifact destination or use storage designed to persist beyond the pod.
- Grid-managed assets: inspect the configured assets path and the retrieval interface supported by your deployment and Grid version.
These choices follow from the separation between a remote WebDriver client and browser process, and from Kubernetes volume lifetimes. They are deployment patterns, not a claim that a particular storage service is required.
5. Use cURL, Python, or Node.js with ScreenshotNeo
If the task is simply to capture a public URL and save an image, ScreenshotNeo can take the screenshot without a Selenium browser pod. It is a website screenshot API and MCP server from ScreenshotNeo; one GET request returns an image or PDF. See the API documentation for parameters and response details.
Or skip the browser setup: cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));
Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Why can’t I find the screenshot file? | The screenshot was written in the browser or Grid container, not the test runner’s filesystem. | Return bytes through WebDriver and write them in the client, or set up a shared or durable storage path. |
| The screenshot method reports a write failure | The path is relative, the directory is missing, or the process lacks write access. | Use an absolute path ending in .png, create the directory, check permissions, and inspect the method’s boolean result. |
| How do I save a screenshot from a remote Selenium node? | A remote session has a distinct browser process and filesystem context. | Use get_screenshot_as_png() or the base64 response and write the returned content in the test process. |
| How do I copy a screenshot out of a Kubernetes pod? | The pod may be deleted before collection, or the test runner may not share its volume. | Transfer bytes to the client, use a volume shared by containers in that pod, or upload to durable storage before cleanup. |
| The file disappeared after the job | The destination was an emptyDir or another pod-local temporary path. |
Upload it before pod removal or select storage with the required retention lifetime. |
| Chrome does not start | Headless configuration may be missing, or Chrome and ChromeDriver may be incompatible. | Check the deployed browser and driver versions, confirm the pod can launch Chrome, and use the documented headless argument where appropriate. |
| The image is blank or stale | The capture ran before the relevant page content was ready. | Wait for the specific element or content state needed by the test, then capture. |
| Grid assets are not retrievable | Asset storage or retrieval may not be configured or supported as assumed in this deployment. | Check the Grid version, configured --kubernetes-assets-path, and deployment-specific retrieval mechanism. |
7. Performance, reliability, and cost
- Transfer overhead: returning bytes through WebDriver carries the image in the screenshot response, then writes it on the client. For a small number of artifacts this is straightforward; for larger volumes, account for response size, storage throughput, and upload time.
- Reliability: capture only after a page-specific readiness condition; create the output directory; check file-write success; and preserve the artifact before ephemeral pods are cleaned up.
- Parallel jobs: use unique filenames or per-job directories so concurrent tests do not overwrite one another.
- Cost: Selenium and Chrome are software, but the browser pods, storage, and CI runtime consume your infrastructure resources. No fixed cost or performance benchmark applies across Kubernetes configurations. Retain only the artifacts needed for debugging or reporting.
8. Frequently asked questions
Does Selenium save the screenshot on the test machine?
Only when the code writing the file runs in a process with access to that machine’s filesystem. For remote sessions, return bytes and write them in the test client.
Does get_screenshot_as_png() capture a full webpage?
It captures the current window. Do not call it a full-page capture unless your implementation separately captures the entire document.
Can I use an emptyDir for CI screenshots?
Yes, for temporary sharing among containers in the same pod. Copy or upload the image before the pod is removed, because the volume does not provide durable retention.
Does Selenium Grid always provide a screenshot download?
No universal retrieval behavior is established here. Check the asset configuration and retrieval mechanism for your Grid version and deployment.


