How Browser Fingerprinting Works: a Full Breakdown of Parameters

How Browser Fingerprinting Works: a Full Breakdown of Parameters

Browser fingerprinting is a method of identifying a user by the combination of characteristics and parameters of their browser and device without using cookies or other stored data. When you visit a site, a special script collects information about your environment (operating system, browser version, language settings, timezone, screen resolution, list of fonts, etc.) and creates a unique identifier, the browser fingerprint. This identifier persists longer than ordinary cookies and helps sites recognize your browser on repeat visits, even if the user clears cookies or opens the site in incognito mode. Due to that, sites can track a user’s actions across different sessions and resources, linking them to one profile.

A browser fingerprint is similar to a human fingerprint, but uniqueness here is not exactly 100% and is roughly 85–90%, which is enough for sites to identify a profile. It’s important to understand that a fingerprint is a set of parameters. Changing one or two of them does not yield a significant spoofing effect: uniqueness drops by only fractions of a percent, so it’s important to work on the fingerprint comprehensively.

Browser fingerprinting

Let’s break down which parameters make up a browser fingerprint, how each parameter is collected, and how much it affects uniqueness.

Browser fingerprinting is a method of identifying a user by the combination of characteristics and parameters of their browser and device without using cookies or other stored data. When you visit a site, a special script collects information about your environment (operating system, browser version, language settings, timezone, screen resolution, list of fonts, etc.) and creates a unique identifier, the browser fingerprint. This identifier persists longer than ordinary cookies and helps sites recognize your browser on repeat visits, even if the user clears cookies or opens the site in incognito mode. Due to that, sites can track a user’s actions across different sessions and resources, linking them to one profile.

A browser fingerprint is similar to a human fingerprint, but uniqueness here is not exactly 100% and is roughly 85–90%, which is enough for sites to identify a profile. It’s important to understand that a fingerprint is a set of parameters. Changing one or two of them does not yield a significant spoofing effect: uniqueness drops by only fractions of a percent, so it’s important to work on the fingerprint comprehensively.

Browser fingerprinting

Let’s break down which parameters make up a browser fingerprint, how each parameter is collected, and how much it affects uniqueness.

Fingerprinting vs. other tracking methods

Browser fingerprinting technology emerged as a response to the limitations of classic user-tracking methods.

HTTP cookies

The best-known way to recognize users is to store a unique identifier in the browser (in a cookie file) and read it on every visit. The drawback is that the user can clear cookies, and the site loses the previously issued ID. Also, in incognito mode or when third-party cookies are blocked by the browser, this method doesn’t work. Modern browsers and extensions offer more tools to block or auto-delete cookies, reducing the effectiveness of this approach. Fingerprinting, on the other hand, does not require storing data on the client side, so it works even with cookies disabled and in incognito mode; it’s enough that the browser provides the necessary system information.

HTTP cookies

LocalStorage, SessionStorage, and other web storages

Like cookies, these technologies store data locally in the browser. Scripts can read them on repeat visits. However, the user can manually clear them, and storage is isolated by domain; moreover, SessionStorage is only available for one tab/session only.

There is also Evercookie, a technique that tries to create “undeletable” cookies by duplicating the identifier across all available storages (HTTP cookie, Flash LSO, Silverlight Isolated Storage, IndexedDB, etc.), and by using cache and other tricks. But even Evercookie isn’t omnipotent: for example, it’s useless in incognito mode, where data is not saved to the hard drive. Fingerprinting does not save anything on the device; it collects information anew on every visit, so it’s harder to stop with standard clearing methods.

LocalStorage, SessionStorage, and other web storages

ETag tracking

Not the most common but a working method of using HTTP cache for user identification. On the first request, the server returns a resource (for example, a single pixel) with a unique ETag header. The browser stores it in the cache. On a repeat request to the same URL, the browser automatically sends If-None-Match with the previously received ETag. Thus, the server can detect the same visitor by matching the ETag even if cookies have been deleted. This is a passive tracking method that doesn’t require JavaScript — the identifier is stored in the caching mechanism. ETag tracking is hard to detect, survives cookie clearing (you’d have to clear the cache), and works even without JS. However, it too can be countered if needed (disable cache, use intermediary proxies that clear ETag headers).

ETag tracking

CNAME cloaking

A technique that disguises a third-party tracker as a first-party domain using a DNS CNAME record. For example, instead of loading from tracker.thirdparty.com, the script loads from a subdomain like tracker.​mysite.​com, which points to the tracker’s server at the DNS level via CNAME. The browser treats such a request as coming from the primary resource, so ad/tracker blockers don’t detect the third-party domain — the tracker’s cookies are considered same-site. CNAME cloaking can even bypass browser protections like Safari’s Intelligent Tracking Prevention and the like. In the context of fingerprinting, this method matters because it allows a third-party script to collect a fingerprint and set cookies as if it were the site itself. In essence, CNAME cloaking hides the third party, while fingerprinting works without stored identifiers. Together they can strengthen tracking (the tracker masquerades as the website and collects maximum user data, including the fingerprint, without being blocked).

Fingerprinting

