| Component name | webgpu_limits |
|---|---|
| In the visitorId | no (reported, kept out of both ids) |
| structuredId group | none |
| Hashing | always a digest (first 128 bits of SHA-256) |
| Excluded under | no browser class |
| Inner timeout | 1000 ms |
| Added in | signalsVersion 11 |
| Collector revision | 1 (reported as revision with every result) |
Before a web page can use the graphics chip through WebGPU, it asks for an “adapter”, which describes what the chip may do. The webgpu signal already reads part of that description. This one reads every maximum the adapter lists (the limits) and the colour format the browser prefers for drawing, and turns them into one short code.
What it reads
- The WebGPU adapter that the
webgpucomponent requests:navigator.gpu.requestAdapter()with no options is called once per collection and shared by both components. - Every numeric attribute of the adapter’s
limits(aGPUSupportedLimitsobject), sorted by name. navigator.gpu.getPreferredCanvasFormat().
No device is requested and nothing is drawn.
How the technique works
The limits are written as name=value;... in name order, followed by canvasFormat=<format>, and the whole string is always hashed. Because it reuses the adapter of webgpu, it adds no second adapter request.
Why it helps
It is the complete limits set, where webgpu keeps only seven limits. The specification buckets the values, so the set mostly separates GPU classes and browser implementations rather than single devices. Its value for your server is consistency: a WebGPU limits set that does not fit the WebGL renderer is unusual.
Stability
Expected to be stable until a browser or driver update. Low entropy and reported outside both ids. Added in library PR #29 (2026-10-27) at signalsVersion 11: it is outside both ids, so adding it changed no id and needed no version bump.
Browser support and what blocks it
okwherenavigator.gpureturns an adapter (secure contexts only).unavailable/no_contextwhen no adapter is returned: Chromium 153 and Chrome 155 on the GPU-less CI runner of PR #29.unavailable/no_apiwithoutnavigator.gpu: headless Firefox and WebKit on Linux in the same runs.- No browser class excludes it. Brave empties the adapter’s info fields (so
webgpuis excluded there); the limits are bucketed by the specification and are still read.
Privacy
The limits describe the GPU’s capabilities in coarse buckets. They leave the library only as a digest. requestAdapter() shows no prompt.
How WhiskerJS handles noise and failures
| Status | ruleId | When |
|---|---|---|
ok |
a digest | |
unavailable |
no_api |
no navigator.gpu.requestAdapter |
unavailable |
no_context |
no adapter |
unavailable |
no_value |
the adapter lists no limits |
unavailable |
no_digest |
no Web Crypto |
blocked |
threw, security_error |
requestAdapter() rejected or a read threw |
excluded |
caller_excluded |
you excluded it |
timed_out |
timeout, aborted |
budget or abort |
Example value
"webgpu_limits": { "status": "unavailable", "ruleId": "no_context", "durationMs": 3.2, "revision": 1 }
That is what the GPU-less CI browsers reported; on a device with a GPU the value is a digest.
Questions and answers
Does webgpu_limits create a GPU device?
No. It reads the limits of the adapter that the webgpu component already requests. requestAdapter() is called once per collection, never prompts, and no device is ever requested.
Why is it low in entropy?
The WebGPU specification lets browsers round adapter limits into a few buckets so that they reveal less. The limits therefore fall into a small number of sets.