html2canvas cannot reliably download WebGL pixels because it reconstructs a new image from the DOM; it does not capture the browser’s composited screen. A WebGL canvas is rendered through a drawing buffer whose contents may be cleared immediately after compositing. Consequently, an html2canvas export can contain the surrounding HTML while the WebGL scene is blank or missing.
There are two separate problems to diagnose: html2canvas’s DOM-based rendering model, and WebGL’s drawing-buffer lifetime. Cross-origin canvas restrictions can introduce a third, independent failure.
What html2canvas actually captures
html2canvas walks the document, reads styles and other information it understands, and paints an approximation into a new canvas. Its documentation explicitly says the result is based on the DOM and is not an actual screenshot of the final browser display: html2canvas documentation.
Ordinary HTML text, backgrounds and many images can therefore appear in the generated canvas. WebGL output is different. The pixels you see are produced by GPU commands in a WebGL drawing context, not represented as DOM nodes or CSS paint instructions that html2canvas can reproduce. Treating a <canvas> element as if it were a normal image does not make its current GPU frame available to the reconstruction process.
#1 Best Overall
- Powered by Radeon RX 9070 XT
- WINDFORCE Cooling System
- Hawk Fan
- Server-grade Thermal Conductive Gel
- RGB Lighting
Why the WebGL frame may be gone by export time
WebGL renders into a drawing buffer. The WebGL specification states that, by default, the buffer is cleared after its contents are composited. If the context was created with preserveDrawingBuffer: false, reading the canvas after the rendering function returns can have undefined results. This applies to readPixels(), toDataURL() and using the canvas as an image source. See the drawing-buffer section of the WebGL 1.0 specification.
That timing rule is independent of html2canvas. Even a native canvas export can be blank if it occurs after the buffer has been discarded. Conversely, setting preservation does not turn html2canvas into a native screen-capture tool; html2canvas still has to represent the WebGL content somehow.
Keep the three failure causes separate
DOM reconstruction versus screen capture
html2canvas creates a new rendering from readable page data. It does not ask the browser compositor for the final pixels, so GPU effects, WebGL scenes and other browser-composited output may differ or disappear.
Drawing-buffer lifetime
A later export can miss a frame because the default WebGL buffer has already been cleared. This is a capture-timing and context-configuration issue, not an html2canvas bug.
Cross-origin tainting
Images, textures or other resources from another origin can make a canvas unreadable under browser security rules. html2canvas cannot bypass those rules. Its FAQ recommends useCORS: true when the remote server sends suitable CORS headers, or a proxy where appropriate: html2canvas FAQ. CORS settings do not solve the general difference between DOM reconstruction and native screenshots.
Rank #2
- Powered by the NVIDIA Blackwell architecture and DLSS 4
- Powered by GeForce RTX 5070 Ti
- Integrated with 16GB GDDR7 256bit memory interface
- PCIe 5.0
- WINDFORCE cooling system
If you control the WebGL application
The most dependable fix is to capture pixels while you still control the render operation, rather than asking html2canvas to infer them later.
Read synchronously in the render function
Render the frame and call readPixels() before the function returns. This follows the WebGL specification’s synchronous-readback technique. The exact pixel format, dimensions and packing must match your implementation, and you must account for WebGL’s bottom-left coordinate origin when turning the data into an image.
Render into a framebuffer object
Instead of relying on the default onscreen buffer, render to a framebuffer object with a color attachment. Read that attachment while it is bound. This gives your application an explicit source whose lifetime is controlled by your render pipeline and can avoid dependence on post-compositing contents.
Free tools Windows power users keep installed
One-click scans. No signup required.
Create the context with preservation
If your workflow genuinely needs to read the default drawing buffer after rendering returns, request it when creating the context:
const gl = canvas.getContext('webgl', { preserveDrawingBuffer: true });
The specification says preserved contents remain until you clear or overwrite them, but warns that preservation can cause significant performance loss on some platforms. It is a trade-off, not a universal repair. The attribute is supplied at context creation; do not assume it can be enabled on an existing context.
Rank #3
- Powered by the NVIDIA Blackwell architecture and DLSS 4. System Requirements: Minimum 850W PSU with 16-pin 12V-2x6 (12VHPWR) connector required. Verify before purchasing.
- Military-grade components deliver rock-solid power and longer lifespan for ultimate durability. Compatibility: 348mm (13.7") length, 3.6 slots, 4.3 lbs. Confirm case clearance and slot spacing. GPU bracket included.
- Protective PCB coating helps protect against short circuits caused by moisture, dust, or debris
- 3.6-slot design with massive fin array optimized for airflow from three Axial-tech fans
- Phase-change GPU thermal pad helps ensure optimal thermal performance and longevity, outlasting traditional thermal paste for graphics cards under heavy loads
Export the WebGL canvas directly
Once you have a valid, readable frame, export that canvas itself (for example with toDataURL('image/png')) or copy known pixels into a 2D canvas. This bypasses html2canvas for the WebGL portion. If the frame was already lost or the canvas is tainted, export still fails or produces unusable output.
If you need the browser’s actual visible result
When the requirement is “what a user sees,” use a capture mechanism that operates at browser or compositor level.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Browser extensions
For an extension capturing a visible tab, the html2canvas FAQ points to native APIs: chrome.tabs.captureVisibleTab() for Chrome, Edge and Opera, and browser.tabs.captureVisibleTab() for Firefox. Configure the required extension permissions and verify whether your use case needs only the visible viewport or another capture scope. These APIs capture the tab rather than reconstructing the DOM.
Server-side automation
For unattended jobs, drive a real browser with Puppeteer or Playwright, as the FAQ recommends. Wait for the WebGL application to initialize, set the intended viewport, and capture after the scene is ready. Browser automation captures the rendered page, but it still requires you to handle authentication, bot checks, timing, permissions and resource failures in your own workflow.
Downloading an html2canvas result
If WebGL is not part of the required pixels, html2canvas’s normal download pattern is sufficient:
Rank #4
- AI Performance: 767 AI TOPS
- OC mode: 2632 MHz (OC mode)/ 2602 MHz (Default mode)
- Powered by the NVIDIA Blackwell architecture and DLSS 4
- Axial-tech fan design features a smaller fan hub that facilitates longer blades and a barrier ring that increases downward air pressure
- A 2.5-slot design maximizes compatibility and cooling efficiency for superior performance in small chassis
html2canvas(document.querySelector('#page')).then(canvas => {
const link = document.createElement('a');
link.download = 'page.png';
link.href = canvas.toDataURL('image/png');
link.click();
});
The html2canvas examples document this toDataURL()-and-anchor method: html2canvas examples. It downloads the canvas html2canvas generated. It cannot restore WebGL pixels that were never represented in that canvas or were unavailable during readback.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated 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 matchPractical decision guide
| Requirement | Preferred approach | Main consideration |
|---|---|---|
| You own the renderer and need exact scene pixels | Synchronous readback or a framebuffer object | Integrate capture with the render loop and handle pixel orientation and format. |
| You need a later read of the default canvas | Create the context with preserveDrawingBuffer: true |
Possible performance cost; it cannot normally be toggled after creation. |
| You need the visible tab in an extension | Native tab screenshot API | Requires extension permissions and captures the permitted tab scope. |
| You need repeatable server-side page images | Puppeteer or Playwright | Manage waits, login state, failures and browser resources. |
| You only need HTML and CSS | html2canvas | Result is a DOM reconstruction, not a guaranteed pixel-identical screenshot. |
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server for developers. A single request runs a real browser capture and can return PNG, JPEG, WebP or PDF. Cookie and consent banners are accepted and 60-plus known consent platforms, newsletter popups and chat widgets are removed before the shot; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers report the page verdict and billing status.
For a URL such as Stripe, the cURL call is:
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 documentation for options. The same request in Python is:
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)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
It also offers full-page lazy-image capture, CSS-selector element shots, dark mode, device presets and custom viewports, retina scale, PDF controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. An MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
There is a free allowance of 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan, and annual billing provides two months free. Create a free ScreenshotNeo account to try it without a card.
Troubleshooting blank or missing WebGL images
The surrounding page appears, but the WebGL scene is blank
This is the expected limitation of DOM reconstruction. Capture the tab with a native browser API or automation, or export the WebGL canvas from code you control.
Best Value
- Powered by the NVIDIA Blackwell architecture and DLSS 4
- Powered by GeForce RTX 5060
- Integrated with 8GB GDDR7 128bit memory interface
- PCIe 5.0
- WINDFORCE cooling system
toDataURL() is blank after animation
Move readback into the same render callback, use a framebuffer, or recreate the context with preserveDrawingBuffer: true. Check that another frame has not cleared or overwritten the buffer.
Readback throws a security error
Identify cross-origin images or textures. Serve them with appropriate CORS headers and use useCORS: true where eligible, or use a proxy. Do not treat CORS as a solution to html2canvas’s DOM-versus-compositor limitation.
The screenshot is captured before WebGL is ready
In automation, wait for a reliable application signal, such as a selector or an explicit readiness flag, rather than an arbitrary short delay. Confirm the canvas dimensions and that the render loop has produced the target frame.
Recommended Free Tools
Preservation causes slow rendering
That is a documented trade-off. Prefer framebuffer rendering or synchronous readback for controlled capture points, and reserve preservation for workflows that truly require the default buffer later.
Key takeaway
Downloading an html2canvas canvas is easy; obtaining WebGL pixels is the hard part. html2canvas can save only the reconstruction it produced. For exact application pixels, capture during rendering or use a framebuffer. For the browser’s composited result, use a native screenshot API or real-browser automation.
Frequently Asked Questions
Can html2canvas capture a WebGL canvas at all?
Not reliably as a pixel-perfect source. It reconstructs the DOM and does not perform a native screenshot, so use renderer-controlled readback or browser-level capture for WebGL output.
Does preserveDrawingBuffer guarantee html2canvas will include WebGL?
No. It preserves the WebGL drawing buffer for later reads, but html2canvas still uses DOM reconstruction rather than requesting the browser’s composited pixels.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteWhat should I use for a server-side screenshot?
Use a real-browser workflow such as Puppeteer, Playwright or a screenshot API. Choose based on your control, authentication, timing and operational requirements.
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.