Browser fingerprinting doesn’t replace the methods described above; it’s often used together with them. For example, on the first visit a script may collect the fingerprint and try to set cookies. If cookies are later cleared, a repeat recognition is possible by matching the fingerprint. Also, the fingerprint can complement other methods: for example, supercookies stored via favicon cache can keep a unique ID, and the tracker may compare browser parameters for confirmation. Taken together, these techniques create a multi-layered system for tracking users.

Parameters that make up the browser fingerprint

A fingerprint is formed from dozens of small attributes that together produce a unique combination. Some of them are sent automatically with every HTTP request (passive signals), while others are collected on the client side via JavaScript and Web APIs (active signals).

Passive parameters (HTTP headers and connection)

IP address

The address of your device on the network, determined from each incoming request. It can indicate geolocation (country/city via WHOIS or GeoIP) and affiliation with an organization/ISP. Although an IP address is often not unique (many users may be behind a public address of a single ISP) and can change dynamically, it is included in the fingerprint as a basic network identifier. Moreover, if WebRTC is available, a script can perform a STUN request and obtain your real IP address. An IP address by itself is not permanent, but combined with other signals it increases the probability of uniqueness.

IP address

User Agent

The user agent string sent in the User-Agent  header by every browser. It contains information about the browser, its version, engine, OS version, architecture, and sometimes device model, e.g. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36. Analyzing the user agent lets you distinguish, roughly, Chrome on Windows from Safari on iOS, etc. — in other words, narrow the identification down to the browser and platform.

User agent uniqueness: although the user agent is formed from a limited set of versions, the combination of OS and browser is often rare. For example, an older browser version on a specific OS will present a unique user agent. Non-standard headers added by extensions may also appear in the fingerprint; from them sites can infer installed plugins or frameworks. Overall, however, the user agent is easy to spoof, so you shouldn’t rely on it alone; it is just one aspect of the fingerprint.

User Agent

Accept headers and other protocol characteristics

With each request the browser sends a set of headers: supported formats (Accept, Accept-Language, Accept-Encoding), referrer, caching flags, etc. The combination of these headers is also quite informative. For example, the order and contents of Accept-Language and Accept-Charset fields can differ between OS locales. Presence of Accept-Encoding: br indicates Brotli support and indirectly a relatively modern browser. The specific order in which a browser enumerates headers can serve as a browser engine signature. 

HTTP-level signals are considered passive, as they are provided automatically by the browser. Without JS, the server can learn device type (via User-Agent), preferred languages (Accept-Language), the content types the client supports (e.g., WebP support in Accept reveals a Blink engine), and so on. All these small details feed into the fingerprint model.

Accept headers and other protocol characteristics

Timezone

Although the user’s timezone can be determined actively (via JS), it can be approximated from headers as well. For example, the Date header in HTTP or the time in server logs can be compared with the request time on the client side (for instance, if If-Modified-Since is visible). More commonly the Timezone is obtained on the client side. However, the time offset (GMT±X) is part of the fingerprint because it differs across regions and remains stable for a user over time (unless the user travels or changes the setting manually).

Timezone

Supported Technologies

Some headers or connection traits may indicate browser capabilities. For example, DNT (Do-Not-Track) is present if the user enabled “Do Not Track”; DNT: 1 then becomes part of the fingerprint (paradoxically, this flag can make you stand out because few people enable it). Another example: Upgrade-Insecure-Requests: 1 is sent by most modern browsers on first transition to HTTPS; its absence might identify an unusual client. These subtle nuances rarely appear as separate fingerprint fields but can be considered collectively.

Active parameters (JavaScript and Web API)

Screen resolution and color depth

Available via window.screen objects. Properties screen.width/height return current screen resolution (sometimes accounting for display scaling), and screen.colorDepth returns color depth (usually 24 or 32 bits). These parameters are frequently included in the fingerprint because they vary widely: everyone’s screen size differs. On desktops the browser window rarely matches maximum resolution, but a fingerprint usually takes the maximum available resolution of the user, which reflects their display size. For example, 1920×1080×24 (Full HD, 24-bit color) is one configuration, 1366×768×24 is another, etc. Each resolution combined with color depth can narrow down the device group. If the user changes monitor resolution or connects a new monitor, the fingerprint will change.

Language settings

A browser exposes several related settings: interface/OS language, preferred page language(s), and locale formats for dates/numbers. JS can get navigator.language (or navigator.languages for a list) — values like “ru-RU” or “en-US.” This usually matches what the server receives in Accept-Language. Locale affects formatting functions like Date.toString() (month names in Russian or English, etc.), which can also be used for fingerprinting.

Effect on uniqueness: combinations of languages and regions are quite variable. For example, a Russian-speaking user might have locale ru-RU, or uk-UA (if their OS is Ukrainian), or even en-US (if the interface is English). These nuances add a few bits of entropy. The number of unique language-combination permutations grows every year, but language alone is not extra unique: many people use popular locales. However, combined with other parameters, language helps distinguish, say, Chrome/Windows in Russian from Chrome/Windows in German, creating two different profiles.

Language settings

Timezone (via JS)

A more accurate way to determine the timezone is to call a new Date().getTimezoneOffset() using JS. This returns the local time offset from UTC in minutes. For example, GMT+3 yields 180 minutes. You can also get the timezone name using Intl API. This parameter is almost always included in the fingerprint because it is stable for a device and varies geographically. Two users with identical parameters but different timezones already produce different fingerprints.

