Settings

The part that happens before any script runs

A page is fetched with an HTTP request, and a request carries headers whether or not you want it to. Point a browser at a server that prints what it received and this is the shape of it, before a byte of JavaScript has run:

user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)  AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36accept-language: en-CA,en;q=0.9,fr;q=0.8accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8host: example.com

Alongside those the server has the connection's remote address, which is your IP address. It is not a header but a property of the socket, and it cannot be omitted, because the answer has to go back somewhere.

On their own these are coarse. The IP address gives a network and usually a city, and is shared by everyone behind one household router. User-Agent gives the system family, the browser and its version, and most people on a current browser look like most other people on a current browser. Accept-Language is the interesting one, because it is an ordered list with weights: en-CA,en;q=0.9,fr;q=0.8 says Canadian English first, then English generally, then French. One common language is unremarkable; three in that order, with that regional variant first, is a much smaller group.

What JavaScript adds, and none of it asks permission

Everything below is read by FINGERPRINT on this site, which is a useful reference because the code that does it is there to read. There is no prompt for any of it.

The screen and the window
screen.width and height for the display; screen.availWidth and availHeight for the display minus whatever the system keeps, such as a taskbar or a dock; window.innerWidth and innerHeight for this window, which is the identifying one, because a window dragged to an arbitrary size is close to unique and follows you from page to page; window.devicePixelRatio; screen.colorDepth; and matchMedia('(color-gamut: p3)') for whether the display is wide-gamut.
The machine
navigator.hardwareConcurrency is the number of cores the browser will use. navigator.deviceMemory is memory in gigabytes, rounded to a power of two before reporting, which was the concession made when it was added. navigator.maxTouchPoints is how many fingers the screen tracks, and zero separates a desktop from everything else. navigator.platform names the system family.
Where and how you are set up
One call to Intl.DateTimeFormat().resolvedOptions() returns timeZone, locale, calendar and numberingSystem together. new Date().getTimezoneOffset() gives the offset a second way, which is how a mismatch with a claimed location gets noticed. navigator.languages is the list the header already carried. Then the media queries prefers-color-scheme, prefers-reduced-motion, prefers-contrast and forced-colors.
The fonts
A page cannot ask for the list, so it measures. FINGERPRINT puts a span off screen at left:-9999px, sets font-size:72px and fills it with mmmmmmmmmmlliWWQ@#, then records offsetWidth and offsetHeight for the generic families monospace, sans-serif and serif. For each of eighty-nine candidate names it sets font-family:"Name",monospace and the other two; if either measurement moves, that family exists and was used instead of the fallback. Seventy-two pixels is what makes the difference land in whole pixels.
The drawing
A canvas 300 by 70 pixels, never shown. It sets 15px "Arial", fills an orange rectangle at (2, 2) measuring 90 by 22, writes a short string and a padlock emoji twice at two offsets in two colours, switches globalCompositeOperation to multiply for three overlapping circles, then fills a ring with the even-odd rule. It reads the pixels back with toDataURL() and hashes them. Glyph rasterisation, subpixel placement, curve smoothing, blend arithmetic and which emoji font the system ships all vary, and all of them are in that one image.
The graphics stack
The WEBGL_debug_renderer_info extension yields UNMASKED_VENDOR_WEBGL and UNMASKED_RENDERER_WEBGL, the make and model of the graphics chip spelled out. Beside those sit the driver's own numbers as plain parameters, among them MAX_TEXTURE_SIZE, MAX_RENDERBUFFER_SIZE, MAX_VERTEX_ATTRIBS and MAX_VIEWPORT_DIMS, plus the sorted output of getSupportedExtensions(), which amounts to a fingerprint of the driver version.
The sound, which is never played
An OfflineAudioContext(1, 44100, 44100) renders one channel of one second at 44 100 Hz into memory. A triangle oscillator at 10 000 Hz runs through a DynamicsCompressor set to threshold −50, knee 40, ratio 12, attack 0, release 0.25. The absolute values of samples 4500 to 4999 are then summed and kept to eight decimal places. That compressor's arithmetic is implemented slightly differently by each browser, platform and processor, so the total differs.

Entropy, and what thirty-three bits means

The unit is information, and what a signal contributes is the surprisal of your particular answer: minus the base-two logarithm of the fraction of people who would give it. Worked through:

  • An answer half of people give is worth 1 bit.
  • An answer one person in twenty gives is worth log2(20) = 4.32 bits.
  • One in two hundred is worth 7.64 bits.
  • One in a thousand is worth 9.97 bits.

So a signal is only worth what your answer to it is worth: the commonest screen size contributes close to nothing, a rare one a great deal, and a question with many possible answers is still cheap if you give the popular answer.

Work the time zone through. Ask a current JavaScript engine for every zone name it knows, with Intl.supportedValuesOf('timeZone'), and you get 418 on the build tested here. If all 418 were equally likely, naming yours would be worth log2(418) = 8.71 bits. They are nowhere near equally likely, since a handful hold most of the world's browsers, so the real figure is lower. FINGERPRINT scores the time zone at 5 bits, which is one person in thirty-two.

Now the arithmetic everyone quotes. 2^33 is 8,589,934,592, more people than are alive, so roughly thirty-three bits of independent information is enough to pick one person out of everybody on earth. Independent is where the honest version parts company with the scary one, because these signals overlap heavily. FINGERPRINT combines its estimates by sorting them largest first and adding each discounted by 0.7 raised to the power of its position, so a set like 9, 7, 6, 6, 6, 5, 5, 5 totals 22.2 rather than a flat 49. The graphics chip, its driver limits and its extension list are three readings of one fact.

