Website Fingerprinting and Privacy Detection: A Developer's Guide
A practical Fusebox guide to website fingerprinting and privacy detection.
Website Fingerprinting and Privacy Detection: A Developer's Guide
Browser fingerprinting has become the invisible tracker of the modern web. Unlike cookies, which users can delete, fingerprinting creates a unique identifier from your browser's characteristics. Studies show that modern fingerprinting techniques can uniquely identify 99.24% of users. This guide reveals how fingerprinting works and how to detect and defend against it.
Why Privacy Detection Matters
In 2019, a study of the top 10,000 websites found that 70% employed some form of fingerprinting. Major companies use these techniques for fraud detection, but the same technology enables invasive tracking across the web. Understanding fingerprinting is essential for both protecting user privacy and implementing legitimate security measures.
Browser Fingerprint Analyzer
Comprehensive fingerprint detection tool:
// Browser Fingerprint Analyzer
const FingerprintAnalyzer = {
fingerprint: {},
// Collect all fingerprint data
async collectFingerprint() {
const start = performance.now();
this.fingerprint = {
timestamp: new Date().toISOString(),
basic: await this.getBasicInfo(),
screen: this.getScreenInfo(),
browser: this.getBrowserInfo(),
hardware: await this.getHardwareInfo(),
webgl: this.getWebGLInfo(),
audio: await this.getAudioInfo(),
fonts: await this.getFontsInfo(),
canvas: this.getCanvasFingerprint(),
permissions: await this.getPermissionsInfo(),
sensors: this.getSensorInfo(),
network: this.getNetworkInfo(),
battery: await this.getBatteryInfo(),
timing: performance.now() - start
};
// Calculate uniqueness score
this.fingerprint.uniqueness = this.calculateUniqueness();
this.fingerprint.privacy = this.assessPrivacy();
return this.fingerprint;
},
// Basic browser information
async getBasicInfo() {
return {
userAgent: navigator.userAgent,
language: navigator.language,
languages: navigator.languages,
platform: navigator.platform,
cookieEnabled: navigator.cookieEnabled,
doNotTrack: navigator.doNotTrack,
hardwareConcurrency: navigator.hardwareConcurrency,
maxTouchPoints: navigator.maxTouchPoints,
vendor: navigator.vendor,
vendorSub: navigator.vendorSub,
product: navigator.product,
productSub: navigator.productSub,
onLine: navigator.onLine,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
timezoneOffset: new Date().getTimezoneOffset(),
sessionStorage: !!window.sessionStorage,
localStorage: !!window.localStorage,
indexedDB: !!window.indexedDB,
openDatabase: !!window.openDatabase
};
},
// Screen and display information
getScreenInfo() {
return {
width: screen.width,
height: screen.height,
availWidth: screen.availWidth,
availHeight: screen.availHeight,
colorDepth: screen.colorDepth,
pixelDepth: screen.pixelDepth,
devicePixelRatio: window.devicePixelRatio,
orientation: screen.orientation?.type,
// Detect multiple monitors
isExtended: screen.availWidth > screen.width ||
screen.availHeight > screen.height
};
},
// Browser capabilities
getBrowserInfo() {
const info = {
plugins: [],
mimeTypes: [],
features: {}
};
// Plugin detection
if (navigator.plugins) {
for (let i = 0; i < navigator.plugins.length; i++) {
info.plugins.push({
name: navigator.plugins[i].name,
description: navigator.plugins[i].description,
filename: navigator.plugins[i].filename
});
}
}
// MIME types
if (navigator.mimeTypes) {
for (let i = 0; i < navigator.mimeTypes.length; i++) {
info.mimeTypes.push(navigator.mimeTypes[i].type);
}
}
// Feature detection
info.features = {
webRTC: !!(window.RTCPeerConnection || window.webkitRTCPeerConnection),
webGL: !!window.WebGLRenderingContext,
webGL2: !!window.WebGL2RenderingContext,
webWorker: !!window.Worker,
serviceWorker: 'serviceWorker' in navigator,
sharedWorker: !!window.SharedWorker,
audioContext: !!(window.AudioContext || window.webkitAudioContext),
mediaDevices: !!navigator.mediaDevices,
geolocation: !!navigator.geolocation,
notifications: 'Notification' in window,
bluetooth: 'bluetooth' in navigator,
usb: 'usb' in navigator,
midi: 'requestMIDIAccess' in navigator,
clipboard: 'clipboard' in navigator,
credentials: 'credentials' in navigator,
mediaSession: 'mediaSession' in navigator,
speechSynthesis: 'speechSynthesis' in window,
vr: 'getVRDisplays' in navigator,
ar: 'xr' in navigator
};
return info;
},
// Hardware fingerprinting
async getHardwareInfo() {
const info = {
cpuClass: navigator.cpuClass,
oscpu: navigator.oscpu,
hardwareConcurrency: navigator.hardwareConcurrency
};
// Memory detection (Chrome only)
if (navigator.deviceMemory) {
info.deviceMemory = navigator.deviceMemory;
}
// Connection info
if (navigator.connection) {
info.connection = {
effectiveType: navigator.connection.effectiveType,
downlink: navigator.connection.downlink,
rtt: navigator.connection.rtt,
saveData: navigator.connection.saveData
};
}
// Media devices
try {
const devices = await navigator.mediaDevices.enumerateDevices();
info.mediaDevices = {
audioinput: devices.filter(d => d.kind === 'audioinput').length,
audiooutput: devices.filter(d => d.kind === 'audiooutput').length,
videoinput: devices.filter(d => d.kind === 'videoinput').length
};
} catch (e) {
info.mediaDevices = { error: 'Permission denied' };
}
return info;
},
// WebGL fingerprinting
getWebGLInfo() {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (!gl) {
return { supported: false };
}
const info = {
supported: true,
vendor: gl.getParameter(gl.VENDOR),
renderer: gl.getParameter(gl.RENDERER),
version: gl.getParameter(gl.VERSION),
shadingLanguageVersion: gl.getParameter(gl.SHADING_LANGUAGE_VERSION),
extensions: gl.getSupportedExtensions()
};
// Get WEBGL_debug_renderer_info if available
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
if (debugInfo) {
info.unmaskedVendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
info.unmaskedRenderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
}
return info;
},
// Audio fingerprinting
async getAudioInfo() {
try {
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const analyser = audioContext.createAnalyser();
const gainNode = audioContext.createGain();
const scriptProcessor = audioContext.createScriptProcessor(4096, 1, 1);
gainNode.gain.value = 0; // Mute
oscillator.connect(analyser);
analyser.connect(scriptProcessor);
scriptProcessor.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.start(0);
return new Promise((resolve) => {
let fingerprint = 0;
scriptProcessor.onaudioprocess = (event) => {
const output = event.inputBuffer.getChannelData(0);
for (let i = 0; i < output.length; i++) {
fingerprint += Math.abs(output[i]);
}
oscillator.stop();
audioContext.close();
resolve({
fingerprint: fingerprint.toString(),
sampleRate: audioContext.sampleRate,
maxChannelCount: audioContext.destination.maxChannelCount,
numberOfInputs: audioContext.destination.numberOfInputs,
numberOfOutputs: audioContext.destination.numberOfOutputs,
channelCount: audioContext.destination.channelCount,
channelCountMode: audioContext.destination.channelCountMode,
channelInterpretation: audioContext.destination.channelInterpretation
});
};
});
} catch (e) {
return { error: e.message };
}
},
// Font fingerprinting
async getFontsInfo() {
const baseFonts = ['monospace', 'sans-serif', 'serif'];
const testString = 'mmmmmmmmmmlli';
const testSize = '72px';
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const baseFontWidths = {};
// Measure base fonts
baseFonts.forEach(baseFont => {
context.font = `${testSize} ${baseFont}`;
baseFontWidths[baseFont] = context.measureText(testString).width;
});
// Test fonts
const fonts = [
'Arial', 'Arial Black', 'Arial Hebrew', 'Arial MT', 'Arial Narrow',
'Comic Sans MS', 'Courier', 'Courier New', 'Georgia', 'Helvetica',
'Impact', 'Lucida Console', 'Lucida Sans Unicode', 'Microsoft Sans Serif',
'Monaco', 'Palatino', 'Tahoma', 'Times', 'Times New Roman', 'Trebuchet MS',
'Verdana', 'Wingdings', 'Wingdings 2', 'Wingdings 3'
];
const detectedFonts = [];
fonts.forEach(font => {
const detected = baseFonts.some(baseFont => {
context.font = `${testSize} ${font}, ${baseFont}`;
const width = context.measureText(testString).width;
return width !== baseFontWidths[baseFont];
});
if (detected) {
detectedFonts.push(font);
}
});
return {
count: detectedFonts.length,
fonts: detectedFonts
};
},
// Canvas fingerprinting
getCanvasFingerprint() {
const canvas = document.createElement('canvas');
canvas.width = 280;
canvas.height = 60;
const context = canvas.getContext('2d');
// Draw test content
context.fillStyle = '#f60';
context.fillRect(125, 1, 62, 20);
context.fillStyle = '#069';
context.font = '11pt Arial';
context.fillText('Canvas fingerprint test 🙃', 2, 15);
context.fillStyle = 'rgba(102, 204, 0, 0.7)';
context.font = '18pt Arial';
context.fillText('BrowserLeaks.com', 4, 45);
// Get canvas data
const dataURL = canvas.toDataURL();
// Calculate hash
let hash = 0;
for (let i = 0; i < dataURL.length; i++) {
const char = dataURL.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return {
hash: hash.toString(),
dataLength: dataURL.length
};
},
// Permission API fingerprinting
async getPermissionsInfo() {
const permissions = {};
const permissionNames = [
'geolocation', 'notifications', 'push', 'midi', 'camera',
'microphone', 'speaker', 'device-info', 'background-sync',
'bluetooth', 'persistent-storage', 'ambient-light-sensor',
'accelerometer', 'gyroscope', 'magnetometer', 'clipboard'
];
for (const permission of permissionNames) {
try {
const result = await navigator.permissions.query({ name: permission });
permissions[permission] = result.state;
} catch (e) {
permissions[permission] = 'not-supported';
}
}
return permissions;
},
// Sensor API detection
getSensorInfo() {
return {
accelerometer: 'Accelerometer' in window,
gyroscope: 'Gyroscope' in window,
magnetometer: 'Magnetometer' in window,
absoluteOrientationSensor: 'AbsoluteOrientationSensor' in window,
relativeOrientationSensor: 'RelativeOrientationSensor' in window,
ambientLightSensor: 'AmbientLightSensor' in window,
proximirtySensor: 'ProximitySensor' in window
};
},
// Network information
getNetworkInfo() {
const info = {
onLine: navigator.onLine
};
if ('connection' in navigator) {
const conn = navigator.connection;
info.connection = {
effectiveType: conn.effectiveType,
downlink: conn.downlink,
downlinkMax: conn.downlinkMax,
rtt: conn.rtt,
type: conn.type,
saveData: conn.saveData
};
}
return info;
},
// Battery API
async getBatteryInfo() {
if ('getBattery' in navigator) {
try {
const battery = await navigator.getBattery();
return {
charging: battery.charging,
chargingTime: battery.chargingTime,
dischargingTime: battery.dischargingTime,
level: battery.level
};
} catch (e) {
return { error: 'Not available' };
}
}
return { supported: false };
},
// Calculate uniqueness score
calculateUniqueness() {
let score = 0;
let factors = 0;
// Factors that increase uniqueness
const uniqueFactors = {
screenResolution: 10,
timezone: 5,
plugins: 15,
fonts: 20,
canvas: 25,
webgl: 20,
audio: 15
};
// Check each factor
if (this.fingerprint.screen) {
const resolution = `${this.fingerprint.screen.width}x${this.fingerprint.screen.height}`;
if (!['1920x1080', '1366x768', '1440x900'].includes(resolution)) {
score += uniqueFactors.screenResolution;
}
factors++;
}
if (this.fingerprint.basic?.timezone) {
score += uniqueFactors.timezone;
factors++;
}
if (this.fingerprint.browser?.plugins.length > 3) {
score += uniqueFactors.plugins;
factors++;
}
if (this.fingerprint.fonts?.count > 15) {
score += uniqueFactors.fonts;
factors++;
}
if (this.fingerprint.canvas?.hash) {
score += uniqueFactors.canvas;
factors++;
}
if (this.fingerprint.webgl?.unmaskedRenderer) {
score += uniqueFactors.webgl;
factors++;
}
if (this.fingerprint.audio?.fingerprint) {
score += uniqueFactors.audio;
factors++;
}
return {
score: Math.min(100, score),
factors: factors,
rating: score > 80 ? 'Very High' :
score > 60 ? 'High' :
score > 40 ? 'Medium' :
score > 20 ? 'Low' : 'Very Low'
};
},
// Assess privacy level
assessPrivacy() {
const issues = [];
const recommendations = [];
// Check for privacy issues
if (this.fingerprint.basic?.doNotTrack !== '1') {
issues.push('Do Not Track is not enabled');
recommendations.push('Enable Do Not Track in browser settings');
}
if (this.fingerprint.canvas?.hash) {
issues.push('Canvas fingerprinting is possible');
recommendations.push('Use browser extensions that block canvas fingerprinting');
}
if (this.fingerprint.webgl?.unmaskedRenderer) {
issues.push('WebGL reveals hardware information');
recommendations.push('Consider disabling WebGL for privacy');
}
if (this.fingerprint.browser?.plugins.length > 0) {
issues.push('Browser plugins are detectable');
recommendations.push('Minimize browser plugins/extensions');
}
if (this.fingerprint.fonts?.count > 20) {
issues.push('Many unique fonts detected');
recommendations.push('Use default system fonts only');
}
return {
score: Math.max(0, 100 - (issues.length * 15)),
issues,
recommendations,
rating: issues.length === 0 ? 'Excellent' :
issues.length <= 2 ? 'Good' :
issues.length <= 4 ? 'Fair' : 'Poor'
};
}
};
// Run fingerprint analysis
FingerprintAnalyzer.collectFingerprint().then(console.log);
Tracking Detection System
Detect various tracking methods:
// Comprehensive Tracking Detector
const TrackingDetector = {
detectedTrackers: {
cookies: [],
localStorage: [],
fingerprinting: [],
pixels: [],
beacons: []
},
// Start detection
async detectTracking() {
console.log('Starting tracking detection...');
this.detectCookies();
this.detectLocalStorage();
this.detectFingerprinting();
this.detectTrackingPixels();
this.detectBeacons();
await this.detectThirdPartyRequests();
return this.generateReport();
},
// Detect tracking cookies
detectCookies() {
const cookies = document.cookie.split(';');
const trackingPatterns = [
'_ga', '_gid', '__utm', '_fbp', '_gcl', 'IDE', 'NID',
'fr', 'tr', '_pinterest', '_twitter', 'personalization_id'
];
cookies.forEach(cookie => {
const [name, value] = cookie.trim().split('=');
// Check for tracking patterns
const isTracker = trackingPatterns.some(pattern =>
name.toLowerCase().includes(pattern.toLowerCase())
);
if (isTracker) {
this.detectedTrackers.cookies.push({
name,
value: value?.substring(0, 20) + '...',
type: this.identifyTrackerType(name),
domain: window.location.hostname
});
}
});
},
// Detect localStorage tracking
detectLocalStorage() {
const suspiciousKeys = [];
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
// Check for tracking patterns
if (key.includes('track') || key.includes('analytics') ||
key.includes('_ga') || key.includes('user_id') ||
key.includes('session') || key.includes('visitor')) {
suspiciousKeys.push({
key,
size: localStorage.getItem(key).length,
type: 'localStorage tracking'
});
}
}
this.detectedTrackers.localStorage = suspiciousKeys;
},
// Detect fingerprinting attempts
detectFingerprinting() {
const fingerprintingAPIs = {
canvas: this.detectCanvasFingerprinting(),
webgl: this.detectWebGLFingerprinting(),
audio: this.detectAudioFingerprinting(),
fonts: this.detectFontFingerprinting()
};
Object.entries(fingerprintingAPIs).forEach(([type, detected]) => {
if (detected) {
this.detectedTrackers.fingerprinting.push({
type,
detected: true,
details: detected
});
}
});
},
// Detect canvas fingerprinting
detectCanvasFingerprinting() {
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData;
let canvasRead = false;
// Override methods temporarily
HTMLCanvasElement.prototype.toDataURL = function(...args) {
canvasRead = true;
return originalToDataURL.apply(this, args);
};
CanvasRenderingContext2D.prototype.getImageData = function(...args) {
canvasRead = true;
return originalGetImageData.apply(this, args);
};
// Create test canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.fillText('test', 0, 0);
// Restore original methods
HTMLCanvasElement.prototype.toDataURL = originalToDataURL;
CanvasRenderingContext2D.prototype.getImageData = originalGetImageData;
return canvasRead ? 'Canvas reading detected' : false;
},
// Detect WebGL fingerprinting
detectWebGLFingerprinting() {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
if (gl) {
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
if (debugInfo) {
return 'WebGL debug info accessible';
}
}
return false;
},
// Detect audio fingerprinting
detectAudioFingerprinting() {
return 'AudioContext' in window || 'webkitAudioContext' in window;
},
// Detect font fingerprinting
detectFontFingerprinting() {
// Check if fonts are being measured
const originalMeasureText = CanvasRenderingContext2D.prototype.measureText;
let fontMeasured = false;
CanvasRenderingContext2D.prototype.measureText = function(...args) {
fontMeasured = true;
return originalMeasureText.apply(this, args);
};
// Restore
setTimeout(() => {
CanvasRenderingContext2D.prototype.measureText = originalMeasureText;
}, 100);
return fontMeasured;
},
// Detect tracking pixels
detectTrackingPixels() {
const images = document.querySelectorAll('img');
const pixels = [];
images.forEach(img => {
// Check for 1x1 pixels
if ((img.width === 1 && img.height === 1) ||
(img.naturalWidth === 1 && img.naturalHeight === 1) ||
img.src.includes('pixel') || img.src.includes('track')) {
pixels.push({
src: img.src,
type: 'tracking pixel',
domain: new URL(img.src).hostname
});
}
});
this.detectedTrackers.pixels = pixels;
},
// Detect beacon API usage
detectBeacons() {
const originalSendBeacon = navigator.sendBeacon;
const beacons = [];
// Override sendBeacon
navigator.sendBeacon = function(url, data) {
beacons.push({
url,
data: data ? 'Data sent' : 'No data',
timestamp: new Date().toISOString()
});
console.warn('Beacon detected:', url);
return originalSendBeacon.apply(navigator, arguments);
};
// Restore after detection period
setTimeout(() => {
navigator.sendBeacon = originalSendBeacon;
this.detectedTrackers.beacons = beacons;
}, 5000);
},
// Detect third-party requests
async detectThirdPartyRequests() {
const requests = performance.getEntriesByType('resource');
const thirdParty = [];
const currentDomain = window.location.hostname;
requests.forEach(request => {
try {
const url = new URL(request.name);
if (url.hostname !== currentDomain &&
!url.hostname.includes(currentDomain)) {
// Known trackers
const trackers = [
'google-analytics.com', 'googletagmanager.com',
'facebook.com', 'doubleclick.net', 'amazon-adsystem.com',
'googlesyndication.com', 'googleadservices.com',
'twitter.com', 'linkedin.com', 'pinterest.com',
'hotjar.com', 'mixpanel.com', 'segment.com'
];
const isTracker = trackers.some(tracker =>
url.hostname.includes(tracker)
);
if (isTracker) {
thirdParty.push({
url: url.hostname,
type: this.identifyTrackerType(url.hostname),
requests: 1
});
}
}
} catch (e) {
// Invalid URL
}
});
// Aggregate by domain
const aggregated = {};
thirdParty.forEach(item => {
if (aggregated[item.url]) {
aggregated[item.url].requests++;
} else {
aggregated[item.url] = item;
}
});
this.detectedTrackers.thirdParty = Object.values(aggregated);
},
// Identify tracker type
identifyTrackerType(identifier) {
const types = {
analytics: ['google-analytics', '_ga', 'gtm', 'analytics'],
advertising: ['doubleclick', 'adsystem', 'adservices', '_fbp'],
social: ['facebook', 'twitter', 'linkedin', 'pinterest'],
marketing: ['hubspot', 'marketo', 'pardot', 'eloqua'],
heatmap: ['hotjar', 'fullstory', 'mouseflow'],
customer: ['intercom', 'drift', 'zendesk']
};
for (const [type, patterns] of Object.entries(types)) {
if (patterns.some(pattern => identifier.toLowerCase().includes(pattern))) {
return type;
}
}
return 'unknown';
},
// Generate tracking report
generateReport() {
const report = {
summary: {
totalTrackers: 0,
byType: {},
privacyScore: 100,
recommendations: []
},
details: this.detectedTrackers
};
// Count trackers
Object.values(this.detectedTrackers).forEach(category => {
report.summary.totalTrackers += Array.isArray(category) ? category.length : 0;
});
// Score calculation
report.summary.privacyScore = Math.max(0, 100 - (report.summary.totalTrackers * 5));
// Recommendations
if (this.detectedTrackers.cookies.length > 0) {
report.summary.recommendations.push('Use privacy-focused browser or extensions to block tracking cookies');
}
if (this.detectedTrackers.fingerprinting.length > 0) {
report.summary.recommendations.push('Enable fingerprinting protection in browser settings');
}
if (this.detectedTrackers.thirdParty?.length > 5) {
report.summary.recommendations.push('Consider using ad blocker to reduce third-party tracking');
}
return report;
}
};
// Run tracking detection
TrackingDetector.detectTracking().then(console.log);
Privacy Protection Analyzer
Analyze and recommend privacy protections:
// Privacy Protection Analyzer
const PrivacyProtector = {
// Check browser privacy features
checkBrowserPrivacy() {
const features = {
doNotTrack: navigator.doNotTrack === '1',
cookieEnabled: navigator.cookieEnabled,
thirdPartyCookies: this.checkThirdPartyCookies(),
trackingProtection: this.checkTrackingProtection(),
httpsOnly: location.protocol === 'https:',
referrerPolicy: document.referrerPolicy || 'not set',
permissions: {}
};
// Check permissions API
const permissions = ['geolocation', 'camera', 'microphone', 'notifications'];
permissions.forEach(async permission => {
try {
const result = await navigator.permissions.query({ name: permission });
features.permissions[permission] = result.state;
} catch (e) {
features.permissions[permission] = 'not supported';
}
});
return features;
},
// Check third-party cookie support
checkThirdPartyCookies() {
// This is a heuristic check
const testCookie = 'test_third_party=1';
document.cookie = testCookie;
const enabled = document.cookie.includes('test_third_party');
// Clean up
if (enabled) {
document.cookie = 'test_third_party=; expires=Thu, 01 Jan 1970 00:00:00 UTC';
}
return !enabled; // If we can't set cookies, third-party might be blocked
},
// Check tracking protection
checkTrackingProtection() {
// Check for common tracking protection indicators
const indicators = {
firefoxTP: navigator.doNotTrack === '1' && navigator.userAgent.includes('Firefox'),
safariITP: navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrome'),
braveShields: navigator.brave !== undefined
};
return Object.values(indicators).some(v => v);
},
// Generate privacy recommendations
generateRecommendations(fingerprint, tracking) {
const recommendations = {
critical: [],
high: [],
medium: [],
low: []
};
// Based on fingerprint uniqueness
if (fingerprint.uniqueness?.score > 80) {
recommendations.critical.push({
issue: 'Highly unique browser fingerprint',
action: 'Use Tor Browser or Firefox with privacy settings',
impact: 'Prevents cross-site tracking'
});
}
// Based on tracking detection
if (tracking.summary?.totalTrackers > 10) {
recommendations.high.push({
issue: 'Multiple trackers detected',
action: 'Install uBlock Origin or Privacy Badger',
impact: 'Blocks most tracking attempts'
});
}
// Canvas fingerprinting
if (fingerprint.canvas?.hash) {
recommendations.high.push({
issue: 'Canvas fingerprinting possible',
action: 'Enable canvas blocker extension',
impact: 'Prevents canvas-based tracking'
});
}
// WebGL info exposed
if (fingerprint.webgl?.unmaskedRenderer) {
recommendations.medium.push({
issue: 'Hardware information exposed via WebGL',
action: 'Disable WebGL or use WebGL blocker',
impact: 'Hides GPU information'
});
}
// Battery API
if (fingerprint.battery?.level !== undefined) {
recommendations.low.push({
issue: 'Battery API accessible',
action: 'Use browser that blocks Battery API',
impact: 'Prevents battery-based tracking'
});
}
return recommendations;
},
// Privacy-preserving alternatives
suggestAlternatives() {
return {
browsers: [
{
name: 'Tor Browser',
privacy: 10,
pros: ['Maximum privacy', 'Anti-fingerprinting'],
cons: ['Slower', 'Some sites may break']
},
{
name: 'Firefox + uBlock Origin',
privacy: 8,
pros: ['Good privacy', 'Fast', 'Customizable'],
cons: ['Requires configuration']
},
{
name: 'Brave',
privacy: 7,
pros: ['Built-in ad blocking', 'Easy to use'],
cons: ['Some privacy concerns with crypto features']
}
],
extensions: [
{
name: 'uBlock Origin',
purpose: 'Ad and tracker blocking',
effectiveness: 'Very High'
},
{
name: 'Privacy Badger',
purpose: 'Learns to block trackers',
effectiveness: 'High'
},
{
name: 'Canvas Blocker',
purpose: 'Prevents canvas fingerprinting',
effectiveness: 'High'
},
{
name: 'HTTPS Everywhere',
purpose: 'Forces HTTPS connections',
effectiveness: 'Medium'
}
],
settings: [
'Enable "Do Not Track"',
'Block third-party cookies',
'Use strict tracking protection',
'Disable WebRTC',
'Clear cookies on browser close',
'Use private/incognito mode for sensitive browsing'
]
};
}
};
Complete Privacy Audit
Comprehensive privacy audit function:
// Complete Privacy Audit
async function performPrivacyAudit() {
console.log('Starting comprehensive privacy audit...');
const audit = {
timestamp: new Date().toISOString(),
url: window.location.href,
results: {},
score: 0,
summary: {}
};
try {
// 1. Collect fingerprint
console.log('Analyzing browser fingerprint...');
audit.results.fingerprint = await FingerprintAnalyzer.collectFingerprint();
// 2. Detect tracking
console.log('Detecting tracking mechanisms...');
audit.results.tracking = await TrackingDetector.detectTracking();
// 3. Check privacy protections
console.log('Checking privacy protections...');
audit.results.protections = PrivacyProtector.checkBrowserPrivacy();
// 4. Generate recommendations
audit.results.recommendations = PrivacyProtector.generateRecommendations(
audit.results.fingerprint,
audit.results.tracking
);
// 5. Calculate privacy score
const fingerprintScore = 100 - audit.results.fingerprint.uniqueness.score;
const trackingScore = audit.results.tracking.summary.privacyScore;
const protectionBonus = audit.results.protections.doNotTrack ? 10 : 0;
audit.score = Math.round((fingerprintScore + trackingScore) / 2 + protectionBonus);
audit.score = Math.min(100, Math.max(0, audit.score));
// 6. Generate summary
audit.summary = {
privacyScore: audit.score,
rating: audit.score > 80 ? 'Excellent' :
audit.score > 60 ? 'Good' :
audit.score > 40 ? 'Fair' :
audit.score > 20 ? 'Poor' : 'Very Poor',
uniquenessRating: audit.results.fingerprint.uniqueness.rating,
trackersFound: audit.results.tracking.summary.totalTrackers,
criticalIssues: audit.results.recommendations.critical.length,
protectionsEnabled: Object.values(audit.results.protections).filter(v => v === true).length
};
// 7. Add alternatives
audit.alternatives = PrivacyProtector.suggestAlternatives();
} catch (error) {
audit.error = error.message;
}
console.log('Privacy audit complete!');
return audit;
}
// Run the audit
performPrivacyAudit().then(audit => {
console.log('Privacy Audit Results:');
console.log(`Overall Score: ${audit.score}/100 (${audit.summary.rating})`);
console.log(`Fingerprint Uniqueness: ${audit.summary.uniquenessRating}`);
console.log(`Trackers Found: ${audit.summary.trackersFound}`);
console.log(`Critical Issues: ${audit.summary.criticalIssues}`);
console.log('\nFull report:', audit);
});
Best Practices for Privacy
- Use Privacy-Focused Browsers: Tor, hardened Firefox, or Brave
- Enable Tracking Protection: Use strict mode in browser settings
- Block Third-Party Cookies: Prevent cross-site tracking
- Use VPN Services: Hide your IP address and location
- Regular Cookie Cleaning: Clear cookies and site data regularly
- Minimize Extensions: Each extension increases fingerprint uniqueness
- Disable Unnecessary APIs: Turn off location, camera, microphone when not needed
- Use Privacy Extensions: uBlock Origin, Privacy Badger, etc.
- HTTPS Only: Use HTTPS Everywhere or browser HTTPS-only mode
- Compartmentalize: Use different browsers/profiles for different activities
Common Privacy Threats
- Browser Fingerprinting: Unique identification without cookies
- Canvas Fingerprinting: Using HTML5 canvas for tracking
- WebRTC IP Leaks: Revealing real IP despite VPN
- Third-Party Cookies: Cross-site tracking cookies
- Supercookies: Persistent tracking via Flash, HTML5
- Device Fingerprinting: Hardware and sensor-based tracking
- Behavioral Analysis: Tracking via typing patterns, mouse movements
- Social Media Tracking: Like buttons and embedded content
- Analytics Services: Detailed user behavior tracking
- Ad Networks: Extensive cross-site tracking networks
Privacy is not about hiding wrongdoing—it's about maintaining autonomy in an increasingly connected world. Use these tools to understand your digital footprint and make informed decisions about your online privacy.