Note: some advanced fingerprinters track timezone changes: this can indicate that the same browser changed context (for instance, if the user traveled or changed clock settings). However, the current offset value is normally used for a simple fingerprint.

Timezone (via JS)

Information about the platform and CPU

The navigator object provides a number of properties related to the device platform:

  • navigator.platform — a string indicating the OS/architecture, for example Win32, Linux x86_64, iPhone, etc. This used to be a fairly telling parameter (distinguishing, for example, 32-bit Windows from 64-bit), but modern browsers may return truncated or unified values for privacy reasons. If the parameter is available, it is included in the fingerprint.

  • navigator.hardwareConcurrency — the number of logical CPU threads (cores) on the device. For example, 8 (which may correspond to 4 physical cores with Hyper-Threading). This adds extra variability: mobile devices often have 4 or 8, desktops — 4, 8, 12, 16 and more cores. Not every browser reports an exact value, but under normal conditions this parameter is collected. An unusual thread count (e.g., 6 or 10) can immediately single out a device.

  • navigator.deviceMemory — approximate RAM size in gigabytes (integer). Chrome rounds to 0.25 (a quarter) increments. For example, 8 GB gives deviceMemory = 8. This signal is not supported in all browsers. Where present, it is included: RAM size is rarely a round number, so variability reduces overlaps.

  • navigator.oscpu — a string with the operating system (Firefox-only API). In modern Firefox on Windows it returns something like Windows NT 10.0; Win64; x64. This parameter is rarely used because it duplicates information from the User-Agent.

  • navigator.webdriver — a boolean indicating whether the browser is driven by automation (WebDriver). If true, the site knows it’s dealing with a bot and may change behavior or factor this into the fingerprint. For fingerprinting this is less a “uniqueness” parameter and more a way to detect automation. Nevertheless, navigator.webdriver=true clearly singles out the client (regular users have false), so indirectly it is part of the fingerprint.

Cookies/Storage enabled state

Scripts can check whether cookies are enabled in the browser (navigator.cookieEnabled). If the user has disabled them, this distinguishes them from the majority of other users (almost everyone keeps cookies enabled) and adds uniqueness.

List of browser plugins

navigator.plugins can return a list of installed NPAPI plugins: Acrobat Reader, Flash, Silverlight, etc., including their versions (navigator.plugins[i].name/version), although NPAPI plugins have largely disappeared (Flash and Java are disabled or removed from modern browsers). In Chrome navigator.plugins now contains only the built-in PDF Viewer; in Firefox, likewise, there is nothing extra. Still, the API exists and some browsers may still return something. The fingerprint may include plugin names and their count. An empty list is also a signal (for example, Firefox in Tor-mode has it empty, while a regular Firefox might include a built-in OpenH264 plugin). Overall the role of plugins as a factor is declining; extensions are gaining importance instead.

List of browser plugins

Installed extensions

Ideally websites shouldn’t know which extensions a user has, but in practice some extensions can be detected indirectly. AdBlock or Adblock Plus can be detected by blocked requests or specific DOM elements they introduce. A site may try to load a known URL filtered by AdBlock — if it doesn’t load, a blocker is likely present. 

Another example: extensions can add special objects to window (e.g., React Developer Tools adds __REACT_DEVTOOLS_GLOBAL_HOOK__), and a script finding such an object recognizes the extension. Dozens of small checks can build a “snapshot” of the browser environment. The approximate number of extensions can sometimes be inferred from page response time. Each installed extension can slow page processing. In any case, presence of popular blockers, password managers, or niche extensions is partially detectable and increases profile uniqueness.

List of installed fonts

One of the most variable parameters. The set of system fonts depends on the OS, installed applications (Microsoft Office adds fonts, Adobe adds its own, etc.), and system language (Chinese fonts usually aren’t present for European users). How can a web page detect which fonts you have? Historically Flash (EnumerateFonts) was used, but without it there are purely browser-side methods:

  • Via CSS+JS: a hidden element is created with a font-family fallback list. If the first font isn’t installed, the text renders in the next font and the element’s width/height changes. JS can measure element dimensions to infer which font applied. Iterating hundreds of popular fonts reveals which are present. This method is time-consuming, so the following method is often used.

  • Via Canvas: drawing text in a specific font on a canvas and comparing the pixel raster lets you determine whether the font is installed. This is essentially a case of Canvas fingerprinting (see below).

List of installed fonts

The number of possible font-set combinations is huge, because few people have identical font lists, especially across different OS versions. A rare font (e.g., design-specific fonts) immediately makes the fingerprint unique, making font data incredibly useful for fingerprinting. Font collection is not instantaneous, so some scripts cache the fingerprint result.

Canvas Fingerprinting

This is a well-known fingerprinting method using the HTML5 <canvas> element to obtain unique rendering characteristics. The browser draws content (usually text with a specific font and colors, sometimes geometric shapes) on a virtual canvas, then the script calls canvas.toDataURL(), getting a bitmap of the rendered content. The image is represented as a base64 string, hashed to produce a Canvas fingerprint.

