Short answer: Selenium’s official Docker video recorder does not record a browser running in pure headless mode. To save test videos, run the browser with a display-backed X server (Xvfb) inside Docker, then pair it with a separate selenium/video recorder container. Set se:recordVideo to true and mount the recorder’s /videos directory to your host so CI can retain the MP4.
What “headless recording” means in Docker
There are two different setups people call headless. A browser can run in pure headless mode, with no display server, or it can run unattended inside a container while still rendering to a virtual display such as Xvfb. Those are not equivalent for video capture.
SeleniumHQ’s docker-selenium documentation explicitly says, “Video recording for headless browsers is not supported.” The supported route is to render the browser through the display-backed setup provided by the Docker image and let the separate video service capture that display. The test still runs without a person watching it; “headless” in this practical sense means unattended, not a pure headless browser process.
How the official Docker recording setup works
The selenium/video image runs FFmpeg separately from the browser. Use one video container for each browser container. The recorder and browser must be able to communicate over the Docker network and share the Selenium session or event information required by the chosen Grid arrangement.
#1 Best Overall
The recorder writes files under /videos. That directory is inside the container unless you bind-mount it to the host or a persistent volume. Without a persistent destination, the MP4 can disappear when the container is removed, even though the test itself passed.
- Browser container: runs Chrome or another supported browser and the WebDriver session.
- Video container: captures the display and encodes the session with FFmpeg.
- Shared network: lets the recorder associate its capture with the correct browser session.
- Persistent output: preserves the resulting recording for CI artifact collection or later upload.
Configure the browser for recording
Use a display-backed browser configuration. The Selenium Docker README’s current Chrome guidance notes that Chrome/Chromium v127 and later requires SE_START_XVFB=true when using --headless=new. From Chrome 132 onward, --headless runs in the new mode, so the same Xvfb setting is needed for recording. Pin your browser and Docker image versions in CI, and confirm this behavior against the README when upgrading.
Give the browser container sufficient shared memory. Selenium’s examples use --shm-size="2g"; this is an example configuration, not a guarantee that every workload needs exactly that amount. Browser memory demand depends on page complexity and test concurrency.
For Dynamic Grid, request recording through Selenium capabilities. A representative payload is:
{
"browserName": "chrome",
"platformName": "linux",
"se:recordVideo": true,
"se:screenResolution": "1920x1080",
"se:name": "checkout_regression"
}
se:recordVideoenables the recording.se:screenResolutionsets the display dimensions when consistent video dimensions matter.se:namesupplies a readable test or suite label. The README describes sanitizing names, replacing spaces with underscores, restricting allowed characters, and imposing a 255-character limit before the session identifier is appended.
Standalone, Hub/Node, and Dynamic Grid have different orchestration details. Follow the example for the topology you are actually running rather than assuming that a capability alone starts every needed service.
Start the recorder and preserve the MP4
- Choose matching image versions. Run a browser image and a
selenium/videoimage on the same Docker network. The official examples include tags such asselenium/video:ffmpeg-8.1-20260905; use a tested, pinned tag in CI rather than relying onlatest. - Start the browser with a display-backed configuration. Enable Xvfb as required for your Chrome version and use adequate shared memory.
- Start one recorder per browser container. Ensure both containers can reach the session or Grid event endpoints used by your setup.
- Mount the output directory. Bind a host directory to the recorder’s
/videospath, or use the documented Grid assets directory for the relevant Grid example. - Create a WebDriver session with recording enabled. Send the
se:recordVideocapability and, where useful, a resolution and unique name. - Wait for session closure and collect the artifact. Let the recorder observe the session ending, then have CI archive the MP4 from the mounted host directory.
For Grid 4.41.0, Selenium documents event-driven recording: it starts on session-created and stops on session-closed. That lifecycle replaces timer-based guesses about when a recording should begin or end. If using a different Grid version or topology, check its matching documentation rather than assuming the same lifecycle behavior.
Rank #3
Do-it-yourself example: Docker Compose pattern
The following is a topology illustration, not a universal drop-in Compose file: the exact browser, Grid endpoint, capabilities, and recorder environment vary by Selenium image and whether you use Standalone, Hub/Node, or Dynamic Grid. Use the official example for the selected topology, keep both services on one network, and mount the recorder output to a host directory.
services:
chrome:
image: selenium/standalone-chrome:PINNED_TAG
shm_size: "2g"
environment:
SE_START_XVFB: "true"
networks: [selenium]
video:
image: selenium/video:ffmpeg-8.1-20260905
depends_on: [chrome]
volumes:
- ./artifacts/videos:/videos
networks: [selenium]
networks:
selenium: {}
Replace PINNED_TAG with a browser image tag you have validated. The official video examples may require additional environment settings to identify the browser container or Grid endpoints; configure these according to the matching docker-selenium README. Create the WebDriver session with the capability JSON above and point your test to the Selenium endpoint in the topology. After the session ends, look for the MP4 under ./artifacts/videos.
Parallel tests, naming, and artifact retention
Parallel sessions
Keep the mapping one recorder to one browser container. When scaling out, provision another video container for each browser container and ensure the output names or destinations remain distinct. If several recorders write into one directory, set SE_VIDEO_FILE_NAME or distinct se:name values to reduce collisions.
Retain only the videos you need
Video is useful for diagnosing flaky or environment-specific failures, but retaining every successful run can increase CPU use and storage. Apply a retain-on-failure policy in the CI orchestration layer if that matches your debugging needs. Selenium’s README also documents rclone-based upload settings for S3/GCS-compatible storage, allowing recordings to be moved off ephemeral CI workers. Credentials, bucket access policy, encryption, and retention rules are deployment choices that your team must configure.
Performance and reliability planning
SeleniumHQ warns that recording uses considerable CPU and recommends estimating about one CPU per video container and one CPU per browser container. Treat that as a planning estimate from Selenium, not a benchmark or fixed requirement for every test. Measure your own workload if scheduling limits, test duration, or recording quality are sensitive.
- Budget CPU for both browser rendering and video encoding.
- Expect storage use to grow with recording duration, resolution, and retention period; no universal file size is established by the cited documentation.
- Use pinned browser and recorder image tags so a CI run does not silently change after an image update.
- Persist recordings outside disposable containers, then confirm your CI artifact step runs after the recorder has finalized its output.
- Record selectively if the diagnostic value does not justify the added CPU and storage cost.
Troubleshoot missing, empty, or incomplete recordings
| Symptom | Likely cause | What to check |
|---|---|---|
| No video or an empty file | The browser is in pure headless mode, which the official recorder documents as unsupported. | Use the display-backed Xvfb path and verify the browser is attached to the display the recorder captures. |
Chrome 127+ recording does not work with --headless=new |
Xvfb is not enabled in the Docker browser setup. | Set SE_START_XVFB=true and confirm the container actually starts the virtual display. |
Chrome 132+ recording fails with --headless |
Chrome’s --headless selects the new headless mode. |
For recording, retain SE_START_XVFB=true and use the display-backed path. |
| Recording starts or stops at the wrong time | A timer-based lifecycle may not align with actual session events. | Grid 4.41.0 documents event-driven start on session-created and stop on session-closed; verify your version and topology support the relevant behavior. |
| The MP4 exists in the container but not on the CI host | /videos or the applicable Grid assets directory was not persisted, or artifact collection ran too early. |
Check the bind mount and collect artifacts after session closure and recorder finalization. |
| One recording overwrites or collides with another | Multiple recorders are writing to the same location with non-unique names. | Use a unique se:name or SE_VIDEO_FILE_NAME and preserve one-to-one recorder mapping. |
| Recorder cannot associate with a browser | The recorder and browser may not share a network or may not have access to the needed session/event endpoints. | Check container networking, endpoint configuration, and that the browser/recorder pairing matches the chosen Grid example. |
Or skip the browser setup
If what you need is a screenshot of a web page rather than a video of a Selenium test session, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF; it does not replace video recording of an interactive test.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallBest Value
- Docker, Docker Swarm, Docker Compose, Programmer, Developer, Coding, Programming, Software Engineer, Code, DevOps, Deploy, Deployment, Kubernetes, Salt, Puppet, Chef, Terraform, Container, AWS, Azure, Cloud, Geek, Funny, Computer, Software, Tech, IT
- Integration, Scrum, Compile, Compilation, Science, Bug, Debug, Python, Linux, Java, Javascript, Scala, Dotnet, Kotlin
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
cURL example, with the target URL adapted to the page you want:
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 ScreenshotNeo API documentation for options and response details. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000 shots. Sign up for ScreenshotNeo free.
Frequently Asked Questions
Can the official Selenium Docker recorder capture pure headless Chrome?
No. SeleniumHQ documents recording for headless browsers as unsupported; use the display-backed Xvfb configuration for video.
Does ScreenshotNeo record Selenium test videos?
No. ScreenshotNeo returns a website screenshot or PDF from a request; Selenium’s separate video recorder is the appropriate tool for test-session video.
Recommended Free Tools
Quick Recap
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.

