Chrome kept the same fingerprint ID on 5 of 5 cookie-free visits. Brave got 5 different ones.
Our home-made test page gave Chrome the same ID, e08e953c, on 5 of 5 visits, and every visit started with a brand new empty profile and zero cookies. Brave, with its default settings, got 5 different IDs in 5 visits on the same Mac.
So clearing cookies changes nothing about what this page sees. We ran this ourselves; below is the method, the reason the two browsers differ, and the limits.
How we measured it
The page reads 7 things from the browser, joins them, and hashes them with SHA-256. The first 8 hex characters are the ID. Two bytes of the ID pick a two-word nickname from two lists of 32 words, so it is easy to read on screen. Chrome was "Bold Llama".
// inside an async function; c is a <canvas> we drew shapes, text and an emoji on
const hex = async s => [...new Uint8Array(await crypto.subtle.digest('SHA-256',
new TextEncoder().encode(s)))].map(b => b.toString(16).padStart(2, '0')).join('');
const canvas = await hex(c.toDataURL());
const ac = new OfflineAudioContext(1, 44100, 44100);
const o = ac.createOscillator(), comp = ac.createDynamicsCompressor();
o.type = 'triangle'; o.frequency.value = 10000;
o.connect(comp); comp.connect(ac.destination); o.start(0);
const buf = (await ac.startRendering()).getChannelData(0);
let sum = 0; for (let i = 4500; i < 5000; i++) sum += Math.abs(buf[i]);
const gl = document.createElement('canvas').getContext('webgl');
const e = gl.getExtension('WEBGL_debug_renderer_info');
const webgl = e ? gl.getParameter(e.UNMASKED_RENDERER_WEBGL) : gl.getParameter(gl.RENDERER);
const parts = {
canvas, audio: String(sum),
screen: `${screen.width}x${screen.height}x${screen.colorDepth}@${devicePixelRatio}`,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
languages: navigator.languages.join(','),
cpu_cores: String(navigator.hardwareConcurrency),
webgl
};
const id = (await hex(JSON.stringify(parts))).slice(0, 8);
A small Playwright script (run.js) opens the page with chromium.launchPersistentContext(profile, { executablePath, headless: true }). The profile is a fresh fs.mkdtempSync folder on every visit, deleted afterwards.
python3 -m http.server 60309 --bind 127.0.0.1
node run.js chrome http://127.0.0.1:60309/fp.html 6 # 1 warm-up + 5 measured
node run.js brave http://127.0.0.1:60309/fp.html 6
KEEP=1 node run.js brave http://127.0.0.1:60309/fp.html 6 # one kept profile, restart + one reload per visit
Machine: Apple M1 Pro, 16 GB, macOS 26.6.2. Chrome 155.0.8059.40, Brave 155.1.97.56, Playwright 1.64.0, Node v26.8.1. Both browsers ran headless.
The 60-second version:
{% youtube HCVKV-BFftM %}
The numbers
| Run | Cookies and saved data per visit | Different IDs in 5 visits | Names |
|---|---|---|---|
| Chrome, new empty profile each visit | 0 | 1 | Bold Llama, 5 times |
| Brave, new empty profile each visit | 0 | 5 | Zippy Llama, Mighty Mole, Zippy Wombat, Chilly Ferret, Fancy Lobster |
| Brave, same profile, browser restarted each visit | 0 | 5 | Mellow Panda, Fuzzy Owl, Jolly Owl, Shiny Yak, Cranky Pigeon |
In Chrome all 7 parts had one value across the 5 visits. In Brave only 3 parts moved: the canvas hash (5 different values), the audio sum (5), and the CPU core count, which came back as 7, 4, 8, 7, 7. The other 4 stayed the same.
We also opened brave://settings/shields in a new empty profile. "Block fingerprinting" was already on.
Why the two browsers differ
None of the 7 parts is stored in the profile. They describe the hardware and the system, so a new profile reads them the same way. A cookie is something the site puts on your disk, a fingerprint is something the site asks your machine. Mozilla's Tom Ritter wrote in the Firefox fingerprinting post (10 Nov 2025) that the technique "lets websites identify you even when cookies are blocked or you're in private browsing".
Brave does not block the reads. Per the Brave fingerprinting wiki, it adds small random changes to some API values, from "a seed that changes per session, per site (eTLD+1) and per storage area". A hash over many parts breaks as soon as one part moves, and here three of them moved.
There is also a consent angle. The UK regulator ICO noted on 19 Dec 2024 that from 16 February 2025 Google no longer prohibits fingerprinting in its advertising products, and that Google itself had earlier said users "cannot easily consent to it as they would cookies".
Limits you should know
- One machine, one test, 5 measured visits per run.
- Both browsers ran headless through Playwright with default launch flags. Chrome reported the 1080x1920 viewport as its screen and Brave reported 3840x2160, neither being the real display.
- The page was served from 127.0.0.1. It is a 7-part toy, not an ad tracker. Real trackers can use more signals, including your IP address, which Brave does not hide.
- We showed the Chrome ID is stable. We did not measure how unique it is: two identical Macs could get the same one.
- In Brave the ID changed on every browser start. A reload inside one session kept the same ID, 5 of 5 times, which matches the per-session seed. It is not a new name on every page load.
- Firefox with Strict protection was not tested.
- Our first full run was thrown away: the nickname list had the word "Brave" in it, so Chrome was named "Brave Llama". We changed it to "Bold" and ran everything again; the pattern was the same.
Next we want to run the page in a normal visible window, and on a second identical Mac to see if the IDs collide. If you run it, which of the 7 parts changes on your setup?
1 reaction · 6 comments
Mentions
Just submitted a PR to add missing --tor flag to manpage on brave/brave-core cc @brave.com brave-core#41191 #documentation #opensource #tor
Floating bookmarks bar for Brave and Helium Browsers Hello everyone! I've been experimenting with a new feature for Brave and Helium: an auto-hiding floating bookmarks bar. The idea is simple, instead of having the bookmarks bar take up space all the time, it stays hidden and appears when you hover near the top of the browser. I've got it working pretty well so far (including theming and vertical tabs), and I already submitting a PR to Brave's GitHub repo and a feature request to Helium's repo. Brave: brave-core#41002 Helium: helium#2814 Any feedback or suggestions are welcome! Edit: If none of the above are willing to implement it I am just gonna make an extensions for this even though it will be a lot more limited.
@BrendanEich @AndreaAmati9 @brave @_brianclifton @petemill Hmm we already remove ref url parameters from Amazon links. github.com/brave/adblock-lists/blob/f7e9289c273c7…
brave search mcp server the docs told ai agents image search had an offset param. it didn't so agents kept sending a param that did nothing. the whole fix was a docs change brave-search-mcp-server#348
@Seitaa1024 Braveでいいか! ありがとう! github.com/brave/brave-browser/releases
现在有了 AI,是不是自己也可以做个适合自己习惯的浏览器? 我看猫眼浏览器是根据 brave/brave-core 改出来的,那是不是自己也可以让 AI 来改一个?难度会很大吗?
Brave Software github.com/brave
Requesting notification bar or button for website and RSS updates I would like Brave to show a dismissible notification bar at the top of the window when a followed website or RSS feed has new content. Problem: New posts on sites or RSS feeds go unnoticed unless I check manually. I have to revisit each site or feed to find out whether anything new was published. Proposed solution: - The bar appears when a subscribed site or RSS feed has new items. - It offers options to open the newest item, view the feed, or dismiss it. - Users subscribe from the address bar or from a page's feed link. - Dismissing the bar does not mark feed items as read. - Users can turn these notifications on or off in settings. - Rules for which updates trigger the bar and what actions it offers are defined in a small domain-specific language (DSL), so users and extensions can customize them. - Brave ships preset rules (for example, "any new item" or "new items matching a keyword") that users can enable without writing any code. Use case: I follow a news site's RSS feed and want to know when it publishes a new article without checking manually. I'd like to enable a preset that only alerts me about articles matching a topic I care about. Alternatives considered: I use feed readers or extensions. None of these alerts me inside the browser when something new arrives. Additional context: Web push notifications cover some of this, but they depend on the site supporting push and on the user granting permission. An RSS-based option would work with sites that don't support push.
@DevBredda @BrendanEich @brave @ParedesLJavi We are also going to implement a full screen experience for web sites using PWA in Q4 this year. brave-browser#59791. Basically it will look like Brave Search webpage is in a dedicated app, but really in a browser tab without any other tabs and so on.
Chrome kept the same fingerprint ID on 5 of 5 cookie-free visits. Brave got 5 different ones. Our home-made test page gave Chrome the same ID, e08e953c, on 5 of 5 visits, and every visit started with a brand new empty profile and zero cookies. Brave, with its default settings, got 5 different IDs in 5 visits on the same Mac. So clearing cookies changes nothing about what this page sees. We ran this ourselves; below is the method, the reason the two browsers differ, and the limits. How we measured it The page reads 7 things from the browser, joins them, and hashes them with SHA-256. The first 8 hex characters are the ID. Two bytes of the ID pick a two-word nickname from two lists of 32 words, so it is easy to read on screen. Chrome was "Bold Llama". // inside an async function; c is a <canvas> we drew shapes, text and an emoji on const hex = async s => [...new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s)))].map(b => b.toString(16).padStart(2, '0')).join(''); const canvas = await hex(c.toDataURL()); const ac = new OfflineAudioContext(1, 44100, 44100); const o = ac.createOscillator(), comp = ac.createDynamicsCompressor(); o.type = 'triangle'; o.frequency.value = 10000; o.connect(comp); comp.connect(ac.destination); o.start(0); const buf = (await ac.startRendering()).getChannelData(0); let sum = 0; for (let i = 4500; i < 5000; i++) sum += Math.abs(buf[i]); const gl = document.createElement('canvas').getContext('webgl'); const e = gl.getExtension('WEBGL_debug_renderer_info'); const webgl = e ? gl.getParameter(e.UNMASKED_RENDERER_WEBGL) : gl.getParameter(gl.RENDERER); const parts = { canvas, audio: String(sum), screen: `${screen.width}x${screen.height}x${screen.colorDepth}@${devicePixelRatio}`, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, languages: navigator.languages.join(','), cpu_cores: String(navigator.hardwareConcurrency), webgl }; const id = (await hex(JSON.stringify(parts))).slice(0, 8); A small Playwright script (run.js) opens the page with chromium.launchPersistentContext(profile, { executablePath, headless: true }). The profile is a fresh fs.mkdtempSync folder on every visit, deleted afterwards. python3 -m http.server 60309 --bind 127.0.0.1 node run.js chrome http://127.0.0.1:60309/fp.html 6 # 1 warm-up + 5 measured node run.js brave http://127.0.0.1:60309/fp.html 6 KEEP=1 node run.js brave http://127.0.0.1:60309/fp.html 6 # one kept profile, restart + one reload per visit Machine: Apple M1 Pro, 16 GB, macOS 26.6.2. Chrome 155.0.8059.40, Brave 155.1.97.56, Playwright 1.64.0, Node v26.8.1. Both browsers ran headless. The 60-second version: {% youtube HCVKV-BFftM %} The numbers | Run | Cookies and saved data per visit | Different IDs in 5 visits | Names | |---|---|---|---| | Chrome, new empty profile each visit | 0 | 1 | Bold Llama, 5 times | | Brave, new empty profile each visit | 0 | 5 | Zippy Llama, Mighty Mole, Zippy Wombat, Chilly Ferret, Fancy Lobster | | Brave, same profile, browser restarted each visit | 0 | 5 | Mellow Panda, Fuzzy Owl, Jolly Owl, Shiny Yak, Cranky Pigeon | In Chrome all 7 parts had one value across the 5 visits. In Brave only 3 parts moved: the canvas hash (5 different values), the audio sum (5), and the CPU core count, which came back as 7, 4, 8, 7, 7. The other 4 stayed the same. We also opened brave://settings/shields in a new empty profile. "Block fingerprinting" was already on. Why the two browsers differ None of the 7 parts is stored in the profile. They describe the hardware and the system, so a new profile reads them the same way. A cookie is something the site puts on your disk, a fingerprint is something the site asks your machine. Mozilla's Tom Ritter wrote in the Firefox fingerprinting post (10 Nov 2025) that the technique "lets websites identify you even when cookies are blocked or you're in private browsing". Brave does not block the reads. Per the Brave fingerprinting wiki, it adds small random changes to some API values, from "a seed that changes per session, per site (eTLD+1) and per storage area". A hash over many parts breaks as soon as one part moves, and here three of them moved. There is also a consent angle. The UK regulator ICO noted on 19 Dec 2024 that from 16 February 2025 Google no longer prohibits fingerprinting in its advertising products, and that Google itself had earlier said users "cannot easily consent to it as they would cookies". Limits you should know - One machine, one test, 5 measured visits per run. - Both browsers ran headless through Playwright with default launch flags. Chrome reported the 1080x1920 viewport as its screen and Brave reported 3840x2160, neither being the real display. - The page was served from 127.0.0.1. It is a 7-part toy, not an ad tracker. Real trackers can use more signals, including your IP address, which Brave does not hide. - We showed the Chrome ID is stable. We did not measure how unique it is: two identical Macs could get the same one. - In Brave the ID changed on every browser start. A reload inside one session kept the same ID, 5 of 5 times, which matches the per-session seed. It is not a new name on every page load. - Firefox with Strict protection was not tested. - Our first full run was thrown away: the nickname list had the word "Brave" in it, so Chrome was named "Brave Llama". We changed it to "Bold" and ran everything again; the pattern was the same. Next we want to run the page in a normal visible window, and on a second identical Mac to see if the IDs collide. If you run it, which of the 7 parts changes on your setup?