# media_codecs

> Which of 8 audio and 12 video formats the browser says it can play, asked of a media element and of MediaSource. Nothing is loaded or played.

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

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

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

> **In plain words:**
>
> Browsers support different audio and video formats, depending on the browser, its build and the operating system’s media libraries. WhiskerJS asks the browser, for 20 common formats, “could you play this?”, and hashes the answers. It never loads, downloads or plays any media.

## What it reads

For each of 8 audio and 12 video MIME types:

- the answer of `canPlayType(type)` on a new `<audio>` or `<video>` element: `probably`, `maybe` or an empty string (written as `no`);
- the answer of `MediaSource.isTypeSupported(type)`, written `1` or `0`.

The audio types include `audio/mp4; codecs="mp4a.40.2"`, `audio/mpeg;`, Vorbis in WebM and Ogg, WAV, Speex, FLAC and AMR in 3GPP. The video types include five H.264 profiles in MP4, two MPEG-4 Part 2 forms, VP8 in WebM, Theora and Dirac in Ogg, MPEG-4 in 3GPP and Theora in Matroska.

## How the technique works

1. One `<audio>` and one `<video>` element are created with `document.createElement`. They are never given a source and never attached, so the browser loads nothing.
2. For each type, `canPlayType` is called on the matching element, and `MediaSource.isTypeSupported` is called if MediaSource exists. A missing method gives `-`, a throw gives `!`.
3. Each answer is written `type=<play>/<source>`, joined with `;`, and always hashed (SHA-256, first 128 bits).

The two MIME lists are adapted from fpscanner 1.0.8 (MIT), with the notice kept.

## Why it helps

The answers follow the browser’s media stack: which decoders it ships, which it gets from the operating system, and how confidently it answers (`maybe` against `probably`). Chromium, Firefox and WebKit differ, and so can builds of one browser on different systems. MediaSource support adds a second, independent view.

## Stability

Stable between visits. It changes when the browser or operating system gains or drops a codec, which happens with updates. That moves the visitorId and the `browser` part of the structuredId.

## Browser support and what blocks it

All current browsers answer `canPlayType`. Where `MediaSource` is missing, the source half of each answer is `-` and the component is still `ok`. See the [browser pages](https://whiskerjs.com/browsers/) and the [support matrix](https://whiskerjs.com/browsers/support-matrix/). No browser class excludes it.

## Privacy

The value describes the browser build’s media support, which is shared by everyone with the same browser and system. It is reported only as a digest. No media is fetched, so there is no network trace.

## How WhiskerJS handles noise and failures

| Status | ruleId | When |
| --- | --- | --- |
| `ok` |   | digest of the 20 answers |
| `unavailable` | `no_document` | no `document` or no `createElement` |
| `unavailable` | `no_api` | neither `canPlayType` nor `MediaSource.isTypeSupported` answered for any type (every entry `-/-`) |
| `unavailable` | `no_digest` | no `crypto.subtle`, so it cannot be hashed |
| `blocked` | `threw`, `security_error` | creating an element throws |
| `excluded` | `caller_excluded` | you excluded it |
| `timed_out` | `timeout`, `aborted` | budget or abort |

Single failing calls become `!` inside the value instead of failing the component.

## Example value

In the container test, headless Chromium gave `dcdbcc9c150c1b84d9741e38cfcc6ddf`, Firefox `a20d8637fc821657c25051d9329cfb27` and WebKit `1e05ba5e0df74709cab1f47e421950b5`: three engines, three different answers.

## Questions and answers

### Does media_codecs download or play anything?

No. It creates an audio and a video element that never get a source and are never attached to the page, and asks them canPlayType(). MediaSource.isTypeSupported() is a pure question too.

### Why does it change after a browser update?

Browsers add and drop codec support over time, and canPlayType answers can move between maybe and probably. Any change in the 20 answers changes the digest.

### Where do the MIME types come from?

The two lists are adapted from fpscanner 1.0.8 under the MIT licence, with the notice kept. The probing code is WhiskerJS's own.

## Related pages

- [math](https://whiskerjs.com/signals/math/): Another engine-build signal in the browser group.
- [browser_class](https://whiskerjs.com/signals/browser-class/): The browser family guess.
- [ua_client_hints](https://whiskerjs.com/signals/ua-client-hints/): Brands and platform from Client Hints.
- [Comparing two results](https://whiskerjs.com/docs/identifiers/#comparing-two-results): Why a change here moves only the browser part.
