Firefox has a setting called resistFingerprinting, and Tor Browser and Mullvad Browser use it too. It makes the browser report the same, deliberately ordinary values as many other users: the time zone, the screen size and several graphics details. Reading those values would add nothing useful, so when WhiskerJS sees all the signs of this mode it simply does not collect nine of its measurements. It is careful to switch only when every sign is there, so an ordinary Firefox is not affected.
At a glance
- Browser class:
firefox_rfp, a special case of Firefox;rfp_hardenedfor Tor Browser and Mullvad Browser (since signalsVersion 6). - Excluded components: 9, with ruleId
firefox_rfporrfp_hardened(7 of them in the visitorId). Both rows list the same components. - Also unavailable by design, as in any Firefox:
device_memory,heap_limit,ua_client_hints,ua_versions,keyboard_layout. - Lab sample: none.
The exact test
A Firefox (a Firefox/<number> user agent token or mozInnerScreenX) is classed firefox_rfp only when all of these hold, in this order, as written in src/browser-class.ts:
- The Intl time zone is
UTC,Etc/UTCorAtlantic/Reykjavik(newer releases report the last). navigator.webdriveris nottrue.screen.widthis a positive number equal toinnerWidth, andscreen.heightequalsinnerHeight(the screen is the content area).screen.availWidthandavailHeightequal the screen size (no space kept for a taskbar).devicePixelRatiois exactly 1.screenXandscreenYare 0 (or absent).
If all six hold, the class is rfp_hardened when, in addition, the content area is on the letterboxing steps (innerWidth a positive multiple of 200 and innerHeight a positive multiple of 100 CSS pixels) and navigator.languages is en-US alone or en-US,en; otherwise firefox_rfp.
Otherwise it is plain firefox (or firefox_fpp when the canvas or WebGL known-answer probe came back altered; see Firefox). Each trait alone is common in stock Firefox, and stock Firefox under automation matches several of them (Playwright runs it in UTC with the screen equal to the viewport), so the test errs towards firefox. A missed resistFingerprinting browser only leaves normalised values in the result; a false positive would drop nine components from a normal browser.
The signalsVersion 5 fix
Before signalsVersion 5, stock Firefox under automation was wrongly classed firefox_rfp and lost nine components. The class now needs every trait at once, accepts Atlantic/Reykjavik as an RFP time zone, and never applies when navigator.webdriver is true. The id effect is limited to Firefox browsers that were wrongly classed before. See What’s new.
What works
Everything not in the exclusion row: offline audio, fonts and font preferences, WebGL parameters, Math, codecs, plugins, languages and Intl locale, color depth, touch support, storage presence, permission states and the display preference queries. Several of these will also be normalised by resistFingerprinting (for example the language), so expect them to be alike across users; WhiskerJS reports what the browser says.
What is unavailable or blocked
The Chromium-only components are unavailable / no_api as in any Firefox. audio_latency is skipped on desktop. canvas_readback and noise_profile are not excluded, but resistFingerprinting changes canvas readback, so altered or a probe state other than exact is likely; that is useful information in itself.
What WhiskerJS excludes and why
| Component | In visitorId | What resistFingerprinting does to it |
|---|---|---|
canvas |
yes | blocks or alters canvas readback |
hardware_concurrency |
yes | reports a fixed core count |
pixel_ratio |
no | reports 1 |
screen_frame |
no | available area equal to the screen |
screen_resolution |
yes | the content-area size as the screen |
time_zone |
yes | UTC (newer releases Atlantic/Reykjavik) |
webgl_image |
yes | blocks or alters readback |
webgl_renderer |
yes | placeholder strings |
webgl_vendor |
yes | placeholder strings |
These report excluded with ruleId firefox_rfp, or rfp_hardened for Tor Browser and Mullvad Browser. With the WebGL renderer excluded, neither software_renderer nor vm_renderer can fire. In the ids they count as “missing”, the same in every run, so they do not make the id unstable.
Tor Browser and Mullvad Browser
Tor Browser and Mullvad Browser are built on Firefox and use resistFingerprinting, so they normally meet the test above. Since signalsVersion 6 they are classed rfp_hardened, recognised by two further measures they apply: letterboxing, which keeps the content area on steps of 200 by 100 CSS pixels, and a spoofed English locale (navigator.languages is en-US or en-US,en). A stock resistFingerprinting Firefox in English whose window happens to sit on those steps (its first window is rounded to them) is classed rfp_hardened too; the two rows exclude the same components, so only the label differs. The Tor Project describes further measures, such as shipping a limited set of fonts, all aimed at making users look the same. WhiskerJS does not try to get around any of it. In practice, many Tor Browser users of the same version will look alike, and sharing a visitorId is expected. For fraud and abuse work, the fact that a visitor uses Tor is usually better taken from your server’s own view (for example the network address) than from the fingerprint.
Integrity flags to expect
native_tamperingandprototype_lieonly if add-ons override functions; resistFingerprinting itself changes values inside the browser.engine_mismatchexpects Gecko behaviour for these classes, as for Firefox.timezone_inconsistentdoes not fire: resistFingerprinting reports UTC through bothIntlandDate.media_query_mismatchdoes not run for these classes.- Under automation
navigator.webdriveris true, so the browser is classedfirefoxinstead andautomation_webdriverfires.
Early lab observations
There is no lab data for resistFingerprinting, Tor Browser or Mullvad Browser yet; the early, small sample at signalsVersion 1 covered Mac and iPhone Chrome and Safari only.
Testing it yourself
In Firefox, set privacy.resistFingerprinting to true in about:config, maximise or resize as your setup needs, and open the live demo. If browser_class says firefox_rfp (or rfp_hardened in Tor Browser or Mullvad Browser), the nine components above show excluded. If it says firefox, one of the traits did not hold; that is the safe outcome. The lab mode copies one line per run.
Support table for Firefox resistFingerprinting, Tor Browser and Mullvad Browser
Expected status of every component in this browser at signalsVersion 9, from the support matrix (updated 2026-10-26). Basis "code" means expected from the library code and documentation, not yet measured; "lab" means seen in the early lab sample.
| Component | Status | Basis | Note |
|---|---|---|---|
apple_pay | none | code | No ApplePaySession: reports the plain value none. |
audio | ok | code | noisy / seeded_noise if the audio known-answer probe sees noise. |
audio_latency | varies | code | Skipped on desktop; read only with an Android user agent. |
browser_class | ok | code | Class firefox_rfp only when every resistFingerprinting trait holds, rfp_hardened for Tor and Mullvad Browser (letterboxing and spoofed English); otherwise firefox. |
canvas | excluded | code | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
canvas_readback | varies | code | resistFingerprinting changes canvas readback, so altered is likely. |
color_depth | ok | code | |
color_gamut | ok | code | |
content_blockers | ok | code | none, or the bait names a content blocker hid. |
cpu_architecture | ok | code | |
device_memory | unavailable | code | navigator.deviceMemory is a Chromium API. Reports unavailable / no_api. |
dynamic_range | ok | code | |
font_preferences | ok | code | |
fonts | ok | code | Tor Browser limits fonts to a bundled set, so values are alike across its users. |
fonts_canvas | ok | code | Tor Browser limits fonts to a bundled set, so values are alike across its users. |
forced_colors | ok | code | |
hardware_concurrency | excluded | code | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
heap_limit | unavailable | code | performance.memory is a Chromium API. Reports unavailable / no_api. |
intl_locale | ok | code | |
keyboard_layout | unavailable | code | No navigator.keyboard here: unavailable / no_api. |
languages | ok | code | resistFingerprinting can normalise the reported language. |
math | ok | code | |
media_codecs | ok | code | |
noise_profile | ok | code | Probe states other than exact are likely, since resistFingerprinting changes readback. |
pdf_viewer | ok | code | |
permissions | ok | code | |
pixel_ratio | excluded | code | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
platform | ok | code | |
plugins | ok | code | |
prefers_contrast | ok | code | |
private_click | none | code | No attributionSourceId on anchors: reports the plain value none. |
reduced_motion | ok | code | |
screen_frame | excluded | code | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
screen_resolution | excluded | code | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
speech_voices | varies | code | Digest of the voice list, or none when the list is empty. |
storage | ok | code | |
time_zone | excluded | code | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
touch_support | ok | code | |
ua_client_hints | unavailable | code | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
ua_versions | unavailable | code | navigator.userAgentData (Client Hints) is a Chromium API. Reports unavailable / no_api. |
vendor | ok | code | |
vendor_flavors | ok | code | |
webgl_image | excluded | code | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
webgl_params | ok | code | Where WebGL 1 is available; unavailable / no_context without it. |
webgl_renderer | excluded | code | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). Neither renderer flag can fire. |
webgl_vendor | excluded | code | Exclusion table: firefox_rfp, or rfp_hardened in Tor and Mullvad Browser (fixed or normalised values). |
webgpu | varies | code | 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
How does WhiskerJS know resistFingerprinting is on?
It does not read the setting. It classes Firefox as firefox_rfp when every trait the setting produces holds at once: an RFP time zone (UTC, Etc/UTC or Atlantic/Reykjavik), a screen equal to the content area, no taskbar space, a pixel ratio of 1, a window at 0,0, and navigator.webdriver not true.
How are Tor Browser and Mullvad Browser told apart from plain resistFingerprinting?
They run resistFingerprinting with letterboxing and a spoofed English locale. When every resistFingerprinting trait holds and, on top, the content area sits on the letterboxing steps (width a multiple of 200, height a multiple of 100 CSS pixels) and navigator.languages is en-US or en-US,en, the class is rfp_hardened (since signalsVersion 6). Both classes exclude the same nine components.
Will Tor Browser users get the same visitorId?
Many may. Tor Browser is designed to make its users look alike, and WhiskerJS respects that: the normalised components are left out, and the rest tend to be similar across users of the same Tor Browser version. Treat a shared id here as expected.
Can a stock Firefox be wrongly classed firefox_rfp?
The test is built to avoid it, and since signalsVersion 5 it never applies when navigator.webdriver is true. A wrong class would drop nine components; a missed one only leaves normalised values in, so the test errs towards plain firefox.