# webgl_renderer

> The GPU name the browser reports through WebGL, often with the graphics back end.

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

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

| Field | Value |
| --- | --- |
| Component name | `webgl_renderer` |
| In the visitorId | yes |
| structuredId group | [gpu (graphics)](https://whiskerjs.com/docs/identifiers/#structuredid) |
| Hashing | plain value; a digest only when longer than 128 characters or not printable ASCII |
| Excluded under | Brave (brave_farbling); Firefox resistFingerprinting (firefox_rfp); Tor Browser and Mullvad Browser (rfp_hardened) |
| Inner timeout | 1000 ms |
| Added in | [signalsVersion 1](https://whiskerjs.com/whats-new/) |

> **In plain words:**
>
> Browsers can tell a page which graphics chip draws its 3D content, for example “Apple M2” or a model of Intel, AMD or NVIDIA GPU, often wrapped in the name of the browser’s graphics layer. WhiskerJS reads that name as text. It is one of the most readable device details there is, and it also shows when there is no GPU at all.

## What it reads

From the shared WebGL 1 context:

- in browsers other than Firefox, WhiskerJS asks for the `WEBGL_debug_renderer_info` extension and, when it exists, reads `UNMASKED_RENDERER_WEBGL` with `getParameter()`;
- if that gives nothing (no extension, or an empty answer), it reads the plain `gl.RENDERER` value instead;
- in Firefox (browser class `firefox` or `firefox_rfp`) the extension is not requested at all: Firefox prints a deprecation warning in the console when it is, and its plain `RENDERER` already carries the unmasked string. WhiskerJS writes nothing to the console, so it avoids that call.

An empty result is `unavailable` / `no_value`.

## How the technique works

The browser’s “masked” renderer value is often a generic word such as “WebKit WebGL”. The debug extension exposes the underlying string the graphics driver reports. Chromium browsers usually wrap it in ANGLE, the translation layer they use, for example `ANGLE (Apple, ANGLE Metal Renderer: Apple M2, Unspecified Version)`. The string is reported as is unless it is longer than 128 characters or not printable ASCII, in which case it is hashed like any other value.

The raw string is also kept, inside the library only, for the [`software_renderer`](https://whiskerjs.com/docs/integrity/#software_renderer) check, which fires when it names SwiftShader, llvmpipe, softpipe, a “software rasterizer”, the “basic render driver” or Mesa offscreen.

## Why it helps

It names the GPU family and often the model and graphics back end (Metal, Direct3D, OpenGL, Vulkan). That separates devices clearly and, read together with the platform and the user agent your server sees, can expose inconsistencies such as a desktop GPU on a phone user agent. It is in the `gpu` group.

## Stability

Stable until the browser or driver changes how the GPU is described, or a different GPU is used (an external display on a laptop with two GPUs, or hardware acceleration switched off). Browser updates sometimes change the ANGLE wrapping text.

## Browser support and what blocks it

- `ok` wherever WebGL 1 is available: [Chrome](https://whiskerjs.com/browsers/chrome-desktop/), [Edge](https://whiskerjs.com/browsers/edge/), [Safari](https://whiskerjs.com/browsers/safari-macos/), [Firefox](https://whiskerjs.com/browsers/firefox/) and mobile browsers. Some browsers report only a generic name (the headless WebKit test run in a container used for these pages reported `Apple GPU`).
- [Brave](https://whiskerjs.com/browsers/brave/): `excluded` / `brave_farbling` (since signalsVersion 6): since Brave 1.93 every user reports one generic renderer string.
- [Firefox resistFingerprinting](https://whiskerjs.com/browsers/firefox-rfp-and-tor/): `excluded` / `firefox_rfp`; [Tor Browser and Mullvad Browser](https://whiskerjs.com/browsers/firefox-rfp-and-tor/): `excluded` / `rfp_hardened`.
- Where it is excluded, neither the `software_renderer` nor the `vm_renderer` flag can fire.
- No WebGL: `unavailable` / `no_context`.

## Privacy

It reveals the graphics hardware, which is device information and can be personal data together with the rest of the result. It is read without any permission or prompt and nothing is sent by WhiskerJS. Long or unusual strings leave only as a digest.

## How WhiskerJS handles noise and failures

| Status | ruleId | When |
| --- | --- | --- |
| `ok` | none | plain text, or a digest when long or not printable ASCII |
| `unavailable` | `no_value` | both the unmasked and the plain value were empty |
| `unavailable` | `no_document`, `no_api`, `no_context` | no document, no `getContext`, no WebGL |
| `unavailable` | `no_digest` | the string needed hashing and Web Crypto is missing |
| `blocked` | `security_error`, `threw` | `getParameter` threw |
| `excluded` | `brave_farbling`, `firefox_rfp`, `rfp_hardened`, `caller_excluded` | exclusion table or your `exclude` list |
| `timed_out` | `timeout`, `aborted` | 1000 ms inner timeout, overall budget, abort |

## Example value

From a headless Chromium test browser in a container, drawing in software:

```json
"webgl_renderer": {
  "status": "ok",
  "value": "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (LLVM 10.0.0) (0x0000C0DE)), SwiftShader driver)",
  "hashed": false
}
```

That run also had the `software_renderer` flag. On a typical Mac with Chrome the docs show `ANGLE (Apple, ANGLE Metal Renderer: Apple M2, Unspecified Version)`.

## Questions and answers

### Why does my renderer say SwiftShader or llvmpipe?

The browser is drawing in software instead of on a GPU: hardware acceleration is off, the GPU is blocklisted, or the machine is a server, container or virtual machine. WhiskerJS then also sets the software_renderer integrity flag.

### Is the renderer string ever hashed?

Only when it is longer than 128 characters or contains a character outside printable ASCII. Otherwise it is reported as plain text with hashed false.

### Why is it excluded under Firefox resistFingerprinting, Tor, Mullvad and Brave?

resistFingerprinting (also in Tor Browser and Mullvad Browser) replaces the WebGL strings with placeholders, and since Brave 1.93 every Brave user reports one generic renderer string. Either way the value would not describe the device, so the exclusion table reports excluded with ruleId firefox_rfp, rfp_hardened or brave_farbling.

## Related pages

- [webgl_vendor](https://whiskerjs.com/signals/webgl-vendor/): The vendor string read the same way.
- [webgpu](https://whiskerjs.com/signals/webgpu/): Adapter info from the newer GPU API.
- [software_renderer flag](https://whiskerjs.com/docs/integrity/#software_renderer): Fires when the renderer names a software rasteriser.
- [Software renderer](https://whiskerjs.com/glossary/#software-renderer): What it means and who has one.
- [Firefox](https://whiskerjs.com/browsers/firefox/): Why the debug extension is not requested there.
