# Browser support matrix

> The expected status of every component in nine browser families at signalsVersion 9, rendered from one data file.

Source: https://whiskerjs.com/browsers/support-matrix/ (last updated 2026-10-26)

> **In plain words:**
>
> Not every browser offers every measurement. Some lack the API, some randomise it on purpose, and some only offer it in certain modes. This table shows, for each of the 47 WhiskerJS signals, what to expect in nine browser families. It is filled from the library’s code and documentation plus one small early lab sample, so treat it as expectations, not measurements.

## How to read it

- **ok**: the value is read. **none**: read, but here the plain value is `none` (for example no Apple Pay outside Safari). **unavailable**: the browser does not offer the API, or WhiskerJS skips it here on purpose. **excluded**: the [exclusion table](https://whiskerjs.com/docs/how-it-works/#the-exclusion-table) removes it for this browser class. **varies**: depends on version, settings, a private window, an extension or the device. The Firefox Fingerprinting Protection (`firefox_fpp`) and Safari Advanced Fingerprinting Protection (`safari_afp`) classes have no column of their own; the components they exclude show **varies** in the Firefox and Safari columns. Tor Browser and Mullvad Browser (`rfp_hardened`) share the resistFingerprinting column, and Android WebView (`chromium_webview`, nothing excluded) the Chrome on Android one.
- Cells marked **lab** were seen in the early lab sample (signalsVersion 1, four device and browser pairs, not a benchmark). Every other cell is expected behaviour from the code and documentation, not yet measured.
- In any browser a component can also be `noisy` (`render_mismatch`, `seeded_noise` or `read_varies`), `blocked` or `timed_out` on a given run; see [Statuses and reason codes](https://whiskerjs.com/docs/how-it-works/#statuses-and-reason-codes).

## Where the data comes from

The page is rendered from one file in the site repository, `data/support-matrix.json`. It holds the browser list, one row per component and one cell per browser (status, basis and a short note). It will be refreshed from aggregated diagnostics once those exist; updating that file updates this page and the table at the end of every [browser page](https://whiskerjs.com/browsers/), with no code change.

## The matrix

47 components by 9 browser families, signalsVersion 9, updated 2026-10-26. Scroll sideways on a small screen. Notes for individual cells follow the table.

| Component | Group | [Chrome (desktop)](https://whiskerjs.com/browsers/chrome-desktop/) | [Chrome on Android](https://whiskerjs.com/browsers/chrome-android/) | [Safari on macOS](https://whiskerjs.com/browsers/safari-macos/) | [Safari and every iOS browser](https://whiskerjs.com/browsers/safari-ios/) | [Firefox](https://whiskerjs.com/browsers/firefox/) | [Firefox resistFingerprinting, Tor Browser and Mullvad Browser](https://whiskerjs.com/browsers/firefox-rfp-and-tor/) | [Brave](https://whiskerjs.com/browsers/brave/) | [Microsoft Edge](https://whiskerjs.com/browsers/edge/) | [Samsung Internet](https://whiskerjs.com/browsers/samsung-internet/) |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| [`apple_pay`](https://whiskerjs.com/signals/apple-pay/) | browser | none * | none * | ok * | varies * | none * | none * | none * | none * | none * |
| [`audio`](https://whiskerjs.com/signals/audio/) | audio | ok * | ok * | varies * | varies * | ok * | ok * | excluded * | ok * | ok * |
| [`audio_latency`](https://whiskerjs.com/signals/audio-latency/) | outside the ids | unavailable * | ok * | ok * | ok * | varies * | varies * | varies * | unavailable * | ok * |
| [`browser_class`](https://whiskerjs.com/signals/browser-class/) | browser | ok * | ok * | ok * | ok * | ok * | ok * | ok * | ok * | ok * |
| [`canvas`](https://whiskerjs.com/signals/canvas/) | gpu | ok * | ok * | varies * | varies * | varies * | excluded * | excluded * | ok * | ok * |
| [`canvas_readback`](https://whiskerjs.com/signals/canvas-readback/) | outside the ids | ok * | ok | varies * | varies * | varies * | varies * | varies * | ok | ok |
| [`color_depth`](https://whiskerjs.com/signals/color-depth/) | device | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`color_gamut`](https://whiskerjs.com/signals/color-gamut/) | prefs | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`content_blockers`](https://whiskerjs.com/signals/content-blockers/) | outside the ids | ok * | ok * | ok * | ok * | ok * | ok * | ok * | ok * | ok * |
| [`cpu_architecture`](https://whiskerjs.com/signals/cpu-architecture/) | device | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`device_memory`](https://whiskerjs.com/signals/device-memory/) | device | ok (lab) * | ok * | unavailable (lab) * | unavailable (lab) * | unavailable * | unavailable * | varies * | ok * | ok * |
| [`dynamic_range`](https://whiskerjs.com/signals/dynamic-range/) | prefs | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`font_preferences`](https://whiskerjs.com/signals/font-preferences/) | fonts | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`fonts`](https://whiskerjs.com/signals/fonts/) | fonts | ok | ok | ok | ok | ok | ok * | excluded * | ok | ok |
| [`fonts_canvas`](https://whiskerjs.com/signals/fonts-canvas/) | fonts | ok | ok | ok | ok | ok | ok * | excluded * | ok | ok |
| [`forced_colors`](https://whiskerjs.com/signals/forced-colors/) | prefs | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`hardware_concurrency`](https://whiskerjs.com/signals/hardware-concurrency/) | device | ok * | ok * | ok * | ok * | ok * | excluded * | excluded * | ok * | ok * |
| [`heap_limit`](https://whiskerjs.com/signals/heap-limit/) | device | ok | ok | unavailable * | unavailable * | unavailable * | unavailable * | ok | ok | ok |
| [`intl_locale`](https://whiskerjs.com/signals/intl-locale/) | locale | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`keyboard_layout`](https://whiskerjs.com/signals/keyboard-layout/) | outside the ids | ok * | varies * | unavailable * | unavailable * | unavailable * | unavailable * | varies * | ok * | varies * |
| [`languages`](https://whiskerjs.com/signals/languages/) | locale | ok | ok | ok | ok | ok | ok * | ok | ok | ok |
| [`math`](https://whiskerjs.com/signals/math/) | browser | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`media_codecs`](https://whiskerjs.com/signals/media-codecs/) | browser | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`noise_profile`](https://whiskerjs.com/signals/noise-profile/) | outside the ids | ok * | ok * | ok * | ok * | ok * | ok * | ok * | ok * | ok * |
| [`pdf_viewer`](https://whiskerjs.com/signals/pdf-viewer/) | browser | ok | ok | ok | varies * | ok | ok | ok | ok | ok |
| [`permissions`](https://whiskerjs.com/signals/permissions/) | outside the ids | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`pixel_ratio`](https://whiskerjs.com/signals/pixel-ratio/) | outside the ids | ok | ok | ok | ok | ok | excluded * | ok | ok | ok |
| [`platform`](https://whiskerjs.com/signals/platform/) | browser | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`plugins`](https://whiskerjs.com/signals/plugins/) | browser | ok | varies * | ok | varies * | ok | ok | excluded * | ok | varies * |
| [`prefers_contrast`](https://whiskerjs.com/signals/prefers-contrast/) | prefs | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`private_click`](https://whiskerjs.com/signals/private-click/) | browser | none * | none * | ok * | varies * | none * | none * | none * | none * | none * |
| [`reduced_motion`](https://whiskerjs.com/signals/reduced-motion/) | prefs | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`screen_frame`](https://whiskerjs.com/signals/screen-frame/) | outside the ids | ok | ok | varies * | varies * | varies * | excluded * | ok | ok | ok |
| [`screen_resolution`](https://whiskerjs.com/signals/screen-resolution/) | device | ok | ok | varies * | varies * | ok | excluded * | ok | ok | ok |
| [`speech_voices`](https://whiskerjs.com/signals/speech-voices/) | outside the ids | ok * | ok * | ok * | ok * | ok * | varies * | excluded * | ok * | ok * |
| [`storage`](https://whiskerjs.com/signals/storage/) | browser | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`time_zone`](https://whiskerjs.com/signals/time-zone/) | locale | ok | ok | ok | ok | ok | excluded * | ok | ok | ok |
| [`touch_support`](https://whiskerjs.com/signals/touch-support/) | device | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`ua_client_hints`](https://whiskerjs.com/signals/ua-client-hints/) | browser | ok * | ok * | unavailable * | unavailable * | unavailable * | unavailable * | ok * | ok * | ok * |
| [`ua_versions`](https://whiskerjs.com/signals/ua-versions/) | outside the ids | ok | ok | unavailable * | unavailable * | unavailable * | unavailable * | ok * | ok | ok |
| [`vendor`](https://whiskerjs.com/signals/vendor/) | browser | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`vendor_flavors`](https://whiskerjs.com/signals/vendor-flavors/) | browser | ok | ok | ok | ok | ok | ok | ok | ok | ok |
| [`webgl_image`](https://whiskerjs.com/signals/webgl-image/) | gpu | ok * | ok * | varies * | varies * | varies * | excluded * | excluded * | ok * | ok * |
| [`webgl_params`](https://whiskerjs.com/signals/webgl-params/) | gpu | ok * | ok * | ok * | ok * | ok * | ok * | excluded * | ok * | ok * |
| [`webgl_renderer`](https://whiskerjs.com/signals/webgl-renderer/) | gpu | ok | ok | ok * | ok * | ok * | excluded * | excluded * | ok | ok |
| [`webgl_vendor`](https://whiskerjs.com/signals/webgl-vendor/) | gpu | ok | ok | ok | ok | ok * | excluded * | excluded * | ok | ok |
| [`webgpu`](https://whiskerjs.com/signals/webgpu/) | gpu | varies * | varies * | varies * | varies * | varies * | varies * | excluded * | varies * | varies * |

Filled on 2026-10-26 from the WhiskerJS code and documentation at signalsVersion 9 (expected behaviour) and from the early lab sample at signalsVersion 1 (four device-browser pairs). It is not a measurement. Privacy modes (Firefox Fingerprinting Protection, Safari Advanced Fingerprinting Protection) are shown as varies on the stock browser's column. It will be refreshed from aggregated diagnostics once those exist; this file is the only place to change.

## Notes on individual cells

Every cell marked with * above, by component.

| Component | Browser | Status | Note |
| --- | --- | --- | --- |
| `apple_pay` | Chrome (desktop) | none | No ApplePaySession: reports the plain value none. |
| `apple_pay` | Chrome on Android | none | No ApplePaySession: reports the plain value none. |
| `apple_pay` | Safari on macOS | ok | version=<n>;can_pay=<1, 0 or blocked>; can_pay is blocked in insecure or cross-origin contexts. |
| `apple_pay` | Safari and every iOS browser | varies | Safari has ApplePaySession; in other iOS browsers it depends on the app. none where it is missing. |
| `apple_pay` | Firefox | none | No ApplePaySession: reports the plain value none. |
| `apple_pay` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | none | No ApplePaySession: reports the plain value none. |
| `apple_pay` | Brave | none | No ApplePaySession: reports the plain value none. |
| `apple_pay` | Microsoft Edge | none | No ApplePaySession: reports the plain value none. |
| `apple_pay` | Samsung Internet | none | No ApplePaySession: reports the plain value none. |
| `audio` | Chrome (desktop) | ok | noisy / seeded_noise if the audio known-answer probe sees noise. |
| `audio` | Chrome on Android | ok | noisy / seeded_noise if the audio known-answer probe sees noise. |
| `audio` | Safari on macOS | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `audio` | Safari and every iOS browser | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `audio` | Firefox | ok | noisy / seeded_noise if the audio known-answer probe sees noise. |
| `audio` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | ok | noisy / seeded_noise if the audio known-answer probe sees noise. |
| `audio` | Brave | excluded | Exclusion table: brave_farbling (Brave adds per-site, per-session noise). |
| `audio` | Microsoft Edge | ok | noisy / seeded_noise if the audio known-answer probe sees noise. |
| `audio` | Samsung Internet | ok | noisy / seeded_noise if the audio known-answer probe sees noise. |
| `audio_latency` | Chrome (desktop) | unavailable | Skipped (unavailable / skipped): creating an AudioContext here would print a console warning. |
| `audio_latency` | Chrome on Android | ok | Read when the user agent says Android. |
| `audio_latency` | Safari on macOS | ok | Read for browser class safari; the context is closed at once. |
| `audio_latency` | Safari and every iOS browser | ok | Read for browser class safari; the context is closed at once. |
| `audio_latency` | Firefox | varies | Skipped on desktop; Firefox for Android has an Android user agent, so it is read there. |
| `audio_latency` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | varies | Skipped on desktop; read only with an Android user agent. |
| `audio_latency` | Brave | varies | Read on Android (Android user agent), skipped on desktop. |
| `audio_latency` | Microsoft Edge | unavailable | Skipped (unavailable / skipped): creating an AudioContext here would print a console warning. |
| `audio_latency` | Samsung Internet | ok | Read when the user agent says Android. |
| `browser_class` | Chrome (desktop) | ok | Class chromium. |
| `browser_class` | Chrome on Android | ok | Class chromium; chromium_webview in Android WebView (in-app browsers). |
| `browser_class` | Safari on macOS | ok | Class safari; safari_afp when Advanced Fingerprinting Protection alters canvas or WebGL readback. |
| `browser_class` | Safari and every iOS browser | ok | Class safari, for every iOS browser (Apple vendor, no Chrome/ token); safari_afp when Advanced Fingerprinting Protection alters canvas or WebGL readback. |
| `browser_class` | Firefox | ok | Class firefox; firefox_fpp when Fingerprinting Protection alters canvas or WebGL readback. |
| `browser_class` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | ok | Class firefox_rfp only when every resistFingerprinting trait holds, rfp_hardened for Tor and Mullvad Browser (letterboxing and spoofed English); otherwise firefox. |
| `browser_class` | Brave | ok | Class brave (navigator.brave.isBrave is a function). |
| `browser_class` | Microsoft Edge | ok | Class chromium. |
| `browser_class` | Samsung Internet | ok | Class chromium. |
| `canvas` | Chrome (desktop) | ok | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
| `canvas` | Chrome on Android | ok | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
| `canvas` | Safari on macOS | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `canvas` | Safari and every iOS browser | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `canvas` | Firefox | varies | Excluded (firefox_fpp) when Fingerprinting Protection is on: in private windows, and in normal windows as Firefox 151 and later roll it out. Otherwise ok. |
| `canvas` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | excluded | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
| `canvas` | Brave | excluded | Exclusion table: brave_farbling (Brave adds per-site, per-session noise). |
| `canvas` | Microsoft Edge | ok | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
| `canvas` | Samsung Internet | ok | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
| `canvas_readback` | Chrome (desktop) | ok | exact, or altered when an extension adds noise. |
| `canvas_readback` | Safari on macOS | varies | exact, or altered with Advanced Fingerprinting Protection (always in private browsing). |
| `canvas_readback` | Safari and every iOS browser | varies | exact, or altered with Advanced Fingerprinting Protection (always in private browsing). |
| `canvas_readback` | Firefox | varies | exact, or altered with Fingerprinting Protection or a canvas-noise extension. |
| `canvas_readback` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | varies | resistFingerprinting changes canvas readback, so altered is likely. |
| `canvas_readback` | Brave | varies | Not excluded; Brave's canvas farbling can make it report altered. |
| `content_blockers` | Chrome (desktop) | ok | none, or the bait names a content blocker hid. |
| `content_blockers` | Chrome on Android | ok | none, or the bait names a content blocker hid. |
| `content_blockers` | Safari on macOS | ok | none, or the bait names a content blocker hid. |
| `content_blockers` | Safari and every iOS browser | ok | none, or the bait names a content blocker hid. |
| `content_blockers` | Firefox | ok | none, or the bait names a content blocker hid. |
| `content_blockers` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | ok | none, or the bait names a content blocker hid. |
| `content_blockers` | Brave | ok | Brave's built-in blocking may hide some baits; reports the hidden bait names or none. |
| `content_blockers` | Microsoft Edge | ok | none, or the bait names a content blocker hid. |
| `content_blockers` | Samsung Internet | ok | none, or the bait names a content blocker hid. |
| `device_memory` | Chrome (desktop) | ok (lab) | Seen ok on Mac Chrome in the lab sample. From Chromium 146 the value carries the tag ;c146 (new buckets). |
| `device_memory` | Chrome on Android | ok | From Chromium 146 the value carries the tag ;c146 (new buckets). |
| `device_memory` | Safari on macOS | unavailable (lab) | Seen unavailable on Mac Safari in the lab sample; Safari does not offer navigator.deviceMemory. |
| `device_memory` | Safari and every iOS browser | unavailable (lab) | Seen unavailable on iPhone Safari and iPhone Chrome in the lab sample; no iOS browser offers it. |
| `device_memory` | Firefox | unavailable | navigator.deviceMemory is a Chromium API. Reports unavailable / no_api. |
| `device_memory` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | unavailable | navigator.deviceMemory is a Chromium API. Reports unavailable / no_api. |
| `device_memory` | Brave | varies | Chromium API; Brave's fingerprinting protections may change the value. From Chromium 146 the value carries the tag ;c146. |
| `device_memory` | Microsoft Edge | ok | From Chromium 146 the value carries the tag ;c146 (new buckets). |
| `device_memory` | Samsung Internet | ok | From Chromium 146 the value carries the tag ;c146 (new buckets). |
| `fonts` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | ok | Tor Browser limits fonts to a bundled set, so values are alike across its users. |
| `fonts` | Brave | excluded | Exclusion table: brave_farbling (Brave adds per-site, per-session noise). |
| `fonts_canvas` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | ok | Tor Browser limits fonts to a bundled set, so values are alike across its users. |
| `fonts_canvas` | Brave | excluded | Exclusion table: brave_farbling (Brave adds per-site, per-session noise). |
| `hardware_concurrency` | Chrome (desktop) | ok | Read 16 times; noisy / read_varies if the reads disagree. Some browsers cap or round the value. |
| `hardware_concurrency` | Chrome on Android | ok | Read 16 times; noisy / read_varies if the reads disagree. Some browsers cap or round the value. |
| `hardware_concurrency` | Safari on macOS | ok | Read 16 times; a 4 or an 8 is reported as the bucket 4_8, because WebKit alternates between them for scripts on its known-fingerprinting list. |
| `hardware_concurrency` | Safari and every iOS browser | ok | Read 16 times; a 4 or an 8 is reported as the bucket 4_8, because WebKit alternates between them for scripts on its known-fingerprinting list. |
| `hardware_concurrency` | Firefox | ok | Read 16 times; noisy / read_varies if the reads disagree. Some browsers cap or round the value. |
| `hardware_concurrency` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | excluded | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
| `hardware_concurrency` | Brave | excluded | Exclusion table: brave_farbling (Brave adds per-site, per-session noise). |
| `hardware_concurrency` | Microsoft Edge | ok | Read 16 times; noisy / read_varies if the reads disagree. Some browsers cap or round the value. |
| `hardware_concurrency` | Samsung Internet | ok | Read 16 times; noisy / read_varies if the reads disagree. Some browsers cap or round the value. |
| `heap_limit` | Safari on macOS | unavailable | performance.memory is a Chromium API. Reports unavailable / no_api. |
| `heap_limit` | Safari and every iOS browser | unavailable | performance.memory is a Chromium API. Reports unavailable / no_api. |
| `heap_limit` | Firefox | unavailable | performance.memory is a Chromium API. Reports unavailable / no_api. |
| `heap_limit` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | unavailable | performance.memory is a Chromium API. Reports unavailable / no_api. |
| `keyboard_layout` | Chrome (desktop) | ok | navigator.keyboard.getLayoutMap() is a Chromium desktop API; blocked in cross-origin iframes. |
| `keyboard_layout` | Chrome on Android | varies | Chromium API meant for physical keyboards; on Android expect unavailable. |
| `keyboard_layout` | Safari on macOS | unavailable | No navigator.keyboard here: unavailable / no_api. |
| `keyboard_layout` | Safari and every iOS browser | unavailable | No navigator.keyboard here: unavailable / no_api. |
| `keyboard_layout` | Firefox | unavailable | No navigator.keyboard here: unavailable / no_api. |
| `keyboard_layout` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | unavailable | No navigator.keyboard here: unavailable / no_api. |
| `keyboard_layout` | Brave | varies | Chromium API; Brave may turn it off. |
| `keyboard_layout` | Microsoft Edge | ok | navigator.keyboard.getLayoutMap() is a Chromium desktop API; blocked in cross-origin iframes. |
| `keyboard_layout` | Samsung Internet | varies | Chromium API meant for physical keyboards; on Android expect unavailable. |
| `languages` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | ok | resistFingerprinting can normalise the reported language. |
| `noise_profile` | Chrome (desktop) | ok | canvas=exact,webgl=exact,audio=exact on a stock browser; webgl=na without WebGL. |
| `noise_profile` | Chrome on Android | ok | canvas=exact,webgl=exact,audio=exact on a stock browser; webgl=na without WebGL. |
| `noise_profile` | Safari on macOS | ok | exact in a normal window; seeded for the APIs Advanced Fingerprinting Protection randomises. |
| `noise_profile` | Safari and every iOS browser | ok | exact in a normal window; seeded for the APIs Advanced Fingerprinting Protection randomises. |
| `noise_profile` | Firefox | ok | exact on stock Firefox; seeded for canvas or WebGL with Fingerprinting Protection or a noise extension. |
| `noise_profile` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | ok | Probe states other than exact are likely, since resistFingerprinting changes readback. |
| `noise_profile` | Brave | ok | Typically seeded for the APIs Brave farbles. |
| `noise_profile` | Microsoft Edge | ok | canvas=exact,webgl=exact,audio=exact on a stock browser; webgl=na without WebGL. |
| `noise_profile` | Samsung Internet | ok | canvas=exact,webgl=exact,audio=exact on a stock browser; webgl=na without WebGL. |
| `pdf_viewer` | Safari and every iOS browser | varies | unavailable where navigator.pdfViewerEnabled does not exist. |
| `pixel_ratio` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | excluded | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
| `plugins` | Chrome on Android | varies | Mobile builds often list no plugins and then report the plain value none. |
| `plugins` | Safari and every iOS browser | varies | Mobile builds often list no plugins and then report the plain value none. |
| `plugins` | Brave | excluded | Exclusion table: brave_farbling (Brave adds per-site, per-session noise). |
| `plugins` | Samsung Internet | varies | Mobile builds often list no plugins and then report the plain value none. |
| `private_click` | Chrome (desktop) | none | No attributionSourceId on anchors: reports the plain value none. |
| `private_click` | Chrome on Android | none | No attributionSourceId on anchors: reports the plain value none. |
| `private_click` | Safari on macOS | ok | Safari Private Click Measurement exposes attributionSourceId. |
| `private_click` | Safari and every iOS browser | varies | Depends on whether the app's WebKit exposes Private Click Measurement; none otherwise. |
| `private_click` | Firefox | none | No attributionSourceId on anchors: reports the plain value none. |
| `private_click` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | none | No attributionSourceId on anchors: reports the plain value none. |
| `private_click` | Brave | none | No attributionSourceId on anchors: reports the plain value none. |
| `private_click` | Microsoft Edge | none | No attributionSourceId on anchors: reports the plain value none. |
| `private_click` | Samsung Internet | none | No attributionSourceId on anchors: reports the plain value none. |
| `screen_frame` | Safari on macOS | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `screen_frame` | Safari and every iOS browser | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `screen_frame` | Firefox | varies | Excluded (firefox_fpp) when Fingerprinting Protection is on: in private windows, and in normal windows as Firefox 151 and later roll it out. Otherwise ok. |
| `screen_frame` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | excluded | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
| `screen_resolution` | Safari on macOS | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `screen_resolution` | Safari and every iOS browser | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `screen_resolution` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | excluded | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
| `speech_voices` | Chrome (desktop) | ok | Digest of the voice list, or none; some browsers fill the list late. |
| `speech_voices` | Chrome on Android | ok | Digest of the voice list, or none; some browsers fill the list late. |
| `speech_voices` | Safari on macOS | ok | Digest of the voice list, or none; some browsers fill the list late. |
| `speech_voices` | Safari and every iOS browser | ok | Digest of the voice list, or none; some browsers fill the list late. |
| `speech_voices` | Firefox | ok | Digest of the voice list, or none; some browsers fill the list late. |
| `speech_voices` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | varies | Digest of the voice list, or none when the list is empty. |
| `speech_voices` | Brave | excluded | Exclusion table: brave_farbling (Brave farbles the voice list). |
| `speech_voices` | Microsoft Edge | ok | Digest of the voice list, or none; some browsers fill the list late. |
| `speech_voices` | Samsung Internet | ok | Digest of the voice list, or none; some browsers fill the list late. |
| `time_zone` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | excluded | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
| `ua_client_hints` | Chrome (desktop) | ok | he=blocked when a Permissions Policy refuses the detailed hints. |
| `ua_client_hints` | Chrome on Android | ok | he=blocked when a Permissions Policy refuses the detailed hints. |
| `ua_client_hints` | Safari on macOS | unavailable | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
| `ua_client_hints` | Safari and every iOS browser | unavailable | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
| `ua_client_hints` | Firefox | unavailable | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
| `ua_client_hints` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | unavailable | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
| `ua_client_hints` | Brave | ok | Chromium API; the brand list is whatever Brave reports. |
| `ua_client_hints` | Microsoft Edge | ok | he=blocked when a Permissions Policy refuses the detailed hints. |
| `ua_client_hints` | Samsung Internet | ok | he=blocked when a Permissions Policy refuses the detailed hints. |
| `ua_versions` | Safari on macOS | unavailable | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
| `ua_versions` | Safari and every iOS browser | unavailable | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
| `ua_versions` | Firefox | unavailable | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
| `ua_versions` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | unavailable | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
| `ua_versions` | Brave | ok | Chromium API; not in either id. |
| `webgl_image` | Chrome (desktop) | ok | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
| `webgl_image` | Chrome on Android | ok | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
| `webgl_image` | Safari on macOS | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `webgl_image` | Safari and every iOS browser | varies | Excluded (safari_afp) when Advanced Fingerprinting Protection is on: always in private browsing, and in all browsing where the setting says so. Otherwise ok. |
| `webgl_image` | Firefox | varies | Excluded (firefox_fpp) when Fingerprinting Protection is on: in private windows, and in normal windows as Firefox 151 and later roll it out. Otherwise ok. |
| `webgl_image` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | excluded | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
| `webgl_image` | Brave | excluded | Exclusion table: brave_farbling (Brave adds per-site, per-session noise). |
| `webgl_image` | Microsoft Edge | ok | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
| `webgl_image` | Samsung Internet | ok | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
| `webgl_params` | Chrome (desktop) | ok | Where WebGL 1 is available; unavailable / no_context without it. |
| `webgl_params` | Chrome on Android | ok | Where WebGL 1 is available; unavailable / no_context without it. |
| `webgl_params` | Safari on macOS | ok | Where WebGL 1 is available; unavailable / no_context without it. |
| `webgl_params` | Safari and every iOS browser | ok | Where WebGL 1 is available; unavailable / no_context without it. |
| `webgl_params` | Firefox | ok | Where WebGL 1 is available; unavailable / no_context without it. |
| `webgl_params` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | ok | Where WebGL 1 is available; unavailable / no_context without it. |
| `webgl_params` | Brave | excluded | Exclusion table: brave_farbling (since Brave 1.93 every user reports generic values). |
| `webgl_params` | Microsoft Edge | ok | Where WebGL 1 is available; unavailable / no_context without it. |
| `webgl_params` | Samsung Internet | ok | Where WebGL 1 is available; unavailable / no_context without it. |
| `webgl_renderer` | Safari on macOS | ok | Often a generic string such as Apple GPU. |
| `webgl_renderer` | Safari and every iOS browser | ok | Often a generic string such as Apple GPU. |
| `webgl_renderer` | Firefox | ok | Read from gl.RENDERER; WEBGL_debug_renderer_info is not requested in Firefox. |
| `webgl_renderer` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | excluded | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). Neither renderer flag can fire. |
| `webgl_renderer` | Brave | excluded | Exclusion table: brave_farbling (since Brave 1.93 every user reports generic values). |
| `webgl_vendor` | Firefox | ok | Read from gl.VENDOR; WEBGL_debug_renderer_info is not requested in Firefox. |
| `webgl_vendor` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | excluded | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
| `webgl_vendor` | Brave | excluded | Exclusion table: brave_farbling (since Brave 1.93 every user reports generic values). |
| `webgpu` | Chrome (desktop) | varies | Depends on browser version, operating system and GPU; needs a secure context. unavailable / no_api without navigator.gpu, no_context without an adapter. |
| `webgpu` | Chrome on Android | varies | Depends on browser version, operating system and GPU; needs a secure context. unavailable / no_api without navigator.gpu, no_context without an adapter. |
| `webgpu` | Safari on macOS | varies | Depends on browser version, operating system and GPU; needs a secure context. unavailable / no_api without navigator.gpu, no_context without an adapter. |
| `webgpu` | Safari and every iOS browser | varies | Depends on browser version, operating system and GPU; needs a secure context. unavailable / no_api without navigator.gpu, no_context without an adapter. |
| `webgpu` | Firefox | varies | Depends on browser version, operating system and GPU; needs a secure context. unavailable / no_api without navigator.gpu, no_context without an adapter. |
| `webgpu` | Firefox resistFingerprinting, Tor Browser and Mullvad Browser | varies | Depends on browser version, operating system and GPU; needs a secure context. unavailable / no_api without navigator.gpu, no_context without an adapter. |
| `webgpu` | Brave | excluded | Exclusion table: brave_farbling (since Brave 1.93 the adapter fields are emptied). |
| `webgpu` | Microsoft Edge | varies | Depends on browser version, operating system and GPU; needs a secure context. unavailable / no_api without navigator.gpu, no_context without an adapter. |
| `webgpu` | Samsung Internet | varies | Depends on browser version, operating system and GPU; needs a secure context. unavailable / no_api without navigator.gpu, no_context without an adapter. |

## Questions and answers

### Is this matrix measured?

Not yet. Almost every cell is expected behaviour read from the library code and documentation. Only the cells marked lab come from the early lab sample at signalsVersion 1, which covered four device and browser pairs. The matrix will be refreshed from aggregated diagnostics.

### Why do all iOS browsers share one column?

On iOS every browser uses Apple's WebKit engine and reports the Apple vendor, so WhiskerJS classes Chrome, Firefox and Edge on iOS as safari, the same as Safari itself.

### What does varies mean?

The status depends on the browser version, a setting, a private window, an extension or the device. The note on that row says what it depends on. Firefox Fingerprinting Protection and Safari Advanced Fingerprinting Protection have no column of their own: the components they exclude show varies in the Firefox and Safari columns.

## Related pages

- [Browsers](https://whiskerjs.com/browsers/): One page per browser family, with what works and what is excluded.
- [The exclusion table](https://whiskerjs.com/docs/how-it-works/#the-exclusion-table): Why Brave and the Firefox and Safari privacy modes skip some components.
- [Signals](https://whiskerjs.com/signals/): Every component on its own page.
- [Live demo](https://whiskerjs.com/demo/): See the real statuses in your own browser.