The heaviest weights in that file: the canvas drawing at 9 bits, the font list at 8 once more than thirty are found, the named graphics chip at 7 and only when the browser does not mask it, and the window size, the language list and the audio value at 6 each.

Blocking a signal can make you rarer, not commoner

Identification does not need you to be visible, only to be unusual, and several defences work by making you unusual. An operating-system high-contrast mode shows up as forced-colors: active, and FINGERPRINT scores it 3 bits for exactly the reason it is worth scoring: almost nobody has it on. The same applies to prefers-reduced-motion, and to navigator.doNotTrack being set at all, which almost nothing honours and which marks out the sort of person who sets it. A browser that refuses to return canvas pixels sits in a far smaller population than one that answers, and a browser that randomises every answer is recognisable as the browser that randomises every answer.

What works is uniformity rather than noise. The browsers that resist this seriously make every copy of themselves look identical, with the same reported window size, the same shipped fonts and the same rendering, which is why the Tor Browser asks you not to resize the window. The cheapest improvement follows from that: what is measured is innerWidth by innerHeight, not the screen, so maximising the window costs nothing and removes several bits.

A private window changes none of this. Private mode governs what is kept on the machine after the visit; your IP address, screen, fonts, time zone, core count and graphics chip are read fresh each time and were never stored, so there is nothing for it to withhold, and nothing to delete afterwards. Refusing cookies, clearing cookies and clicking through a consent banner all address a different mechanism, and are still worth doing for what they do address.

What the page on this site measures, and what it cannot

FINGERPRINT reads everything above in the tab, puts every label and value into one string and takes a SHA-256 of it. That digest is the number a site would store and compare on your next visit. It is computed in the tab, not sent anywhere, and there is nothing to clear afterwards because nothing was written.

It cannot read your IP address. No page can: the address belongs to the connection, the server sees it, and script in the page has no interface to it. So the figure that page reports is an undercount, and the header block at the top of this guide is the part it is structurally unable to show you.

It has no database of anybody else either. The per-signal bit values are published estimates of how varied each detail is across the web, not a measurement of how rare you are, because working that out would need everyone else's values and there are none here. The meter is scaled against 34 bits and turns amber at 16 and red at 24: thresholds chosen in the code, not findings about you.

Nor can it tell you whether any particular site is doing this; it shows what is readable, not who is reading. COOKIEAUDIT covers the other mechanism, sorting the cookies a site has set into advertising, analytics, functional and unknown, which is the half you can refuse and delete. DEADBOLT clears what this site has stored in a browser, for a shared or borrowed machine. Both are about storage, and neither touches the list above.

What this is, and what it is not

This is the tracking with nothing to refuse. A cookie is stored on your machine, so it can be blocked, deleted and reasoned about, which is why every site now asks. None of the signals here is stored. They are read again on each visit, combined into a number, and compared with the number from last time. There is no banner because there is nothing to consent to.

The estimates are estimates. Every bit figure quoted here comes from the weights written into FINGERPRINT, which are published measurements of how varied each detail is across the web. None of them is a measurement of how rare you personally are. Doing that honestly would need everyone else's values in a database, and the whole point of that page is that there is no database.

Reading the list is not proof anyone is using it. A site that can read forty things about your browser is not necessarily reading any of them. This explains what is available, not what is happening on the page you came from.

Nothing here defends the device. If the machine has malware on it, or an extension with permission to read every page, none of this matters. A browser extension sits inside the page and sees more than any fingerprinting script does.

Being ordinary is the defence, which is unsatisfying. The advice that follows from the arithmetic is not to lock everything down. It is to look like as many other people as possible, which mostly means using a common browser at its defaults with a common window size, and reserving the unusual settings for when you actually need them.

Questions people ask

Does browser fingerprinting still work if I block cookies?

Yes, completely. Nothing on this page uses cookies or any other storage. The signals are read from the browser on each visit and combined into a value, so there is nothing stored for a cookie setting to block or for you to clear.

Does a private or incognito window stop it?

No. Private mode changes what is kept after the visit. Your IP address, screen size, font list, time zone, processor count and graphics chip are read fresh each time and were never stored, so a private window has nothing to withhold. Most of what a fingerprinting script reads is identical in a private window.

What is canvas fingerprinting?

A page draws text and shapes onto a canvas that is never displayed and reads the pixels back. The exact pixels depend on the graphics chip, the drivers, the installed fonts and the operating system, so the result is stable for one machine and different on most others. It takes a few milliseconds and there is nothing to see.

How many bits does it take to identify one person?

About thirty-three of independent information, because two to the power of thirty-three is 8,589,934,592, which is more people than are alive. Independent is the load-bearing word: real signals overlap heavily, so the bits from a long list of readings cannot simply be added together.

Will a fingerprint-blocking extension help?

Sometimes, and it can also hurt. Refusing a signal puts you in the much smaller group that refuses it, and randomising every answer makes you recognisable as the browser that randomises. The approach that works is the opposite one, which is to look the same as everyone else using the same browser, and that has to be built into the browser rather than added on top.

Can a website see my IP address with JavaScript?

It does not need to. The IP address is a property of the connection and the server has it before any script runs. Script inside the page has no interface for reading it, which is why a page that shows you your own fingerprint cannot show you that part.

Related tools