Why is it unique? Tiny differences in the system — font smoothing algorithms, GPU driver versions, platform (Linux vs Windows) — produce subtle variations in the final image. Typically text with diverse characters (letters of different shapes, special symbols) is drawn to maximize smoothing effects. Scripts may also draw colored rectangles, apply transforms or shadows to exercise graphics functions. Different devices yield different images from the same drawing code. A Canvas fingerprint can change after GPU driver updates or switching from integrated to discrete graphics. Combined with WebGL, however, it becomes extremely valuable.

Canvas Fingerprinting

WebGL Fingerprinting

WebGL is an API for rendering 3D graphics in the browser (essentially providing access to OpenGL/ES capabilities). It supplies two key types of data for fingerprinting:

Direct GPU identifiers

The WEBGL_debug_renderer_info extension allows a script to retrieve the UNMASKED_VENDOR_WEBGL and UNMASKED_RENDERER_WEBGL strings from the WebGL context — these typically list the manufacturer and model of the GPU (e.g., Intel Inc., Intel Iris Plus Graphics 640, or NVIDIA Corporation, GeForce GTX 1070). These values effectively reveal the user’s video card model. Most browsers allow this in standard mode (except Tor). The GPU model adds significant entropy: even if two users have the same operating system and browser, one with Intel HD Graphics and the other with an RTX 3080 will have distinct fingerprints.

WebGL constants and capabilities

Even without the direct GPU name, the WebGL context holds many parameters that depend on the driver and hardware: maximum texture units, geometry size limits, shadow and anti-aliasing support, and other numeric constants. A script can sequentially call gl.getParameter(...) for various constants and collect the results. For example, MAX_VERTEX_UNIFORM_VECTORS might be 4,096 on one card and 1,024 on another, etc. The result is a long vector of numbers, a sort of profile of the graphics subsystem. Such a profile is often unique to a device and can differ even between similar GPU models.

WebGL constants and capabilities

Additionally, WebGL can be used like Canvas: that is, by rendering a complex 3D scene and obtaining its raster image. This approach can reveal even subtler differences (for example, in shader implementations). In practice, libraries such as FingerprintJS usually limit themselves to reading UNMASKED_RENDERER (since it’s simpler and more reliable), but some scripts also hash a rendered 3D shape for greater stability. WebGL data greatly increase fingerprint uniqueness, especially on mobile devices: for instance, it used to be difficult to distinguish between iPhones (all had identical Canvas output due to identical GPUs), but now the GPU version can reveal the iPhone model if WebGL is enabled. Combined with Canvas, WebGL provides a powerful source of entropy. That’s why browsers in privacy-oriented modes try to hide or spoof this data.

AudioContext Fingerprinting

Another sophisticated fingerprinting method uses the Web Audio API to derive a unique audio fingerprint of the device. It’s based on the fact that audio generation and processing vary slightly across systems (due to library implementations, SIMD instruction usage, floating-point inaccuracies, etc.). In practice, AudioContext fingerprint values differ noticeably between browsers; each “browser + OS + hardware” combination produces its own deterministic result (as long as the browser or OS aren’t significantly changed). Adding an audio fingerprint further strengthens identification: even if Canvas and WebGL outputs coincidentally match, the audio fingerprint may still distinguish the devices.

Media devices and sensors

During fingerprinting, a script can also collect information about peripheral hardware:

  • Via navigator.mediaDevices.enumerateDevices(), it can obtain a list of the user’s media devices (cameras, microphones). The browser usually returns limited data, for example, “two cameras and one microphone” without names or IDs unless permission is granted. Still, the number of devices alone can serve as a distinguishing factor

  • APIs such as Battery Status (battery charge level) were once available and also used for fingerprinting. Battery level and remaining time produced unique combinations. Because these APIs could yield overly precise identifiers (a privacy issue), they are now either restricted or permission-based.

  • Sensors (Orientation, Motion): the presence of certain sensors and the format of their output may vary across devices (e.g., gyroscope refresh rate). These are relatively exotic signals but they can still theoretically supplement a fingerprint.

Overall, the more non-standard the device, the more it reveals through such APIs. If a user has no camera or microphone at all, that already distinguishes them from most laptops, which almost always have webcams.

All of the above — both active and passive attributes — form a set of browser and system characteristics. In practice, scripts collect 10–30 parameters and compile them into a structure (e.g., an object or an array of strings), which is then converted into a hash. Many libraries use fast hashing algorithms such as MurmurHash to produce a compact identifier from roughly 500 bytes of attribute data. The result is a string (e.g., a3f6e9b12d4...) that can be stored on a server as the device ID.

Media devices and sensors

Protection against browser fingerprinting

Modern browsers implement various countermeasures aimed at combating fingerprinting. For example, Tor Browser aims to make all users look identical (the same User-Agent, fixed window size, uniform font set, Canvas and AudioContext disabled, etc.). It even warns users not to maximize the window if they want to remain anonymous

Firefox includes the privacy.resistFingerprinting setting, which similarly averages out values. Brave blocks third-party trackers by default and injects noise into APIs. There are extensions such as CanvasBlocker or Privacy Badger that selectively break tracking scripts.

