Browser fingerprinting is a way to identify a user based on technical details of their device and browser, without using cookies. When you visit a website, a script collects basic information such as your operating system, browser version, language, time zone, screen settings, fonts, and other parameters. Together, these details form a digital “fingerprint” that allows the website to recognize you on future visits — even if you clear cookies or use incognito mode.
This fingerprint is not 100% unique, but it is accurate enough (about 85–90%) to reliably identify the same user. Because a fingerprint is made up of many parametres, changing just one or two settings usually does not help. To really avoid tracking, the entire fingerprint configuration has to be changed, not individual parameters.
What makes up a browser fingerprint?
A digital fingerprint is made up of many small parameters that together create an almost unique profile of a device. Some of this data is sent automatically by the browser with each HTTP request (passive parametres). Other data is collected on the client side using JavaScript and various Web APIs (active parametres).
Passive parameters (HTTP headers and connection)
IP address
Every request to a website contains the device’s source IP address. It can be used to determine an approximate location (country, city, ISP) via WHOIS and GeoIP databases. Although an IP address is often shared by multiple users of the same provider and may change over time, it remains a core network signal in a browser fingerprint. If WebRTC is available, a script can reveal the real IP via a STUN request, making identification even more accurate. On its own, an IP is rarely stable, but combined with other signals it significantly increases uniqueness.
User-Agent
The browser sends a User-Agent string that describes the browser type and version, operating system, architecture, and sometimes the device model:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
The User-Agent helps quickly classify a user by browser and platform. While it is easy to spoof, in real-world fingerprints it is still one of the key attributes. Some extensions also add their own headers, which can reveal installed plugins or frameworks. Uncommon combinations of operating systems and browser versions are more likely to stand out and expose the user.
Accept headers
With every request to a server, the browser automatically sends a set of HTTP headers: which content types it can handle (Accept), which languages it prefers (Accept-Language), which compression methods it supports (Accept-Encoding), as well as cache-related headers, referrer information, and other technical details. Taken together, these values can be highly informative.
For example, differences in the order of locales listed in Accept-Language or character sets in Accept-Charset can reveal specific system or regional settings. Support for Brotli compression, shown by Accept-Encoding: br, usually indicates a modern browser. The exact order in which headers are sent is also often tied to a particular browser engine—different browsers construct and transmit headers in slightly different sequences, which becomes an additional identifying signal.
All of this data falls into the category of passive signals: no scripts are required to collect it, as the browser sends it automatically. Based on these headers, a server can infer the client type (for example, from the User-Agent), preferred interface languages, supported image formats, and more. All of these details ultimately become part of the overall browser fingerprint.
Supported technologies
Some headers indicate the capabilities of the browser—for example, DNT (Do Not Track) or Upgrade-Insecure-Requests. Having DNT enabled is relatively rare and can make a profile more noticeable. These attributes are seldom used on their own, but when combined with other signals, they contribute to the overall uniqueness of the browser fingerprint.
Timezone
The most accurate way to determine a user’s timezone is through an active method using JavaScript, which directly returns the offset from UTC. Even without scripts, the server can make an approximate estimate—for example, by comparing the Date header or log timestamps with client-side data like If-Modified-Since. Differences in time can sometimes reveal the user’s timezone.
Usually, the timezone is obtained directly from the browser, providing a precise value. The offset from GMT (for example, GMT+3) is a stable characteristic: it varies between regions and generally stays the same for a single device unless the user travels or manually changes the settings.
Active parameters (JavaScript and Web APIs)
Screen resolution and color depth
These parameters are read via the window.screen object. The screen.width and screen.height properties show the available screen resolution (sometimes already adjusted for system scaling), while screen.colorDepth indicates color depth—most commonly 24 or 32 bits. These values are almost always included in a browser fingerprint because there are many possible combinations, and users’ displays vary widely.
On desktop devices, the browser window size usually does not match the actual screen size, so fingerprinting systems typically use the maximum available resolution, which reflects the real monitor settings.
Common combinations like 1920×1080×24 or 1366×768×24 already help split devices into distinct groups. Any change in setup—such as switching monitors, changing resolution, or connecting a second display—updates these values and, as a result, changes the overall fingerprint.
Language settings
Browsers have several language-related parameters: the system interface language, the preferred language for websites, and the locale, which determines date, number, and other regional formats. These values can be accessed via JavaScript, for example through navigator.language or navigator.languages. Values like "ru-RU" or "en-US" usually match what the server receives in the Accept-Language header. The locale also affects how the browser displays dates—month names, time format, and other elements—which provides an additional signal for trackers.
In terms of uniqueness, language settings add noticeable variation. A user might have a Russian system interface (ru-RU), a Ukrainian one (uk-UA), or an English interface (en-US) while still being a Russian speaker.
While common languages are shared by many users and don’t provide absolute uniqueness on their own, in combination with other characteristics they help create distinct profiles. For example, they can distinguish a Chrome on Windows with Russian locale from the same Chrome version on Windows with German settings.
Timezone (via JavaScript)
A timezone can be determined using new Date().getTimezoneOffset(), which returns the difference from UTC in minutes. For GMT+3, this value is around 180. The Intl API can also provide the timezone as a string identifier. Timezone is almost always included in a browser fingerprint because it is stable and clearly differentiates users from different regions. Even if other parameters match, different timezones result in different profiles.
Some advanced tracking systems monitor changes in this value, which can indicate that the browser is the same but the user has changed time settings. In standard fingerprinting, however, only the current offset is usually taken into account.
Platform and CPU information
Websites can obtain a range of technical details about a device through the navigator object.
- navigator.platform returns a string indicating the operating system or architecture, such as Win32, Linux x86_64, or iPhone. In the past, this parameter clearly distinguished platforms, but modern browsers often mask it for privacy reasons. When available, it becomes part of the fingerprint.
- navigator.hardwareConcurrency reports the number of logical CPU threads. On mobile devices this is usually 4–8, while on desktops it can be 4, 8, 12, 16, or more. Unusual values like 6 or 10 tend to stand out and make a device more distinctive.
- navigator.deviceMemory provides an approximate amount of RAM in gigabytes (in Chrome it is usually rounded, for example to 8). This parameter is not supported everywhere, but when present it significantly increases fingerprint variability.
- navigator.oscpu is Firefox-specific and largely duplicates OS information, so it is rarely used.
- navigator.webdriver indicates whether the browser is being controlled by automation. It does not add entropy to the fingerprint, but a true value clearly separates automated browsers from regular users, indirectly contributing to identification.
Cookies and Web Storage
Checking navigator.cookieEnabled shows whether cookies are disabled. This is quite rare and can serve as a distinguishing signal.
Plugin list
navigator.plugins is almost empty in most modern browsers, but its state (full, partial, or empty) can still be used. In the past, the plugin list provided very high uniqueness; today it is more of an auxiliary signal.
Installed extensions
Although browsers do not directly expose a list of installed extensions, many can be detected indirectly. Ad blockers reveal themselves by blocking specific requests or modifying the DOM. Some extensions leave unique objects on the window object, making them easy to identify. A combination of such signals allows a website to build an approximate profile of installed extensions. Even a single popular ad blocker or password manager can noticeably increase fingerprint uniqueness.
Installed fonts
The set of system fonts varies greatly depending on the operating system, installed software, and locale, which makes it a strong source of uniqueness. Available fonts can be detected without Flash, using CSS+JS or Canvas.
With CSS, a hidden element is assigned a font stack and its dimensions are measured—changes indicate whether a specific font is installed. A faster approach uses Canvas: text is rendered with a chosen font, and pixel differences reveal its presence. Since there are countless font combinations and rare fonts stand out immediately, this parameter is especially valuable for fingerprinting.
Canvas fingerprinting
This is one of the most well-known fingerprinting techniques, based on how a device renders graphics in the HTML5 element. A script draws text and simple shapes, then reads the result via canvas.toDataURL() and converts it into a hash—the Canvas fingerprint.
Uniqueness comes from many subtle differences: font rendering and anti-aliasing, driver versions, operating system, and graphics hardware. Even with identical code, two devices almost always produce slightly different bitmaps.
Typically, scripts draw text with various characters or add colored shapes and shadows to trigger as many rendering features as possible. The fingerprint may change after driver updates or a GPU change, but together with WebGL it remains one of the most informative signals.
WebGL fingerprinting
WebGL provides access to graphics subsystem data, which is why it is widely used for fingerprinting. Through the WEBGL_debug_renderer_info extension, a website can obtain the GPU vendor and model—essentially a direct identifier of the graphics card, which greatly increases profile uniqueness.
Even without exposing the adapter name, WebGL returns many numeric parameters that depend on drivers and hardware, such as buffer sizes, the number of supported textures, and shader limits. By collecting these values, trackers build a characteristic “capability vector” of the device.
Similar to Canvas fingerprinting, a scene can also be rendered and the output hashed to detect even subtler differences. When combined with Canvas, WebGL becomes one of the strongest fingerprinting signals, which is why privacy-focused browsers try to hide or distort this data.
AudioContext fingerprinting
This method uses the Web Audio API to generate a unique “audio fingerprint.” Different combinations of browser, operating system, and hardware process and generate sound slightly differently due to variations in audio libraries, drivers, and floating‑point calculations. These tiny differences produce a stable but distinctive result for each device.
An audio fingerprint strengthens overall identification: even if Canvas and WebGL fingerprints match, audio data often makes it possible to tell two otherwise similar profiles apart.
Media devices and sensors
Scripts can also collect information about connected hardware. Using navigator.mediaDevices.enumerateDevices(), a site can determine the number of cameras and microphones— even without device names, this already adds a fingerprinting signal.
In the past, additional APIs such as the Battery Status API were used to expose battery level and remaining time, but they were restricted due to privacy concerns.
Motion and orientation sensors provide further differences: update frequency, the presence of specific sensors, and data formats vary between devices. These signals are especially noticeable on uncommon hardware. In practice, dozens of such parameters are combined into a structured dataset and hashed (for example, with MurmurHash) to produce a short device identifier.
Is there any protection against browser fingerprinting?
Modern browsers try to reduce the amount of data that can be collected. Tor Browser makes users as similar as possible by using a unified User‑Agent, a fixed window size, a limited set of fonts, and by restricting Canvas and AudioContext. Firefox offers the privacy.resistFingerprinting mode, which also standardizes many parameters. Brave blocks trackers by default and adds noise to key APIs. There are also extensions like CanvasBlocker or Privacy Badger that disrupt fingerprint collection in specific areas. Still, full protection is not possible — browsers inevitably expose too much information.
At the same time, anti‑detect browsers are evolving. Tools like Octo Browser, MultiLogin, and Dolphin Anty allow users to modify fingerprints and create multiple isolated profiles. They are widely used in web scraping, automation, digital marketing and other spheres where it's important to avoid browser fingerprinting.
You can try Octo Browser using the promo code DEVTO, which gives 4 days of free trial.








Top comments (0)