Browser Fingerprinting Demonstration & Privacy Education Tool
Open the page. Click one button. Watch everything your browser silently leaks — in real time.
TraceLine is a 100% client-side browser fingerprinting demo. It has no backend, stores nothing, and sends nothing anywhere — it simply shows you what any website can silently extract about you through standard browser APIs the moment you load a page.
This project exists to make the invisible visible. Ad networks, data brokers, and tracking networks stopped relying on cookies years ago. They fingerprint you instead — using the unique combination of your hardware, software, and network configuration that no two browsers share. TraceLine runs every technique they use, then tells you exactly what it found and how to fight it.
| Network & IP Fingerprint — Public IP address, ISP / ASN lookup, approximate geolocation, IP-derived timezone vs. system timezone mismatch for VPN detection, and datacenter/residential classification. | |
| Privacy Score — A weighted 0–10 scoring system that evaluates your active privacy protections: ad blockers, canvas/audio fingerprint guards, WebGL masking, VPN status, DNT/GPC headers, cookie policy, and WebRTC leaks. | |
| Canvas Fingerprinting — Renders a hidden canvas scene (text, shapes, gradients) and extracts a stable hardware-dependent hash. Detects noise injection by privacy-hardened browsers like Brave and Tor Browser. | |
| Audio Fingerprinting — Generates a silent AudioContext signal through an oscillator + compressor chain. The tiny floating-point rounding variations produced by your audio hardware create a unique, reproducible hash. | |
GPU & WebGL Fingerprint — Reads unmasked GPU vendor and renderer strings via WEBGL_debug_renderer_info, detects hardware acceleration support, generates a WebGL scene rendering hash that varies per graphics driver, and queries the newer WebGPU adapter API for vendor and architecture details where supported. |
|
| System Hardware Profile — CPU core count, device RAM (capped at 8 GB by spec), screen resolution & DPR, color depth, touch points, screen orientation, active CSS media queries, and User-Agent Client Hints (UA-CH). | |
| Privacy Signal Detection — DNT (Do Not Track) and GPC (Global Privacy Control) headers, cookie acceptance policy, localStorage availability, IndexedDB status, Service Worker support, PDF viewer, and WebRTC leak exposure. | |
Media Devices & Capabilities — Enumerates connected audio inputs, audio outputs, and video cameras (device count only — no labels without permission). Also measures display refresh rate via requestAnimationFrame sampling over 60 frames. |
|
| Font & Speech Fingerprinting — Probes for installed system fonts by measuring canvas glyph render dimensions. Enumerates available speech synthesis voices (count and language tags), which varies significantly across OS and browser. | |
Battery Status Leak Detection — Uses the Battery API to detect real vs. spoofed values. Flags the 100% charging, 0s charge time state used by Brave and Firefox as their default privacy spoof, and unrealistically long discharge times. |
|
Tor Browser Detection Heuristics — Checks for the standard Tor Browser letterboxed 1000×900 resolution, single en-US language, hardware concurrency masked to 1 core, and suppressed deviceMemory — all signals of Tor Browser's anti-fingerprinting measures. |
|
CPU Timing Benchmark — Runs a tight floating-point loop five times using performance.now(), takes the median, and classifies the result. Throttled or virtualized environments show elevated times — a signal used by bot-detection systems. |
| No server. No database. No tracking. Every single computation runs in your browser tab. Nothing is transmitted anywhere. Closing the tab wipes all collected data. The source code is fully auditable — there is no build output to hide anything in. |
No npm. No webpack. No build step.
git clone https://github.com/your-username/traceline.git
cd traceline
open index.html # macOS
# or: xdg-open index.html (Linux)
# or: start index.html (Windows)Or serve it over a local HTTP server if you want to test Service Worker behaviour:
python3 -m http.server 8080
# then visit http://localhost:8080Tip: Some APIs (like
getUserMediadevice enumeration) require a secure context (https://orlocalhost). Serving viapython3 -m http.servercovers this for local testing.
Traceline/
│
├── index.html ← Entry point. No framework. No bundler.
│
├── css/
│ ├── base.css ← CSS variables, reset, layout, footer
│ ├── components.css ← Nav, hero, buttons, score card, docs section
│ └── terminal.css ← Terminal window chrome + typewriter animations
│
├── js/
│ ├── core/
│ │ ├── theme.js ← Dark / light mode toggle (persisted to localStorage)
│ │ └── tl.js ← Global TL namespace: utilities, hashing, browser/platform detection
│ │
│ ├── engine/
│ │ ├── collect.js ← Orchestrates all data collectors via Promise.all
│ │ ├── system.js ← CPU, RAM, screen, language, timezone, connection, timing, Tor heuristics
│ │ ├── gpu.js ← WebGL renderer string, WebGL scene hash, hardware acceleration
│ │ ├── canvas.js ← Canvas 2D fingerprint hash
│ │ ├── audio.js ← AudioContext fingerprint hash
│ │ ├── media.js ← Device enumeration, refresh rate, font probing, speech voices
│ │ ├── geo.js ← IP geolocation lookup + VPN / datacenter detection heuristics
│ │ └── privacy.js ← LocalStorage, IndexedDB, WebRTC, cookies, DNT, GPC, ad blocker, battery
│ │
│ └── ui/
│ ├── terminal.js ← Typewriter rendering engine for the diagnostic terminal
│ ├── score.js ← Weighted privacy scoring algorithm + score card renderer
│ └── app.js ← Main orchestration: wires UI events, runs the audit, displays results
│
├── assets/
│ └── icons/
│ └── favicon.png
│
└── LICENSE ← MIT
All modules attach themselves to a single window.TL namespace object. Scripts are loaded with defer in dependency order — no module bundler, no import maps, no global pollution beyond one namespace:
theme.js → tl.js → engine/* → ui/terminal.js → ui/score.js → ui/app.js
collect.js fans out to every engine module in parallel using Promise.all, so the latency of the full audit is bounded by the slowest single probe (typically the IP geolocation fetch or the 60-frame refresh rate sampler), not the sum of all of them.
The privacy score runs from 0 to 10, built from four weighted categories that are each scored out of their own point pool and then combined.
| Category | Check | Weight | Detection Method |
|---|---|---|---|
| Network | VPN or proxy in use | 3.0 | ISP/org string matched against known datacenter and VPN providers |
| Network | VPN masks true region from timezone leak | 1.0 | IP-derived timezone vs. system Intl timezone |
| Network | Connection is encrypted (HTTPS) | 1.0 | location.protocol === 'https:' |
| Fingerprint | Canvas fingerprint blocked or noised | 2.5 | Repeated canvas renders diffed for injected noise |
| Fingerprint | Audio fingerprint blocked or noised | 2.0 | Repeated OfflineAudioContext renders diffed for injected noise |
| Fingerprint | GPU renderer masked | 2.0 | WEBGL_debug_renderer_info unavailable or locked vendor string |
| Fingerprint | WebGL fingerprint surface reduced | 1.0 | WebGL scene hash unavailable or GPU masked |
| Fingerprint | WebGPU adapter details hidden | 1.0 | navigator.gpu.requestAdapter() unavailable or withholds vendor info |
| Fingerprint | Media device enumeration blocked | 1.5 | enumerateDevices() blocked or restricted |
| Fingerprint | Font probing blocked | 2.0 | Canvas-based font metric probing fails |
| Hardware | CPU core count hidden | 2.0 | navigator.hardwareConcurrency unavailable on Chromium |
| Hardware | Device RAM hidden | 2.0 | navigator.deviceMemory unavailable on Chromium |
| Hardware | Client Hints not exposed | 1.5 | navigator.userAgentData unavailable on Chromium |
| Hardware | Battery API shielded | 1.5 | Battery API blocked, rejected, or returning spoofed values |
| Hardware | High-resolution timer clamped | 1.0 | performance.now() resolution rounded |
| Hardware | No Tor or automation signals raised | 2.0 | Screen/letterboxing heuristics |
| Privacy | Ad and tracker requests blocked | 2.5 | Hidden DOM trap element + real ad network fetch |
| Privacy | Do Not Track sent | 0.5 | navigator.doNotTrack === '1' (only scored if the header is supported) |
| Privacy | Global Privacy Control active | 1.5 | navigator.globalPrivacyControl === true |
| Privacy | Cookies rejected | 1.0 | navigator.cookieEnabled === false |
| Privacy | Local storage blocked | 1.0 | Write/read test throws |
| Privacy | WebRTC leak shield active | 1.5 | RTCPeerConnection unavailable |
| Privacy | Geolocation permission blocked | 1.0 | Permissions API reports denied |
| Privacy | No fingerprintable extensions detected | 1.0 | DOM signatures for Dark Reader, Grammarly, LanguageTool, etc. |
Scores are classified as Critical (0–3), Exposed (3–5), Partial (5–7), or Protected (7–10). Letter grades (F through A+) are derived from the same percentage and shown per category and overall.
The canvas API renders text with different fonts, geometric shapes, and gradient fills. Subtle differences in sub-pixel anti-aliasing, font rendering hinting, and GPU compositing produce a bitmap that hashes to a value unique per OS/GPU/driver combination.
An OfflineAudioContext runs an oscillator through a dynamics compressor. Floating-point arithmetic differences in the DSP pipeline — caused by OS audio stack variations and hardware implementations — produce a stable numeric fingerprint without any sound being played.
Two independent signals are compared:
- Timezone cross-check —
Intl.DateTimeFormat().resolvedOptions().timeZone(your OS clock) vs. the timezone field returned by the IP geolocation API. A mismatch means your VPN server is in a different region than your system clock claims. - ASN classification — Your ISP's Autonomous System Number is checked against known datacenter operators (AWS, DigitalOcean, Hetzner, etc.). Residential ISPs don't share ASN blocks with server farms.
System fonts are detected without the Font Access API by rendering each candidate font to a canvas and comparing the resulting glyph dimensions to a baseline monospace font. A dimension mismatch confirms the font is installed.
| Browser | Notes |
|---|---|
| Chrome / Edge 90+ | Full support including UA Client Hints |
| Firefox 100+ | Battery API, some UA-CH fields are restricted |
| Safari 16+ | WebRTC availability varies; battery API not exposed |
| Brave | Canvas/audio noise injection is detected and flagged |
| Tor Browser | Letterboxing and anti-fingerprint measures are detected |
| Signal | Mitigation |
|---|---|
| Canvas fingerprint | Brave Shield or Firefox privacy.resistFingerprinting = true |
| Audio fingerprint | Same as above |
| WebGL renderer leak | Brave shields, privacy.resistFingerprinting, or uBlock Origin |
| IP / geolocation | VPN with residential exit nodes + timezone spoofing extension |
| VPN timezone mismatch | Match system timezone to VPN server region |
| Fonts | privacy.resistFingerprinting normalises font rendering |
| Device memory / CPU cores | Brave randomises; Firefox caps both |
| WebRTC IP leak | Disable in about:config (media.peerconnection.enabled = false) |
| Battery status | Firefox and Brave already return fake values |
| Refresh rate | No standard mitigation; rarely used in production fingerprinters |
Issues and pull requests are welcome. Since there's no build step, contributions need only vanilla JS, plain CSS, and an HTML editor. The TL namespace pattern is the only convention to follow — each new engine module should export a get() function (sync or async) and attach to window.TL.
MIT — see LICENSE for full terms.
Copyright © 2026 Trmin°ᶻ𝗓𐰁.ᐟ
Built to educate, not to track.