Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To render and capture a WebGL page with Selenium .NET, run Chrome in headless mode with a fixed viewport, wait for the page’s own signal that its WebGL scene is ready, then save a PNG with Selenium’s screenshot API. Use an element screenshot when you need only the canvas. If ordinary capture is unstable because an animation or compositor frame is still changing, use Chrome DevTools’ BeginFrame workflow instead of relying on a longer fixed sleep.

What Selenium is actually capturing

Selenium does not render WebGL itself. It controls Chrome, and Chrome loads the page, initializes its WebGL context, draws the scene, and exposes the resulting browser output for capture. Chrome’s current headless implementation shares the browser implementation with regular Chrome; since Chrome 112, headless creates platform windows without displaying them. That makes headless Chrome a practical default for unattended capture, but it does not promise pixel-identical output across machines. GPU paths, drivers, fonts, browser versions, device scale factor, available WebGL extensions, and page timing can all affect the result.

There are two separate problems to solve: making sure the scene has reached a useful state, and choosing the right capture scope. A WebDriver screenshot captures the current browser context; a canvas element screenshot captures the canvas region. Neither API can determine by itself that an application-specific WebGL scene is finished loading.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Set up a deterministic Selenium .NET capture

Prerequisites

  • A .NET project and the Selenium WebDriver package. Install or update the package using your normal NuGet workflow.
  • Chrome and a compatible ChromeDriver available to the project. Keep a record of both versions; compatibility and rendering behavior can change across browser updates.
  • A page URL and, ideally, a readiness signal owned by the application, such as a JavaScript flag set after the scene initializes.

The sources establish the Selenium screenshot and DevTools APIs, but do not prescribe a universal Chrome/ChromeDriver version pairing or a flag set that works on every CI host. Use versions supported by your project and deployment environment.

Configure headless Chrome and viewport size

Use a current Chrome headless argument and an explicit viewport. Chrome documents --window-size for choosing dimensions, for example --window-size=1365,900. The dimensions matter because responsive layouts, canvas sizing, and WebGL scene composition may change with the viewport.

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using System;

var options = new ChromeOptions();
options.AddArgument("--headless");
options.AddArgument("--window-size=1365,900");

using var driver = new ChromeDriver(options);
driver.Navigate().GoToUrl("https://example.com/webgl-demo");

// Wait for an application-owned readiness signal (example below).
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.Until(d => (bool)((IJavaScriptExecutor)d).ExecuteScript(
    "return window.webglSceneReady === true;"));

var screenshot = ((ITakesScreenshot)driver).GetScreenshot();
screenshot.SaveAsFile("webgl.png", ScreenshotImageFormat.Png);

Replace the example URL and readiness property with values from the page you are capturing. The example assumes the application exposes window.webglSceneReady; a third-party page may not. If the page offers no explicit flag, use a page-specific condition such as the presence and nonzero dimensions of its canvas, a known loading overlay disappearing, or a stable-frame check. Those are synchronization strategies to implement for the target site, not automatic Selenium WebGL detection.

Wait for readiness rather than guessing

A call to Navigate().GoToUrl indicates navigation progress, not necessarily completion of the WebGL scene. Scripts may still be loading assets, compiling shaders, or drawing animated frames. A fixed delay can help with a known static page, but it is brittle when network and rendering time vary.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Prefer a condition that reflects the page’s actual state. For example, if the page owns the WebGL canvas and you can inspect it, poll for a canvas with nonzero dimensions and a separate application readiness flag. If the scene animates continuously, define what “ready” means for the capture—such as after a particular state is reached—rather than waiting for animation to stop when it never will.

Capture the full page or only the WebGL canvas

Whole browser-context screenshot

ITakesScreenshot.GetScreenshot() returns a Selenium Screenshot; SaveAsFile writes it to disk. Selenium’s documented .NET API supports PNG, BMP, GIF, JPEG, and TIFF. PNG is a sensible default for WebGL screenshots because it preserves text and sharp edges without JPEG compression artifacts.

var shot = ((ITakesScreenshot)driver).GetScreenshot();
shot.SaveAsFile("webgl-page.png", ScreenshotImageFormat.Png);

Canvas-only screenshot

When navigation, controls, or other page UI should not appear in the image, locate the canvas and use Selenium’s element screenshot API. This is a region capture, not a different WebGL renderer.

var canvas = driver.FindElement(By.CssSelector("canvas#scene"));
canvas.GetScreenshot().SaveAsFile("webgl-canvas.png", ScreenshotImageFormat.Png);

Use the actual selector for the target page. If the page has multiple canvases, make the selector specific enough to identify the intended scene. Make sure the element exists and has nonzero dimensions before taking its screenshot.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Stabilize animated scenes with DevTools BeginFrame

For a scene whose animation or compositor updates make ordinary screenshot timing nondeterministic, Selenium .NET documents the DevTools HeadlessExperimental BeginFrame workflow. A BeginFrame command waits for a frame to complete and can optionally return a screenshot. This is a more controlled alternative to increasing a sleep duration, but it is a versioned Chrome DevTools Protocol API rather than the basic WebDriver screenshot path.

The target must have BeginFrameControl enabled; the API is designed for use with --run-all-compositor-stages-before-draw. Exact generated .NET types and command plumbing depend on the Selenium and DevTools protocol versions used by the project. Consult the API documentation for the matching version before wiring it into an application. Do not assume BeginFrame is available merely because ordinary Selenium screenshots work.

