WebGL exposes a full parameter table + UNMASKED vendor/renderer
Non-empty unmasked vendor and renderer, plus 12 or more parameters returning values.
What a detector infers
Beyond the two headline strings, a WebGL context answers getParameter for dozens of driver-specific limits.
The audit queries 21 of them — MAX_TEXTURE_SIZE, MAX_VIEWPORT_DIMS, MAX_VERTEX_UNIFORM_VECTORS, ALIASED_LINE_WIDTH_RANGE, the RED/GREEN/BLUE/ALPHA/DEPTH/STENCIL bit depths, MAX_TEXTURE_MAX_ANISOTROPY_EXT and others — hashes the collected values, and passes when at least 12 of them returned a value and the context is not masked: WEBGL_debug_renderer_info must be present, UNMASKED_VENDOR and UNMASKED_RENDERER must both be non-empty, and the renderer must not read "Masked" or "Not supported".
Only a missing WebGL context reports N/A — a stripped debug extension is a fail, not an abstention. Note the scope: it verifies the table is present and unmasked, not that the limits match the named GPU. That second step is the detector's: they hash the whole table, so a rewritten renderer string can be checked against limits that belong to a different GPU — which is why exposing an honest table only helps if the strings describe it.
How to resolve it
Expose a real GPU's parameter table by giving the browser a genuine GPU-backed context (canvas bridge). Don't strip WEBGL_debug_renderer_info or blank out vendor/renderer — the absence is itself distinguishing. If you do set the strings, set them to a GPU whose limits actually match the table you are exposing.
Read in the wild by
Commercial detector B
Collects the full WebGL driver-limit table — the aliased line-width and point-size ranges, the alpha, blue and green bit depths, depth and stencil bits, the MAX_* limits and MAX_TEXTURE_MAX_ANISOTROPY_EXT — and appends a getShaderPrecisionFormat reading (precision, rangeMin, rangeMax) for each shader and precision pair, sending the table both as a raw array and as a hash. getSupportedExtensions() is collected and hashed as its own separate field.
[internal reference] (identifiers hQ/Ak; the same logic appears in [internal reference] and [internal reference] under different minified names): `n.webglParameters=[];var h=n.webglParameters;if(h[hQ(234)](c(Ak(t,t.ALIASED_LINE_WIDTH_RANGE))),h.push(c(Ak(t,t.ALIASED_POINT_SIZE_RANGE))),h[hQ(234)](Ak(t,t.ALPHA_BITS)),h.push(t.getContextAttributes()[hQ(493)]?"yes":"no"),h.push(Ak(t,t.BLUE_BITS)),h.push(Ak(t,t.DEPTH_BITS)),h.push(Ak(t,t.GREEN_BITS)),h.push(function(t){…e=t.getExtension("EXT_texture_filter_anisotropic")…t.getParameter(e.MAX_TEXTURE_MAX_ANISOTROPY_EXT)…}(t)),…h.push(Ak(t,t.MAX_CUBE_MAP_TEXTURE_SIZE)),h.push(Ak(t,t.MAX_FRAGMENT_UNIFORM_VECTORS)),…h.push(c(Ak(t,t.MAX_VIEWPORT_DIMS))),h.push(Ak(t,t.STENCIL_BITS))` — note RED_BITS is absent (grep -c RED_BITS = 0). Precision: `var l=t[hQ(497)](t[u],t[s]);h.push(l.precision,l[hQ(500)],l[hQ(501)])`. Extensions: `n.extensions=t[hQ(490)]()||[pd]`. Dispatch pairs each raw value with a hash: `e["PAhJQnpoSHY="]=n.extensions,e["GCQtLl1ELx8="]=iR(n.extensions),e["LVkYU2g9Hmg="]=n.webglParameters,e["dWFAKzABQhs="]=iR(n.webglParameters)`. Decoded payload [internal reference] confirms: LVkYU2g9Hmg= = ["[1, 1]","[1, 1024]",8,"yes",8,24,8,16,32,16384,1024,16384,16,16384,30,16,16,4096,"[32767, 32767]","no_fp",23,127,127,…] (20 params + 12 precision triples), dWFAKzABQhs= = "dab81cb438e9b1ecd9151a3ba33a82b8", GCQtLl1ELx8= = "96ff435b6ebac2817a4d5bfc475aa8e4", PAhJQnpoSHY= = ["ANGLE_instanced_arrays","EXT_blend_minmax",…]. hQ(490)/hQ(497) semantics confirmed empirically from these payload values. [site] build independently shows the same raw+hash pairing: `n["bRJWEyh9Xig="]=t.webglParameters,n["GwBgAV5rbDE="]=fJ(t.webglParameters)`.
Commercial detector A
Hashes a full WebGL getParameter table rather than trusting the vendor string alone.
gl_unmasked_vendor, gl_unmasked_renderer, gl_version, gl_max_uniform_buffer_bindings, gl_max_fragment_uniform_vectors, gl_aliased_line_width_range …
Commercial detector D
Lists the GPU renderer and vendor via WEBGL_debug_renderer_info as hardware signals.
[internal reference] - 2. Hardware - WebGL renderer / WebGL vendor
Every attribution traces to a published artifact. See the sources and their limits.
Nearby checks in Render & GPU
- WebGPU's architecture is the one Chrome's own table gives the GPU WebGL names
webgpu-architecture-vs-rendererGPUAdapterInfo.architecture is not free text. Chrome's WebGPU implementation derives it from the GPU's PCI device id through its own table… - WebGPU's subgroup size is the wave width of the GPU WebGL names
webgpu-subgroup-vs-rendererChrome's WebGPU implementation (Dawn) reports GPUAdapterInfo.subgroupMinSize from the driver: on Windows the Direct3D 12 backend reads… - WebGPU's features and limits fit the hardware GPU WebGL names
webgpu-features-vs-rendererOn Windows, Chrome's WebGPU runs on Direct3D 12, and Direct3D bounds what an adapter can expose: DXGI has no ASTC or ETC2 formats at all, BC… - The WebGL renderer string is one ANGLE's Direct3D 11 backend can print
webgl-renderer-angle-formatOn Windows, Chrome's WebGL renderer string is assembled by ANGLE's Direct3D 11 backend, not typed by anyone: the adapter's description, then… - WebGL parameters return the JavaScript types the specification assigns them
webgl-param-value-typesgetParameter does not return loose values: the WebGL specification fixes the JavaScript TYPE of each one. - The anisotropy limit reads as a number once its WebGL extension is enabled
webgl-anisotropy-after-extensionEXT_texture_filter_anisotropic adds exactly one parameter to getParameter, MAX_TEXTURE_MAX_ANISOTROPY_EXT, and the extension guarantees it… - A Direct3D 11 WebGL renderer reports the uniform limits ANGLE fixes for its vendor
webgl-d3d11-limits-vs-vendorChrome, Edge, Brave and Firefox on Windows render WebGL through ANGLE's Direct3D 11 backend, and that backend does not ask the driver for… - A Mesa OpenGL WebGL renderer reports the varying and uniform limits Mesa and ANGLE give it
webgl-mesa-limits-vs-driverChrome on Linux renders WebGL through ANGLE's OpenGL backend, which does not invent shader limits: it reads MAX_VARYING_VECTORS from the GL…
Clearcote is a browser built for fingerprint coherence
It is a Chromium fork, maintained by the same people who wrote this reference. It ships as a compiled browser rather than as a stealth script injected into someone else's — which is a description of how it is built, and is not an argument about how it behaves on this check.
This audit takes no position on how Clearcote scores on Render & GPU checks, on this one, or anywhere else. It has no baseline corpus of other people's fingerprints to rank you against and no vendor scoreboard — nearly every check is self-referential, asking one browser the same question through two independent APIs and reporting whether both answers can be true at once. It runs identically on any browser, including ours. Run it on yours and read the result yourself.
See the other checks in Render & GPU — the family webgl-param-table belongs to.
