| Component name | video_decoding |
|---|---|
| In the visitorId | no (reported, kept out of both ids) |
| structuredId group | none |
| Hashing | plain value; a digest only when longer than 128 characters or not printable ASCII |
| Excluded under | no browser class |
| Inner timeout | 1000 ms |
| Added in | signalsVersion 14 |
| Collector revision | 2 (reported as revision with every result) |
Browsers can tell a page whether a video format would play, play without stutter, and play on a hardware decoder that saves battery. Which formats get a hardware decoder depends on the graphics chip, the operating system and the browser build. WhiskerJS asks about four common video formats at two sizes and keeps only the yes or no answers.
What it reads
navigator.mediaCapabilities.decodingInfo() for eight plain-file configurations (type: 'file', 30 frames per second), and from each answer only supported, smooth and powerEfficient:
| Key | Codec | Codecs string | Size | Bitrate |
|---|---|---|---|---|
h264_1080 |
H.264 High | avc1.640028 (MP4) |
1920 x 1080 | 8 Mbit/s |
h264_2160 |
H.264 High | avc1.640033 (MP4) |
3840 x 2160 | 30 Mbit/s |
vp9_1080 |
VP9 profile 0 | vp09.00.40.08 (WebM) |
1920 x 1080 | 6 Mbit/s |
vp9_2160 |
VP9 profile 0 | vp09.00.51.08 (WebM) |
3840 x 2160 | 20 Mbit/s |
av1_1080 |
AV1 Main | av01.0.08M.08 (MP4) |
1920 x 1080 | 5 Mbit/s |
av1_2160 |
AV1 Main | av01.0.12M.08 (MP4) |
3840 x 2160 | 16 Mbit/s |
hevc_1080 |
HEVC Main | hvc1.1.6.L120.90 (MP4) |
1920 x 1080 | 6 Mbit/s |
hevc_2160 |
HEVC Main | hvc1.1.6.L153.90 (MP4) |
3840 x 2160 | 20 Mbit/s |
No key system is named, so no DRM machinery starts; no media element is created, nothing is fetched and nothing prompts.
How the technique works
| Step | What happens | Value |
|---|---|---|
| 1 | ask all eight at once; wait up to 650 ms | three digits per key: supported, smooth, powerEfficient (1 or 0); ! when the call failed, ? when it did not answer in time |
| 2 | ask all eight again; wait up to 250 ms (the media stack is warm now) | |
| 3 | both rounds answered everything and differ | noisy / read_varies |
| 4 | otherwise | the first round’s answers |
The first round gets more time because the first decodingInfo() of a page can wait for the browser’s media stack to start: in one CI run Firefox gave no answer within 400 ms on a first page load (library PR #41 raised the first round from 400 to 650 ms; the component’s revision went to 2).
Why it helps
Hardware decoders differ between graphics chips, operating systems and builds: licensed codecs (H.264 in some builds, HEVC on many systems) and AV1 decode support on newer chips. powerEfficient says whether a hardware decoder would be used. On a desktop the answers mostly follow the GPU and the browser build; they say little alone but add context to webgl_renderer and the platform.
Stability
Expected to be the same from load to load on one device, but smooth and powerEfficient can follow load, power state and driver updates, so it is reported outside both ids until it is measured on real devices. Added in library PR #40 (2026-10-28) at signalsVersion 14; it is outside both ids, so no version moved and no id changed.
Browser support and what blocks it
In the self-hosted CI browser matrix (23 browsers and channels on Linux without a GPU; load, reload and a new context; Browsers runs 40635322566 and 40635905144) every browser reported ok and the same value in all three collections. No browser reported a power-efficient decoder there, since the runner has no GPU:
| Browsers | H.264 | VP9 | AV1 | HEVC |
|---|---|---|---|---|
| Chrome (stable, beta, dev, canary), Chromium, Edge (stable, beta, dev), Brave (stable, beta), Playwright’s Chromium | 110 |
110 |
110 |
000 |
| Opera (stable, beta, developer) | 000 |
110 |
110 |
000 |
| Firefox stable and ESR, Playwright’s Firefox (default and fingerprinting protection) | 110 |
110 |
110 |
111 |
| Firefox beta and nightly, Playwright’s Firefox with resistFingerprinting | 110 |
110 |
110 |
110 |
| Playwright’s WebKit | 110 |
110 |
110 |
110 |
Each cell is the same at 1080p and 2160p. Opera’s Linux build has no H.264 decoder. One earlier run caught Playwright’s Firefox with a display giving no answer within 400 ms on its first page load (unavailable / no_value there, the usual value on the reload); PR #41 gave the first round more time. Time taken: 100 to 400 ms in Firefox, about 26 ms in Brave, under about 100 ms in the other browsers.
unavailable/no_apiwithoutnavigator.mediaCapabilities(Safari before 13, Firefox before 63, Chrome before 66).- No browser class excludes it.
Privacy
It asks the browser eight fixed questions about described files and keeps eight three-digit answers; no media is created or fetched, no DRM query is made and nothing prompts. Leave it out with collect({ exclude: ['video_decoding'] }) if you do not need it; no id changes.
How WhiskerJS handles noise and failures
| Status | ruleId | When |
|---|---|---|
ok |
the answers, for example h264_1080=110,...,hevc_2160=000 |
|
unavailable |
no_api |
no navigator.mediaCapabilities.decodingInfo |
unavailable |
no_value |
no answer within the first round |
blocked |
threw, security_error |
every call failed |
noisy |
read_varies |
two rounds in a row gave different answers |
excluded |
caller_excluded |
you excluded it |
timed_out |
timeout, aborted |
budget or abort |
Example value
"video_decoding": { "status": "ok", "value": "h264_1080=110,h264_2160=110,vp9_1080=110,vp9_2160=110,av1_1080=110,av1_2160=110,hevc_1080=000,hevc_2160=000", "hashed": false, "durationMs": 31.2, "revision": 2 }
Questions and answers
Does video_decoding query DRM or key systems?
No. It never passes a keySystemConfiguration, so no Encrypted Media Extensions code starts. DRM key system queries are on the roadmap's Not doing list because they can show browser UI or leak a client id.
Does it play or download a video?
No. decodingInfo() is a question about a described file (codec, size, bitrate, frame rate); no media is created, fetched or decoded, and nothing prompts.
Why is it not in the visitorId?
smooth and powerEfficient can change with load, power state and driver updates, and the component is new and not yet measured on real devices. It is reported outside both ids.