Browsers · WhiskerJS 0.1.0

Brave

Brave randomises some signals per site and per session; WhiskerJS recognises Brave and does not collect those twelve components at all.

In plain words

Brave is built on the same engine as Chrome, but it deliberately blurs some measurements: it adds small random changes that differ per website and per browsing session, which Brave calls “farbling”. Reading those measurements would only make the id change for no reason, so WhiskerJS recognises Brave and skips them. Since Brave 1.93 every Brave user also reports the same generic graphics card details, which say nothing about the device, so those are skipped too: twelve components in all. Everything else is read as in Chrome.

At a glance

  • Browser class: brave (navigator.brave.isBrave is a function).
  • Excluded components: 12, with ruleId brave_farbling (11 of them in the visitorId; speech_voices is outside both ids). The whole gpu group is excluded, so its structuredId part is the same for every Brave run.
  • Chromium APIs: present, as in Chrome.
  • Lab sample: none.

How Brave is recognised

The first step of the class test asks whether navigator.brave exists and has an isBrave function. Nothing is called or awaited; the presence of the function is enough. This comes first because Brave’s user agent string looks like Chrome’s, so without it Brave would be classed chromium and the farbled values would be read.

What works

  • Chromium-only components: ua_client_hints and ua_versions report the brands and versions Brave gives; heap_limit from performance.memory. device_memory and keyboard_layout are Chromium APIs too, but Brave’s protections may change or turn off such values, so treat them as variable.
  • font_preferences, Math, codecs, locale, screen, color depth, CPU architecture, touch support, storage presence, permission states and the display preference queries.
  • content_blockers: Brave blocks ads by default, so its cosmetic filtering may hide some of the eight bait elements; the component lists which. It is outside both ids, because blockers are switched per site.

What is unavailable or blocked

  • audio_latency is unavailable / skipped on desktop and read on Android (Android user agent).
  • apple_pay and private_click report the plain value none.
  • canvas_readback and noise_profile are not excluded; with farbling they typically report altered and seeded for the APIs Brave randomises, which is itself a useful diagnostic.

What WhiskerJS excludes and why

Component Why it is left out
audio audio output is farbled
canvas canvas readback is farbled
fonts Brave randomises the visible font set
fonts_canvas the same font set, probed through the canvas (added to the table at signalsVersion 3)
hardware_concurrency the CPU thread count is farbled
plugins the plugin list is farbled
speech_voices the voice list is farbled (added at signalsVersion 6)
webgl_image WebGL readback is farbled
webgl_params since Brave 1.93 every user reports generic WebGL parameters (added at signalsVersion 6)
webgl_renderer since Brave 1.93 every user reports one generic renderer string (added at signalsVersion 6)
webgl_vendor since Brave 1.93 every user reports one generic vendor string (added at signalsVersion 6)
webgpu since Brave 1.93 the WebGPU adapter info has its fields emptied (added at signalsVersion 6)

All twelve report excluded with ruleId brave_farbling. In the visitorId and structuredId they count as “missing”, the same in every run. The rows reflect Brave’s public documentation of farbling, as noted in src/exclusions.ts. languages stays in: Brave shortens the list but does not randomise it in script. If Brave changes what it farbles, the table changes and signalsVersion goes up.

Integrity flags to expect

  • engine_mismatch expects V8 behaviour for the brave class (a 33-character eval source, productSub 20030107), which Brave has.
  • native_tampering, prototype_lie and navigator_own_property are designed to spot scripts that override functions. Whether Brave’s built-in protections trip any of them has not been measured; treat these flags on Brave traffic with the same care as for privacy extensions.
  • automation_webdriver under automation, as in Chrome.
  • media_query_mismatch does not run for the brave class, and with the WebGL renderer excluded neither software_renderer nor vm_renderer can fire.
  • Brave’s noise is never a flag: it shows in noise_profile and in the excluded components.

Early lab observations

There is no lab data for Brave yet. The early, small sample at signalsVersion 1 covered Mac Chrome, Mac Safari, iPhone Chrome and iPhone Safari only, and none of those had exclusions.

Testing it yourself

Open the live demo in Brave: browser_class should say brave and the twelve components above show excluded. Change the Shields setting for the demo site and run again to see content_blockers and canvas_readback move. The lab mode copies one line per run. Nothing is sent anywhere.

Support table for Brave

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.

ComponentStatusBasisNote
apple_paynonecodeNo ApplePaySession: reports the plain value none.
audioexcludedcodeExclusion table: brave_farbling (Brave adds per-site, per-session noise).
audio_latencyvariescodeRead on Android (Android user agent), skipped on desktop.
browser_classokcodeClass brave (navigator.brave.isBrave is a function).
canvasexcludedcodeExclusion table: brave_farbling (Brave adds per-site, per-session noise).
canvas_readbackvariescodeNot excluded; Brave's canvas farbling can make it report altered.
color_depthokcode
color_gamutokcode
content_blockersokcodeBrave's built-in blocking may hide some baits; reports the hidden bait names or none.
cpu_architectureokcode
device_memoryvariescodeChromium API; Brave's fingerprinting protections may change the value. From Chromium 146 the value carries the tag ;c146.
dynamic_rangeokcode
font_preferencesokcode
fontsexcludedcodeExclusion table: brave_farbling (Brave adds per-site, per-session noise).
fonts_canvasexcludedcodeExclusion table: brave_farbling (Brave adds per-site, per-session noise).
forced_colorsokcode
hardware_concurrencyexcludedcodeExclusion table: brave_farbling (Brave adds per-site, per-session noise).
heap_limitokcode
intl_localeokcode
keyboard_layoutvariescodeChromium API; Brave may turn it off.
languagesokcode
mathokcode
media_codecsokcode
noise_profileokcodeTypically seeded for the APIs Brave farbles.
pdf_viewerokcode
permissionsokcode
pixel_ratiookcode
platformokcode
pluginsexcludedcodeExclusion table: brave_farbling (Brave adds per-site, per-session noise).
prefers_contrastokcode
private_clicknonecodeNo attributionSourceId on anchors: reports the plain value none.
reduced_motionokcode
screen_frameokcode
screen_resolutionokcode
speech_voicesexcludedcodeExclusion table: brave_farbling (Brave farbles the voice list).
storageokcode
time_zoneokcode
touch_supportokcode
ua_client_hintsokcodeChromium API; the brand list is whatever Brave reports.
ua_versionsokcodeChromium API; not in either id.
vendorokcode
vendor_flavorsokcode
webgl_imageexcludedcodeExclusion table: brave_farbling (Brave adds per-site, per-session noise).
webgl_paramsexcludedcodeExclusion table: brave_farbling (since Brave 1.93 every user reports generic values).
webgl_rendererexcludedcodeExclusion table: brave_farbling (since Brave 1.93 every user reports generic values).
webgl_vendorexcludedcodeExclusion table: brave_farbling (since Brave 1.93 every user reports generic values).
webgpuexcludedcodeExclusion table: brave_farbling (since Brave 1.93 the adapter fields are emptied).

Questions and answers

Does WhiskerJS try to get around Brave's farbling?

No. Components Brave randomises on purpose are not collected; they report excluded with ruleId brave_farbling. Working around a privacy feature is out of scope for the library.

How does WhiskerJS recognise Brave?

By navigator.brave.isBrave being a function. Brave's user agent looks like Chrome's, so the user agent alone would not tell it apart.

Is the id stable in Brave?

The excluded components count as missing in every run, so they do not change the id. Other components can still change, and Brave may alter more values than the twelve in the table; the known-answer probes then turn canvas, webgl_image or audio noisy instead of letting them change the id. No stability figure has been measured.