# webgl_params

> 21 WebGL parameters, the precision of eight shader formats and the sorted list of extensions, as one digest.

Source: https://whiskerjs.com/signals/webgl-params/ (last updated 2026-10-26)

**webgl_params at a glance (from the library code, signalsVersion 9)**

| Field | Value |
| --- | --- |
| Component name | `webgl_params` |
| In the visitorId | yes |
| structuredId group | [gpu (graphics)](https://whiskerjs.com/docs/identifiers/#structuredid) |
| Hashing | always a digest (first 128 bits of SHA-256) |
| Excluded under | Brave (brave_farbling) |
| Inner timeout | 1000 ms |
| Added in | [signalsVersion 1](https://whiskerjs.com/whats-new/) |

> **In plain words:**
>
> Every graphics setup tells web pages what it can do: the biggest texture it can handle, how many inputs a shader may have, how precise its numbers are, and which optional features (extensions) it supports. WhiskerJS reads that list and turns it into one short code. Different GPUs, drivers and browsers report different lists.

## What it reads

From the shared WebGL 1 context of the collection:

- 21 parameters with `getParameter()`: `ALIASED_LINE_WIDTH_RANGE`, `ALIASED_POINT_SIZE_RANGE`, `ALPHA_BITS`, `BLUE_BITS`, `DEPTH_BITS`, `GREEN_BITS`, `MAX_COMBINED_TEXTURE_IMAGE_UNITS`, `MAX_CUBE_MAP_TEXTURE_SIZE`, `MAX_FRAGMENT_UNIFORM_VECTORS`, `MAX_RENDERBUFFER_SIZE`, `MAX_TEXTURE_IMAGE_UNITS`, `MAX_TEXTURE_SIZE`, `MAX_VARYING_VECTORS`, `MAX_VERTEX_ATTRIBS`, `MAX_VERTEX_TEXTURE_IMAGE_UNITS`, `MAX_VERTEX_UNIFORM_VECTORS`, `MAX_VIEWPORT_DIMS`, `RED_BITS`, `SHADING_LANGUAGE_VERSION`, `STENCIL_BITS` and `VERSION`;
- with `getShaderPrecisionFormat()`, the range and precision of `HIGH_FLOAT`, `MEDIUM_FLOAT`, `LOW_FLOAT` and `HIGH_INT` in both the vertex and the fragment shader (eight entries);
- the list from `getSupportedExtensions()`, sorted alphabetically.

## How the technique works

Each value is written as `NAME=value` (arrays joined with commas, `!` when a call throws, an empty value when it returns nothing), the precision entries as `SHADER.PRECISION=rangeMin,rangeMax,precision`, and the extensions as one comma-separated list. All parts are joined with semicolons into one string, which is always hashed with SHA-256 because `webgl_params` is a large component. Sorting the extension list makes the value independent of the order the browser returns them in.

## Why it helps

Limits and extensions come from the GPU, the driver and the browser’s graphics layer together. A laptop’s integrated GPU, a desktop card and a phone’s GPU report different texture limits and precisions, and browsers expose different extension sets. The combination separates graphics setups that a renderer name alone might group together. It is part of the `gpu` group.

## Stability

These values change rarely. They can change with a browser update (new or removed extensions, changed limits), a driver update, switching hardware acceleration, or a different GPU being used. They do not depend on the page, the zoom level or the window size.

## Browser support and what blocks it

`ok` wherever a WebGL 1 context can be created. [Brave](https://whiskerjs.com/browsers/brave/): `excluded` / `brave_farbling` (since signalsVersion 6): since Brave 1.93 every user reports the same generic WebGL parameters, so they carry nothing about the device. It is collected under [Firefox resistFingerprinting, Tor and Mullvad](https://whiskerjs.com/browsers/firefox-rfp-and-tor/), Firefox Fingerprinting Protection and Safari Advanced Fingerprinting Protection (those modes change the rendered image or the GPU strings, not this list). Without WebGL it is `unavailable` / `no_context`, together with the other WebGL components.

## Privacy

It reveals the capabilities of the graphics stack, not what the user does. The whole list leaves the library only as a 32-character digest. No permission, no prompt, no request.

## How WhiskerJS handles noise and failures

| Status | ruleId | When |
| --- | --- | --- |
| `ok` | none | the list was read; value is a digest |
| `unavailable` | `no_document`, `no_api`, `no_context` | no document, no `getContext`, or no WebGL context |
| `unavailable` | `no_digest` | no Web Crypto |
| `blocked` | `security_error`, `threw` | a WebGL call threw outside the per-parameter guards |
| `excluded` | `brave_farbling`, `caller_excluded` | exclusion table or your `exclude` list |
| `timed_out` | `timeout`, `aborted` | 1000 ms inner timeout, overall budget, abort |

A single parameter that throws does not fail the component: it is written as `!` inside the hashed string.

## Example value

From a headless Chromium test browser in a container:

```json
"webgl_params": { "status": "ok", "value": "79906793c9fee64879c122d10676691b", "hashed": true }
```

## Questions and answers

### Why is webgl_params not checked for noise?

It reads numbers and names the browser reports, not rendered pixels, so there is nothing for readback noise to change. The rendered image is checked separately in webgl_image.

### Can a browser update change it?

Yes. A new browser version can add or remove WebGL extensions or change a reported limit, and the digest then changes.

## Related pages

- [webgl_image](https://whiskerjs.com/signals/webgl-image/): The rendered image from the same context.
- [webgl_renderer](https://whiskerjs.com/signals/webgl-renderer/): The GPU name.
- [webgpu](https://whiskerjs.com/signals/webgpu/): A newer view of the GPU's limits and features.
- [Digest](https://whiskerjs.com/glossary/#digest): How large values are reported.