However, no method offers 100% protection — too many parameters are exposed by browsers. In response to the growing demand for anonymity, anti-detect browsers (such as Octo Browser, MultiLogin, and Dolphin {anty}) have appeared, allowing users to emulate different fingerprints and create dozens of “virtual” identities with distinct parameters for, e.g., affiliate marketing purposes.

The race that began years ago continues: trackers develop new techniques, and browsers devise new countermeasures. The average user clearly loses this race — if one doesn’t actively care about privacy, any site can capture their digital fingerprint and correlate it with data from other sources.

A fingerprint consists of many components, each adding a degree of uniqueness. Hopefully, this breakdown helped you understand how exactly your browser can be identified by websites — because understanding how the technology works is the first step to knowing where the line lies between the convenience of personalization and the protection of personal data.

Fingerprinting vs. other tracking methods

Browser fingerprinting technology emerged as a response to the limitations of classic user-tracking methods.

HTTP cookies

The best-known way to recognize users is to store a unique identifier in the browser (in a cookie file) and read it on every visit. The drawback is that the user can clear cookies, and the site loses the previously issued ID. Also, in incognito mode or when third-party cookies are blocked by the browser, this method doesn’t work. Modern browsers and extensions offer more tools to block or auto-delete cookies, reducing the effectiveness of this approach. Fingerprinting, on the other hand, does not require storing data on the client side, so it works even with cookies disabled and in incognito mode; it’s enough that the browser provides the necessary system information.

HTTP cookies

LocalStorage, SessionStorage, and other web storages

Like cookies, these technologies store data locally in the browser. Scripts can read them on repeat visits. However, the user can manually clear them, and storage is isolated by domain; moreover, SessionStorage is only available for one tab/session only.

There is also Evercookie, a technique that tries to create “undeletable” cookies by duplicating the identifier across all available storages (HTTP cookie, Flash LSO, Silverlight Isolated Storage, IndexedDB, etc.), and by using cache and other tricks. But even Evercookie isn’t omnipotent: for example, it’s useless in incognito mode, where data is not saved to the hard drive. Fingerprinting does not save anything on the device; it collects information anew on every visit, so it’s harder to stop with standard clearing methods.

LocalStorage, SessionStorage, and other web storages

ETag tracking

Not the most common but a working method of using HTTP cache for user identification. On the first request, the server returns a resource (for example, a single pixel) with a unique ETag header. The browser stores it in the cache. On a repeat request to the same URL, the browser automatically sends If-None-Match with the previously received ETag. Thus, the server can detect the same visitor by matching the ETag even if cookies have been deleted. This is a passive tracking method that doesn’t require JavaScript — the identifier is stored in the caching mechanism. ETag tracking is hard to detect, survives cookie clearing (you’d have to clear the cache), and works even without JS. However, it too can be countered if needed (disable cache, use intermediary proxies that clear ETag headers).

ETag tracking

CNAME cloaking

A technique that disguises a third-party tracker as a first-party domain using a DNS CNAME record. For example, instead of loading from tracker.thirdparty.com, the script loads from a subdomain like tracker.​mysite.​com, which points to the tracker’s server at the DNS level via CNAME. The browser treats such a request as coming from the primary resource, so ad/tracker blockers don’t detect the third-party domain — the tracker’s cookies are considered same-site. CNAME cloaking can even bypass browser protections like Safari’s Intelligent Tracking Prevention and the like. In the context of fingerprinting, this method matters because it allows a third-party script to collect a fingerprint and set cookies as if it were the site itself. In essence, CNAME cloaking hides the third party, while fingerprinting works without stored identifiers. Together they can strengthen tracking (the tracker masquerades as the website and collects maximum user data, including the fingerprint, without being blocked).

Fingerprinting

Browser fingerprinting doesn’t replace the methods described above; it’s often used together with them. For example, on the first visit a script may collect the fingerprint and try to set cookies. If cookies are later cleared, a repeat recognition is possible by matching the fingerprint. Also, the fingerprint can complement other methods: for example, supercookies stored via favicon cache can keep a unique ID, and the tracker may compare browser parameters for confirmation. Taken together, these techniques create a multi-layered system for tracking users.

Parameters that make up the browser fingerprint

A fingerprint is formed from dozens of small attributes that together produce a unique combination. Some of them are sent automatically with every HTTP request (passive signals), while others are collected on the client side via JavaScript and Web APIs (active signals).

Passive parameters (HTTP headers and connection)

IP address

The address of your device on the network, determined from each incoming request. It can indicate geolocation (country/city via WHOIS or GeoIP) and affiliation with an organization/ISP. Although an IP address is often not unique (many users may be behind a public address of a single ISP) and can change dynamically, it is included in the fingerprint as a basic network identifier. Moreover, if WebRTC is available, a script can perform a STUN request and obtain your real IP address. An IP address by itself is not permanent, but combined with other signals it increases the probability of uniqueness.

IP address

User Agent

The user agent string sent in the User-Agent  header by every browser. It contains information about the browser, its version, engine, OS version, architecture, and sometimes device model, e.g. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36. Analyzing the user agent lets you distinguish, roughly, Chrome on Windows from Safari on iOS, etc. — in other words, narrow the identification down to the browser and platform.

