WebGL is not just for cool web effects — it can also be used to track users. Learn how WebGL fingerprinting works and how to defend against it.
WebGL fingerprinting identifies your device by querying your graphics hardware and observing exactly how it renders 3D scenes. Because every combination of GPU model, driver version, and operating system produces slightly different output and reports slightly different capabilities, a website can read your GPU vendor and renderer string, enumerate your supported extensions and numeric limits, and hash a rendered image into a stable identifier — all without permission, cookies, or storage. This makes WebGL one of the highest-entropy signals in modern browser fingerprinting.
What WebGL Is and Why It Leaks Hardware Identity
WebGL is a JavaScript API that gives web pages low-level access to the GPU for hardware-accelerated 2D and 3D graphics. It is essentially a browser binding to OpenGL ES, which means that when you call WebGL, you are reaching down through the browser, through the graphics driver, to the physical graphics processor inside your machine.
That deep access is exactly what makes it a fingerprinting goldmine. To draw efficiently, WebGL must expose what your hardware can do — how large a texture it supports, which optional features are available, how its shaders round floating-point numbers. It also produces output that varies by hardware: the same drawing instructions yield subtly different pixels on an NVIDIA card versus an Apple GPU versus an Intel integrated chip, because each implements rasterization, anti-aliasing, and floating-point math differently.
There are two broad families of WebGL signals: declared metadata (strings and numbers the GPU reports about itself) and rendered output (the actual pixels produced when you draw a scene). Together they complement Canvas fingerprinting, which probes the 2D rendering path, and together both feed into the broader picture described in our browser fingerprinting guide.
The High-Signal Data Points
GPU Vendor and Renderer Strings
The single most identifying WebGL signal is the unmasked vendor and renderer string. By default the standard VENDOR and RENDERER parameters return generic values, but the WEBGL_debug_renderer_info extension exposes the real hardware identity — strings like Google Inc. (NVIDIA) and ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11).
This string often reveals your GPU model, the rendering backend (Direct3D, Metal, OpenGL via ANGLE), and sometimes the driver. On its own it can narrow you to a small slice of users, because exact GPU-plus-backend combinations are far less common than people assume.
Whether that string is actually readable now depends heavily on the browser. In a default Chrome or Edge install it still is. Brave and Firefox increasingly are not — see “What Browsers Now Hide” below for the current, browser-by-browser picture.
Supported Extensions
WebGL ships a core feature set plus dozens of optional extensions. The list returned by getSupportedExtensions() — and its order — depends on the GPU, driver, and browser version. Two devices with the same headline GPU can still differ here if their drivers or browser builds differ, adding another distinguishing layer. This makes it a favorite for hash-based fingerprinting: a script does not need to parse the list, it just hashes it, and a stable hash is as good an identifier as the string itself — which is exactly the property Brave now attacks (see “What Browsers Now Hide” below).
Numeric Parameters and Shader Precision
WebGL exposes a long list of numeric limits that reflect hardware capabilities: MAX_TEXTURE_SIZE, MAX_VIEWPORT_DIMS, MAX_RENDERBUFFER_SIZE, the aliased line-width and point-size ranges, and the maximum number of vertex and fragment uniform vectors. Shader precision — queried via getShaderPrecisionFormat() for high/medium/low float and int formats — adds further granularity, since precision behavior is tied to the silicon.
Rendering-Based Hashing
The most powerful technique mirrors canvas fingerprinting but drives it through the GPU. A script renders a deliberately tricky scene — gradients, lighting, transparency, curved geometry — reads the pixels back with readPixels(), and hashes them. Differences in floating-point rounding, anti-aliasing, and texture filtering across GPUs and drivers produce a stable hash that differs between hardware families. Because it captures behavior rather than just declared values, it is much harder to fake convincingly than a metadata string.
A Practical Look at the Code
The snippet below collects the core WebGL signals a fingerprinting script would gather. You can see equivalent live results for your own browser using BrowserInsight's fingerprint detection tool.
function getWebGLFingerprint() {
const canvas = document.createElement('canvas');
const gl =
canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (!gl) return { supported: false };
// 1. Unmasked GPU vendor + renderer via the debug extension
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
const vendor = debugInfo
? gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL)
: gl.getParameter(gl.VENDOR);
const renderer = debugInfo
? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
: gl.getParameter(gl.RENDERER);
// 2. Numeric capability limits
const params = {
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
maxViewportDims: gl.getParameter(gl.MAX_VIEWPORT_DIMS),
maxRenderbufferSize: gl.getParameter(gl.MAX_RENDERBUFFER_SIZE),
aliasedLineWidth: gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE),
};
// 3. Shader precision for the fragment high-float format
const precision = gl.getShaderPrecisionFormat(
gl.FRAGMENT_SHADER,
gl.HIGH_FLOAT
);
// 4. Supported extensions (presence + order are both informative)
const extensions = gl.getSupportedExtensions();
return {
supported: true,
vendor,
renderer,
params,
precision: { rangeMin: precision.rangeMin, prec: precision.precision },
extensions,
};
}
A rendering-based hash goes one step further: it compiles a shader, draws a gradient-lit shape, calls gl.readPixels() into a typed array, and runs that array through a hash function. The resulting value stays constant for your device but differs across hardware.
How Much Entropy WebGL Adds
Entropy measures how much a signal narrows down who you are. WebGL is valuable to trackers precisely because it carries a lot of it and stays stable: your GPU does not change between page loads, and most users never alter their driver. The vendor/renderer string, the extension list, the numeric limits, and the rendered hash are partly correlated — they all flow from the same hardware — but each captures something the others miss.
In practice WebGL is rarely used alone. It is combined with canvas, audio, fonts, screen metrics, and dozens of other attributes. The table below contrasts the main WebGL signal types and how easily each is spoofed.
| WebGL signal | What it reveals | Stability | Spoofing difficulty |
|---|---|---|---|
| Vendor / renderer string | GPU model + rendering backend | Very high in Chrome/Edge; generic and non-identifying in Brave 1.93+ | Easy to overwrite, but breaks consistency |
| Supported extensions | Driver + browser feature set | High; randomized per-site in Brave 1.93+ | Moderate — list must stay self-consistent |
| Numeric parameters | Hardware capability limits | Very high | Moderate — values are interdependent |
| Shader precision | Floating-point behavior | High | Hard — tied to real silicon |
| Rendered pixel hash | Actual GPU rendering behavior | High | Very hard — must fake real output |
Because the metadata and the rendered output must agree with each other, naive spoofing often increases uniqueness: a device reporting an Intel renderer string while producing NVIDIA-style pixels stands out more than one that simply tells the truth.
What Browsers Now Hide
The signals above describe the default web platform. Individual browsers increasingly deviate from it, and as of August 2026 the gap between "what WebGL can theoretically read" and "what a given visitor's browser actually returns" is wider than it has ever been. The most recent, concrete example is Brave's privacy update #38, which ships in Brave 1.93 as a default-on rollout on the two platforms Brave lists, desktop and Android. Brave describes the rollout as gradual, spread over several days, so not every user will see it immediately. It changes three of the signals covered above:
- Vendor and renderer strings are de-identified. Instead of returning your real GPU model through
WEBGL_debug_renderer_info, Brave now replacesUNMASKED_VENDOR_WEBGL/UNMASKED_RENDERER_WEBGLwith a single generic string that is identical for every Brave user. The section above still describes reality for Chrome and Edge in their default configuration — it no longer describes Brave. - WebGPU adapter descriptors are emptied.
GPUAdapterInfo— the WebGPU analog of the vendor/renderer string, exposingvendor,architecture, anddeviceas first-class properties with no debug extension required — is blanked out by Brave rather than left to leak the same hardware identity through a newer API. We cover that surface in depth in WebGPU Fingerprinting: The Next GPU ID After WebGL; the short version here is that Brave 1.93 closes it the same way it closes WebGL's vendor string. - The extension list is randomized, not just hidden. Brave injects randomization into
getSupportedExtensions()so that a hash-based fingerprinter sees a different value per browsing session, per site (eTLD+1), and per storage area. This directly defeats the hashing technique described earlier: a hash is only useful as an identifier if the same input produces the same hash on every site you visit. Once the underlying extension list itself varies by site, the hash varies with it — so the value a tracker collects on site A no longer matches the value collected on site B, and it stops functioning as a cross-site identifier at all, even though your hardware never changed.
Attribution matters here, because these protections are not universal. Brave de-identifies and randomizes by default in 1.93+. Firefox takes a different route: with privacy.resistFingerprinting enabled, it disables WEBGL_debug_renderer_info outright, so every Firefox user in that mode gets the same generic VENDOR/RENDERER values rather than a randomized one. Chrome and Edge ship neither protection by default — the unmasked strings and the real extension list remain readable exactly as described above. None of this is a claim that fingerprinting is "solved" in any browser, and Brave's own rollout notes make clear it is still reaching users in phases — treat this section as the state of one vendor's defenses, not the state of the web.
It's also worth knowing why a string this identifying was ever readable with no permission prompt in the first place. The answer is in the extension's name: WEBGL_debug_renderer_info was specified for debugging. Hardware-specific rendering bugs are real, and a site that draws heavy 3D content has a genuine reason to log which GPU and driver combinations produce broken output. Once an extension is exposed to the web platform generally, though, every site can call it, not only the ones with a legitimate debugging need — which is the general pattern behind most permissionless, high-entropy fingerprinting signals.
How Websites Use WebGL Fingerprinting
Legitimate uses are common. Fraud-prevention and anti-bot systems use the WebGL fingerprint as one signal among many to spot automated traffic, headless browsers, and accounts that suddenly switch hardware. Analytics and security teams use it to flag suspicious sessions. Headless and virtualized environments often expose tell-tale renderer strings (such as software rasterizers like SwiftShader or llvmpipe), which is why bot detectors lean on WebGL so heavily.
The same consistency logic extends beyond the GPU to the browser itself: a renderer string has to agree with the rest of the environment, including the rendering engine that actually drew the page. You can check your own engine and version — and spot signs of engine spoofing — with BrowserInsight's browser kernel check.
The same capability also powers cross-site advertising and tracking, since a stable hardware-derived ID survives cookie clearing and private-browsing windows. That dual-use nature is why understanding WebGL fingerprinting matters whether your interest is security or privacy.
Defenses and Their Tradeoffs
There is no perfect defense — every option trades away functionality, performance, or blend-in value. The main approaches:
Tor Browser
Tor Browser takes the standardization route: it ships uniform settings so that all users present the same fingerprint, and it prompts before allowing WebGL at all. The goal is not to hide your GPU but to make every user look identical, which is the strongest privacy model — at the cost of speed and some broken 3D content.
Brave and Farbling
Brave adds tiny, deterministic, per-session-and-per-site randomization (called "farbling") to fingerprintable outputs, including WebGL readbacks. Each site sees a slightly different value, and the noise reshuffles, so a stable cross-site ID is hard to build while most pages keep working. As of Brave 1.93 this approach was extended to the metadata layer too — see “What Browsers Now Hide” above for the vendor/renderer de-identification and extension-list randomization specifics.
Disabling WebGL
Turning WebGL off entirely (via flags or webgl.disabled) removes the surface completely. It is effective but blunt: the absence of WebGL is itself somewhat unusual and can break maps, games, and visualization tools.
Value Spoofing — and Why It Backfires
Extensions that overwrite the renderer string or inject noise can help, but carry real risk. If the spoofed metadata contradicts the rendered pixels or the numeric limits, a sophisticated detector notices the inconsistency, and you become more identifiable, not less. The safest spoofing is consistent and shared by many users; ad-hoc per-user randomization without coordination often achieves the opposite of its goal.
The pragmatic takeaway: pick a defense that many other people use (Tor's uniformity, Brave's farbling) rather than a bespoke setup that makes you unique. To see where you stand right now, run BrowserInsight's fingerprint detection tool and review your WebGL renderer, extensions, and hash.
WebGL is also not the final word in GPU fingerprinting. The newer WebGPU API exposes adapter vendor, architecture, and device strings as first-class properties — no debug extension required — and until recently it was a richer surface than WebGL that most privacy tools had not addressed. Brave 1.93 closes it by emptying those adapter descriptors; other browsers still leave them readable.
Randomization Is Not Anonymity
None of the defenses above make you invisible, and it's worth being explicit about why. A defense that makes your browser rare — an unusual combination of randomized values nobody else shares — can be as identifying as the signal it was meant to hide, for the same reason a disguise that nobody else is wearing draws attention. We cover this tradeoff, and how to reason about it, in Cover Your Tracks: What Your Uniqueness Score Doesn't Prove. The underlying concept — how many other people need to look identical to you before a signal stops being useful for re-identification — is explained in Browser Fingerprint Entropy and Anonymity Sets Explained. Uniformity (Tor, and now Brave's de-identified vendor string) helps because it keeps you inside a large crowd; per-user randomization only helps if enough other people are doing it too.
Frequently Asked Questions
Can a website read my exact GPU model?
It depends on your browser. The WEBGL_debug_renderer_info extension exposes an unmasked renderer string that frequently names your GPU model and rendering backend, and in a default Chrome or Edge configuration it is still readable without any permission prompt. Firefox disables the extension under privacy.resistFingerprinting, and as of Brave 1.93 (August 2026) Brave replaces it with a generic string shared by every Brave user — see “What Browsers Now Hide” above for the current per-browser breakdown.
Does WebGL fingerprinting still work in private/incognito mode?
Yes. Private browsing clears cookies and history but does not change your hardware. The WebGL signals — vendor, renderer, extensions, numeric limits, and rendered hash — remain the same across normal and private windows, so they can re-identify you across both.
Is disabling WebGL enough to stop fingerprinting?
It removes the WebGL surface, but not fingerprinting as a whole. Canvas, audio, fonts, screen, and other signals still apply, and the conspicuous absence of WebGL can itself be a distinguishing trait. Disabling it is one layer, not a complete solution.
How is WebGL fingerprinting different from canvas fingerprinting?
Canvas fingerprinting probes the 2D rendering path, while WebGL probes the GPU-driven 3D path and also exposes explicit hardware metadata (vendor, renderer, capability limits). They are correlated but distinct, which is why trackers collect both for higher confidence.