Use BeginFrame when the capture must correspond to a controlled completed compositor frame. For a static page with a reliable readiness flag, the simpler WebDriver screenshot call is easier to maintain. The trade-off is synchronization control versus reliance on a DevTools namespace that can change with protocol versions.

Choose options that affect the image

Decision Use it when Considerations
Explicit viewport via --window-size You need repeatable layout dimensions. Use the same dimensions in comparable runs; viewport changes can alter responsive layout and canvas size.
Whole-context screenshot The artifact should include surrounding page content. Uses ITakesScreenshot.GetScreenshot() and saves the current browser screenshot.
Canvas element screenshot You need the WebGL scene without surrounding UI. Target the correct canvas and wait until it is present and sized.
PNG output You need crisp edges and text without lossy compression. Selenium also documents BMP, GIF, JPEG, and TIFF; choose a different format only for a concrete downstream need.
BeginFrame Animation or compositor timing makes ordinary capture unreliable. Requires BeginFrameControl and version-aware DevTools API integration.

Chrome’s command-line screenshot documentation also describes --timeout as a maximum wait before command-line capture, even if loading continues, and --screenshot as writing screenshot.png. A Selenium program normally uses the WebDriver screenshot endpoint rather than Chrome’s command-line --screenshot switch. The broader lesson still applies: set a deliberate viewport and synchronize to meaningful page readiness instead of treating a timeout as proof the scene is ready.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make screenshots reproducible across machines

A fixed viewport and readiness condition reduce avoidable variation, but browser screenshots are not guaranteed to match pixel for pixel across operating systems or hardware. For useful comparisons, record the browser version, ChromeDriver version, viewport, device scale factor, operating system, and whether Chrome ran headless or headed. Also keep the page state and test data consistent.

  • Use the same browser and driver versions when comparing a baseline with a new capture.
  • Keep viewport and device scale factor consistent; both can affect layout and rasterization.
  • Use the same readiness condition and capture scope for each run.
  • For animated scenes, capture a defined state or use a completed BeginFrame rather than an arbitrary delay.
  • Investigate differences in GPU drivers, fonts, and WebGL extensions when the same code produces different output on separate hosts.

These controls improve explainability, not universal pixel equivalence. The browser architecture supports headless capture, while rendering differences remain environment- and page-dependent.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot blank, incomplete, or inconsistent captures

The screenshot is blank or the canvas is empty

  • Check that the page actually created a WebGL context and that its scripts and assets loaded successfully.
  • Wait on a page-owned scene-ready signal rather than assuming navigation completion means rendering completion.
  • Verify the canvas has nonzero dimensions and that the target selector points to the intended canvas.
  • Compare headless and headed runs in the same environment. If output differs, record browser, driver, OS, viewport, and device scale factor before changing flags.

The image captures a loading state

The screenshot call may be racing asynchronous assets, shader setup, or page scripts. Replace a short fixed sleep with an explicit readiness condition. If there is no suitable signal, build a target-specific check, such as waiting for a loader to disappear and a canvas dimension to become nonzero.

Animation frames vary between runs

A continuously changing scene may be captured at different points even when every run succeeds. Define the desired scene state or use DevTools BeginFrame with the required BeginFrameControl support. A longer sleep only shifts the capture later; it does not ensure the same frame.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Canvas-only capture fails or includes the wrong area

Confirm that the canvas selector matches one visible element, wait until it is present and sized, and use the element screenshot method rather than the driver-level screenshot. If the page contains multiple canvases, narrow the CSS selector.

CI output differs from a developer workstation

Do not attribute every difference to headless mode. Compare the recorded browser and driver versions, viewport, device scale factor, operating system, GPU/driver path, fonts, and WebGL extension availability. The Chrome headless implementation shares browser code with regular Chrome, but that does not make hardware and software environments identical.

DevTools BeginFrame is unavailable

Check that the target has BeginFrameControl enabled, that the Chrome configuration includes the documented compositor setting, and that the Selenium DevTools namespace matches the Chrome protocol version in use. If those requirements do not fit the deployment, use the standard screenshot API with a robust page readiness condition.

Or skip the browser setup

For ordinary website screenshots, ScreenshotNeo provides a screenshot API and MCP server. Its API captures a URL in one GET request; it is not a substitute for Selenium when your task specifically requires executing and controlling a WebGL scene in your own browser session. For a page that works with a hosted screenshot request, the basic call is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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 request options. Cookie banners are accepted and removed before capture along with supported newsletter popups and chat widgets; those steps can be disabled. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents use screenshot tools, and 1,000 screenshots per month are free without a card; paid plans start at $5 for 3,000 shots. Sign up for the free plan.

Frequently Asked Questions

Can Selenium .NET detect when a WebGL scene is ready automatically?

No. Wait for a readiness condition exposed by the page or implement a page-specific check; a navigation call alone does not establish that the scene has finished initializing.

Should I use a whole-page or canvas screenshot?

Use the driver screenshot when you want the browser context; use the canvas element screenshot when you want only that region.

Is headless Chrome guaranteed to match headed Chrome pixel for pixel?

No. Chrome shares its browser implementation in headless mode, but machine, GPU, driver, font, scale-factor, version, and timing differences can affect pixels.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.