User agent uniqueness: although the user agent is formed from a limited set of versions, the combination of OS and browser is often rare. For example, an older browser version on a specific OS will present a unique user agent. Non-standard headers added by extensions may also appear in the fingerprint; from them sites can infer installed plugins or frameworks. Overall, however, the user agent is easy to spoof, so you shouldn’t rely on it alone; it is just one aspect of the fingerprint.

User Agent

Accept headers and other protocol characteristics

With each request the browser sends a set of headers: supported formats (Accept, Accept-Language, Accept-Encoding), referrer, caching flags, etc. The combination of these headers is also quite informative. For example, the order and contents of Accept-Language and Accept-Charset fields can differ between OS locales. Presence of Accept-Encoding: br indicates Brotli support and indirectly a relatively modern browser. The specific order in which a browser enumerates headers can serve as a browser engine signature. 

HTTP-level signals are considered passive, as they are provided automatically by the browser. Without JS, the server can learn device type (via User-Agent), preferred languages (Accept-Language), the content types the client supports (e.g., WebP support in Accept reveals a Blink engine), and so on. All these small details feed into the fingerprint model.

Accept headers and other protocol characteristics

Timezone

Although the user’s timezone can be determined actively (via JS), it can be approximated from headers as well. For example, the Date header in HTTP or the time in server logs can be compared with the request time on the client side (for instance, if If-Modified-Since is visible). More commonly the Timezone is obtained on the client side. However, the time offset (GMT±X) is part of the fingerprint because it differs across regions and remains stable for a user over time (unless the user travels or changes the setting manually).

Timezone

Supported Technologies

Some headers or connection traits may indicate browser capabilities. For example, DNT (Do-Not-Track) is present if the user enabled “Do Not Track”; DNT: 1 then becomes part of the fingerprint (paradoxically, this flag can make you stand out because few people enable it). Another example: Upgrade-Insecure-Requests: 1 is sent by most modern browsers on first transition to HTTPS; its absence might identify an unusual client. These subtle nuances rarely appear as separate fingerprint fields but can be considered collectively.

Active parameters (JavaScript and Web API)

Screen resolution and color depth

Available via window.screen objects. Properties screen.width/height return current screen resolution (sometimes accounting for display scaling), and screen.colorDepth returns color depth (usually 24 or 32 bits). These parameters are frequently included in the fingerprint because they vary widely: everyone’s screen size differs. On desktops the browser window rarely matches maximum resolution, but a fingerprint usually takes the maximum available resolution of the user, which reflects their display size. For example, 1920×1080×24 (Full HD, 24-bit color) is one configuration, 1366×768×24 is another, etc. Each resolution combined with color depth can narrow down the device group. If the user changes monitor resolution or connects a new monitor, the fingerprint will change.

Language settings

A browser exposes several related settings: interface/OS language, preferred page language(s), and locale formats for dates/numbers. JS can get navigator.language (or navigator.languages for a list) — values like “ru-RU” or “en-US.” This usually matches what the server receives in Accept-Language. Locale affects formatting functions like Date.toString() (month names in Russian or English, etc.), which can also be used for fingerprinting.

Effect on uniqueness: combinations of languages and regions are quite variable. For example, a Russian-speaking user might have locale ru-RU, or uk-UA (if their OS is Ukrainian), or even en-US (if the interface is English). These nuances add a few bits of entropy. The number of unique language-combination permutations grows every year, but language alone is not extra unique: many people use popular locales. However, combined with other parameters, language helps distinguish, say, Chrome/Windows in Russian from Chrome/Windows in German, creating two different profiles.

Language settings

Timezone (via JS)

A more accurate way to determine the timezone is to call a new Date().getTimezoneOffset() using JS. This returns the local time offset from UTC in minutes. For example, GMT+3 yields 180 minutes. You can also get the timezone name using Intl API. This parameter is almost always included in the fingerprint because it is stable for a device and varies geographically. Two users with identical parameters but different timezones already produce different fingerprints.

Note: some advanced fingerprinters track timezone changes: this can indicate that the same browser changed context (for instance, if the user traveled or changed clock settings). However, the current offset value is normally used for a simple fingerprint.

Timezone (via JS)

Information about the platform and CPU

The navigator object provides a number of properties related to the device platform:

  • navigator.platform — a string indicating the OS/architecture, for example Win32, Linux x86_64, iPhone, etc. This used to be a fairly telling parameter (distinguishing, for example, 32-bit Windows from 64-bit), but modern browsers may return truncated or unified values for privacy reasons. If the parameter is available, it is included in the fingerprint.

  • navigator.hardwareConcurrency — the number of logical CPU threads (cores) on the device. For example, 8 (which may correspond to 4 physical cores with Hyper-Threading). This adds extra variability: mobile devices often have 4 or 8, desktops — 4, 8, 12, 16 and more cores. Not every browser reports an exact value, but under normal conditions this parameter is collected. An unusual thread count (e.g., 6 or 10) can immediately single out a device.

  • navigator.deviceMemory — approximate RAM size in gigabytes (integer). Chrome rounds to 0.25 (a quarter) increments. For example, 8 GB gives deviceMemory = 8. This signal is not supported in all browsers. Where present, it is included: RAM size is rarely a round number, so variability reduces overlaps.

  • navigator.oscpu — a string with the operating system (Firefox-only API). In modern Firefox on Windows it returns something like Windows NT 10.0; Win64; x64. This parameter is rarely used because it duplicates information from the User-Agent.

  • navigator.webdriver — a boolean indicating whether the browser is driven by automation (WebDriver). If true, the site knows it’s dealing with a bot and may change behavior or factor this into the fingerprint. For fingerprinting this is less a “uniqueness” parameter and more a way to detect automation. Nevertheless, navigator.webdriver=true clearly singles out the client (regular users have false), so indirectly it is part of the fingerprint.

Cookies/Storage enabled state

Scripts can check whether cookies are enabled in the browser (navigator.cookieEnabled). If the user has disabled them, this distinguishes them from the majority of other users (almost everyone keeps cookies enabled) and adds uniqueness.

List of browser plugins

navigator.plugins can return a list of installed NPAPI plugins: Acrobat Reader, Flash, Silverlight, etc., including their versions (navigator.plugins[i].name/version), although NPAPI plugins have largely disappeared (Flash and Java are disabled or removed from modern browsers). In Chrome navigator.plugins now contains only the built-in PDF Viewer; in Firefox, likewise, there is nothing extra. Still, the API exists and some browsers may still return something. The fingerprint may include plugin names and their count. An empty list is also a signal (for example, Firefox in Tor-mode has it empty, while a regular Firefox might include a built-in OpenH264 plugin). Overall the role of plugins as a factor is declining; extensions are gaining importance instead.

List of browser plugins

Installed extensions

Ideally websites shouldn’t know which extensions a user has, but in practice some extensions can be detected indirectly. AdBlock or Adblock Plus can be detected by blocked requests or specific DOM elements they introduce. A site may try to load a known URL filtered by AdBlock — if it doesn’t load, a blocker is likely present. 

Another example: extensions can add special objects to window (e.g., React Developer Tools adds __REACT_DEVTOOLS_GLOBAL_HOOK__), and a script finding such an object recognizes the extension. Dozens of small checks can build a “snapshot” of the browser environment. The approximate number of extensions can sometimes be inferred from page response time. Each installed extension can slow page processing. In any case, presence of popular blockers, password managers, or niche extensions is partially detectable and increases profile uniqueness.

List of installed fonts

One of the most variable parameters. The set of system fonts depends on the OS, installed applications (Microsoft Office adds fonts, Adobe adds its own, etc.), and system language (Chinese fonts usually aren’t present for European users). How can a web page detect which fonts you have? Historically Flash (EnumerateFonts) was used, but without it there are purely browser-side methods:

  • Via CSS+JS: a hidden element is created with a font-family fallback list. If the first font isn’t installed, the text renders in the next font and the element’s width/height changes. JS can measure element dimensions to infer which font applied. Iterating hundreds of popular fonts reveals which are present. This method is time-consuming, so the following method is often used.

  • Via Canvas: drawing text in a specific font on a canvas and comparing the pixel raster lets you determine whether the font is installed. This is essentially a case of Canvas fingerprinting (see below).

List of installed fonts

The number of possible font-set combinations is huge, because few people have identical font lists, especially across different OS versions. A rare font (e.g., design-specific fonts) immediately makes the fingerprint unique, making font data incredibly useful for fingerprinting. Font collection is not instantaneous, so some scripts cache the fingerprint result.

Canvas Fingerprinting

This is a well-known fingerprinting method using the HTML5 <canvas> element to obtain unique rendering characteristics. The browser draws content (usually text with a specific font and colors, sometimes geometric shapes) on a virtual canvas, then the script calls canvas.toDataURL(), getting a bitmap of the rendered content. The image is represented as a base64 string, hashed to produce a Canvas fingerprint.

Why is it unique? Tiny differences in the system — font smoothing algorithms, GPU driver versions, platform (Linux vs Windows) — produce subtle variations in the final image. Typically text with diverse characters (letters of different shapes, special symbols) is drawn to maximize smoothing effects. Scripts may also draw colored rectangles, apply transforms or shadows to exercise graphics functions. Different devices yield different images from the same drawing code. A Canvas fingerprint can change after GPU driver updates or switching from integrated to discrete graphics. Combined with WebGL, however, it becomes extremely valuable.

Canvas Fingerprinting

WebGL Fingerprinting

WebGL is an API for rendering 3D graphics in the browser (essentially providing access to OpenGL/ES capabilities). It supplies two key types of data for fingerprinting:

Direct GPU identifiers

The WEBGL_debug_renderer_info extension allows a script to retrieve the UNMASKED_VENDOR_WEBGL and UNMASKED_RENDERER_WEBGL strings from the WebGL context — these typically list the manufacturer and model of the GPU (e.g., Intel Inc., Intel Iris Plus Graphics 640, or NVIDIA Corporation, GeForce GTX 1070). These values effectively reveal the user’s video card model. Most browsers allow this in standard mode (except Tor). The GPU model adds significant entropy: even if two users have the same operating system and browser, one with Intel HD Graphics and the other with an RTX 3080 will have distinct fingerprints.

WebGL constants and capabilities

Even without the direct GPU name, the WebGL context holds many parameters that depend on the driver and hardware: maximum texture units, geometry size limits, shadow and anti-aliasing support, and other numeric constants. A script can sequentially call gl.getParameter(...) for various constants and collect the results. For example, MAX_VERTEX_UNIFORM_VECTORS might be 4,096 on one card and 1,024 on another, etc. The result is a long vector of numbers, a sort of profile of the graphics subsystem. Such a profile is often unique to a device and can differ even between similar GPU models.

WebGL constants and capabilities

Additionally, WebGL can be used like Canvas: that is, by rendering a complex 3D scene and obtaining its raster image. This approach can reveal even subtler differences (for example, in shader implementations). In practice, libraries such as FingerprintJS usually limit themselves to reading UNMASKED_RENDERER (since it’s simpler and more reliable), but some scripts also hash a rendered 3D shape for greater stability. WebGL data greatly increase fingerprint uniqueness, especially on mobile devices: for instance, it used to be difficult to distinguish between iPhones (all had identical Canvas output due to identical GPUs), but now the GPU version can reveal the iPhone model if WebGL is enabled. Combined with Canvas, WebGL provides a powerful source of entropy. That’s why browsers in privacy-oriented modes try to hide or spoof this data.

AudioContext Fingerprinting

Another sophisticated fingerprinting method uses the Web Audio API to derive a unique audio fingerprint of the device. It’s based on the fact that audio generation and processing vary slightly across systems (due to library implementations, SIMD instruction usage, floating-point inaccuracies, etc.). In practice, AudioContext fingerprint values differ noticeably between browsers; each “browser + OS + hardware” combination produces its own deterministic result (as long as the browser or OS aren’t significantly changed). Adding an audio fingerprint further strengthens identification: even if Canvas and WebGL outputs coincidentally match, the audio fingerprint may still distinguish the devices.

Media devices and sensors

During fingerprinting, a script can also collect information about peripheral hardware:

  • Via navigator.mediaDevices.enumerateDevices(), it can obtain a list of the user’s media devices (cameras, microphones). The browser usually returns limited data, for example, “two cameras and one microphone” without names or IDs unless permission is granted. Still, the number of devices alone can serve as a distinguishing factor

  • APIs such as Battery Status (battery charge level) were once available and also used for fingerprinting. Battery level and remaining time produced unique combinations. Because these APIs could yield overly precise identifiers (a privacy issue), they are now either restricted or permission-based.

  • Sensors (Orientation, Motion): the presence of certain sensors and the format of their output may vary across devices (e.g., gyroscope refresh rate). These are relatively exotic signals but they can still theoretically supplement a fingerprint.

Overall, the more non-standard the device, the more it reveals through such APIs. If a user has no camera or microphone at all, that already distinguishes them from most laptops, which almost always have webcams.

All of the above — both active and passive attributes — form a set of browser and system characteristics. In practice, scripts collect 10–30 parameters and compile them into a structure (e.g., an object or an array of strings), which is then converted into a hash. Many libraries use fast hashing algorithms such as MurmurHash to produce a compact identifier from roughly 500 bytes of attribute data. The result is a string (e.g., a3f6e9b12d4...) that can be stored on a server as the device ID.

Media devices and sensors

Protection against browser fingerprinting

Modern browsers implement various countermeasures aimed at combating fingerprinting. For example, Tor Browser aims to make all users look identical (the same User-Agent, fixed window size, uniform font set, Canvas and AudioContext disabled, etc.). It even warns users not to maximize the window if they want to remain anonymous

Firefox includes the privacy.resistFingerprinting setting, which similarly averages out values. Brave blocks third-party trackers by default and injects noise into APIs. There are extensions such as CanvasBlocker or Privacy Badger that selectively break tracking scripts.

However, no method offers 100% protection — too many parameters are exposed by browsers. In response to the growing demand for anonymity, anti-detect browsers (such as Octo Browser, MultiLogin, and Dolphin {anty}) have appeared, allowing users to emulate different fingerprints and create dozens of “virtual” identities with distinct parameters for, e.g., affiliate marketing purposes.

The race that began years ago continues: trackers develop new techniques, and browsers devise new countermeasures. The average user clearly loses this race — if one doesn’t actively care about privacy, any site can capture their digital fingerprint and correlate it with data from other sources.

A fingerprint consists of many components, each adding a degree of uniqueness. Hopefully, this breakdown helped you understand how exactly your browser can be identified by websites — because understanding how the technology works is the first step to knowing where the line lies between the convenience of personalization and the protection of personal data.

Stay up to date with the latest Octo Browser news

By clicking the button you agree to our Privacy Policy.

Stay up to date with the latest Octo Browser news

By clicking the button you agree to our Privacy Policy.

Stay up to date with the latest Octo Browser news

By clicking the button you agree to our Privacy Policy.

Join Octo Browser now

Or contact Customer Service at any time with any questions you might have.

Join Octo Browser now

Or contact Customer Service at any time with any questions you might have.

Join Octo Browser now

Or contact Customer Service at any time with any questions you might have.

©

2025

Octo Browser

©

2025

Octo Browser

©

2025

Octo Browser