A lightweight, deterministic browser fingerprinting library that generates consistent device signatures without cookies or storage. Perfect for enhancing security, preventing fraud, or implementing robust user identification systems.
- Features
- Installation
- Quick Start
- How It Works
- Complete Customization Guide
- Common Use Cases
- API Reference
- Custom Components
- Entropy Sources
- Browser Support
- Security & Privacy
- License
- Contributing
- Forever FREE & Unlimited - No dependency, no server cost, runs on regular browser
- Stable & Deterministic - Same fingerprint across page loads and sessions
- Zero Dependencies - Only 2KB minified
- Multiple Hash Formats - SHA-256, SHA-512, SHA-1, or custom length
- Customizable Components - Enable/disable specific entropy sources
- Multiple Output Formats - Hex, Base64, Integer, or Binary
- Cross-Browser Compatible - Works in all modern browsers
- Privacy-Friendly - No cookies, localStorage, or server components
- Extensible Architecture - Add custom entropy sources
# NPM
npm install fingerprint-web
# Yarn
yarn add fingerprint-web
<!-- Direct script include -->
<script src="https://unpkg.com/fingerprint-web@latest/dist/fingerprint.min.js"></script>
<!-- Now available globally as Fingerprint -->
<script>
const fingerprinter = new Fingerprint();
fingerprinter.get().then(hash => {
console.log("Browser fingerprint:", hash);
});
</script>
You can also download the library directly from the GitHub repository and include it in your project:
<script src="path/to/fingerprint.min.js"></script>
import Fingerprint from 'fingerprint-web';
// Create fingerprinter and get device signature
const fingerprinter = new Fingerprint();
fingerprinter.get().then(fingerprint => {
console.log('Fingerprint:', fingerprint);
// e.g. "3f4e591c86c9c5f734fc4b54d5322549bf85ec34b4c2f36310490b3e187b733d"
});
Web-Based Fingerprint generates deterministic device signatures by combining multiple stable browser and hardware characteristics:
-
Data Collection: The library collects various entropy sources that remain consistent between browser sessions:
- Hardware identifiers (screen resolution, color depth, CPU cores)
- Browser configuration (user agent, language, plugins)
- Rendering capabilities (canvas, WebGL, color gamut)
- System settings (timezone, fonts, preferences)
-
Component Processing: Each data point is normalized to ensure consistency:
- Canvas rendering uses controlled drawing parameters
- WebGL details include vendor and renderer information
- Font detection identifies system fonts without accessing the file system
- Plugin details are sorted and normalized
-
Weighting System: More reliable components can be given higher weight
-
Cryptographic Hashing: All collected data points are combined and processed through cryptographic hashing (SHA-256 by default)
-
Format Conversion: The resulting hash can be represented in various formats (hex, base64, integer)
The fingerprint remains consistent across browser sessions because it's based on stable device and browser characteristics rather than stored data.
-
Browser Information Collection:
- User agent string is captured exactly as provided by the browser
- Language preferences are normalized to ensure consistent format
- Do Not Track setting is captured as a boolean value
-
Hardware Information Collection:
- Screen dimensions and color depth are captured in a consistent format
- CPU core count and device memory are included when available
- Touch point capability helps distinguish mobile from desktop devices
-
Advanced Fingerprinting Techniques:
- Canvas fingerprinting draws specific shapes and text with controlled parameters
- WebGL fingerprinting captures graphics hardware details
- Font availability detection uses width comparison techniques
- Audio context processing creates a unique audio signature (optional)
-
Data Processing:
- All components are joined using a configurable separator
- The combined string is hashed using a cryptographic algorithm
- The resulting hash can be truncated or formatted as needed
The library offers extensive customization options for different use cases:
Choose which entropy sources to include:
const fingerprinter = new Fingerprint({
components: {
// Browser basics
userAgent: true,
language: true,
doNotTrack: true,
// Hardware identifiers
screen: true,
hardware: true,
touchPoints: true,
// Advanced sources
canvas: true,
webGL: true,
colorGamut: true,
// Additional sources
plugins: true,
fonts: true,
timezone: true,
// Optional (more volatile)
audio: false
}
});
Choose cryptographic algorithm and result length:
// SHA-512 with custom length output
const fingerprinter = new Fingerprint({
hashAlgorithm: 'SHA-512', // 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'
hashLength: 32 // First 32 characters only (default: 0 = full length)
});
Give more weight to more reliable components:
const fingerprinter = new Fingerprint({
weights: {
// Higher values = more influence on final fingerprint
canvas: 3, // Canvas has 3x normal weight
webGL: 2, // WebGL has 2x normal weight
userAgent: 2, // User agent has 2x normal weight
// All other components have default weight of 1
}
});
Add your own data sources:
const fingerprinter = new Fingerprint({
customComponents: [
// Check for specific browser features
function() {
return {
speechSynthesis: 'speechSynthesis' in window,
bluetooth: 'bluetooth' in navigator,
serviceWorker: 'serviceWorker' in navigator
};
},
// Connection information
function() {
const connection = navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection;
return connection ? connection.effectiveType : 'unknown';
}
]
});
Change options at runtime without creating new instances:
const fingerprinter = new Fingerprint();
// First get standard fingerprint
fingerprinter.get().then(standardHash => {
console.log('Standard fingerprint:', standardHash);
// Then get a shorter SHA-1 fingerprint with the same instance
return fingerprinter.get({
hashAlgorithm: 'SHA-1',
hashLength: 16
});
}).then(shortHash => {
console.log('Short SHA-1 fingerprint:', shortHash);
});
For maximum stability across sessions:
const stableFingerprinter = new Fingerprint({
// Exclude all potentially volatile components
excludeVolatile: true,
// Disable specific volatile components individually
components: {
audio: false,
plugins: false
}
});
Control how fonts are detected:
const fingerprinter = new Fingerprint({
// Enable or disable font detection entirely
enableFonts: true,
// Font detection is included in components
components: {
fonts: true
}
});
Change how components are joined:
const fingerprinter = new Fingerprint({
// Use a different separator between components
separator: ':::' // Default is '||'
});
// Only use the most stable components for maximum consistency
const minimalFingerprint = new Fingerprint({
components: {
userAgent: true,
screen: true,
language: true,
canvas: true,
webGL: true,
// Disable less stable components
fonts: false,
plugins: false,
timezone: false,
colorGamut: false,
touchPoints: false,
hardware: false,
doNotTrack: false
},
hashLength: 32 // Shorter output
});
// Get fingerprint in different formats
fingerprinter.get().then(hash => {
// Different representations of the same fingerprint
console.log('Hex:', hash);
console.log('Base64:', fingerprinter.formatHash(hash, 'base64'));
console.log('Integer:', fingerprinter.formatHash(hash, 'int'));
console.log('Binary:', fingerprinter.formatHash(hash, 'binary').substring(0, 64) + '...');
});
// Maximum entropy configuration
const enhancedFingerprint = new Fingerprint({
// Use stronger hash algorithm
hashAlgorithm: 'SHA-512',
// Include all components including audio
components: {
/* ... all components enabled ... */
audio: true
},
// Include less stable components
excludeVolatile: false,
// Prioritize the most reliable components
weights: {
canvas: 3, // Canvas has 3x normal influence
webGL: 2 // WebGL has 2x normal influence
}
});
// Create a fingerprint instance
const fingerprinter = new Fingerprint({
// Balance between stability and uniqueness
components: {
userAgent: true,
screen: true,
language: true,
timezone: true,
canvas: true,
webGL: true,
plugins: true,
fonts: true,
// Disable less stable components
audio: false
}
});
// When user logs in or makes a purchase
async function verifyUser(userId, transaction) {
// Get current device fingerprint
const deviceFingerprint = await fingerprinter.get();
// Check against known devices for this user
const isKnownDevice = await checkDeviceDatabase(userId, deviceFingerprint);
if (!isKnownDevice && transaction.amount > 1000) {
// Require additional verification for large transactions on new devices
return requestAdditionalVerification(userId, transaction);
} else {
// Proceed with transaction
return processTransaction(userId, transaction, deviceFingerprint);
}
}
// Create a high-entropy fingerprinter
const botDetectionFingerprinter = new Fingerprint({
components: {
userAgent: true,
language: true,
timezone: true,
screen: true,
canvas: true,
webGL: true,
fonts: true,
plugins: true,
audio: true
},
excludeVolatile: false,
customComponents: [
// Add bot detection heuristics
function() {
return {
// Check for inconsistencies typical in bots
navigatorPrototype: Object.getOwnPropertyNames(Navigator.prototype).length,
windowKeys: Object.keys(window).length,
// Automation detection
webdriver: navigator.webdriver,
automation: window.navigator.webdriver ||
window.document.documentElement.getAttribute("webdriver") ||
window.callPhantom ||
window._phantom
};
}
]
});
// Check if current client is likely a bot
async function detectBot() {
const fingerprint = await botDetectionFingerprinter.get();
const rawData = await botDetectionFingerprinter.getRawData();
// Analyze fingerprint and raw data for bot indicators
const botScore = calculateBotScore(fingerprint, rawData);
return {
isBot: botScore > 0.7,
confidence: botScore,
fingerprint: fingerprint
};
}
new Fingerprint({
// Core settings
hashAlgorithm: 'SHA-256', // 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'
hashLength: 0, // 0 = full length, or specify character count
enableFonts: true, // Include font detection
excludeVolatile: true, // Exclude less stable components
// Enable/disable specific components
components: {
userAgent: true, // User agent string
language: true, // Browser language
screen: true, // Screen dimensions and color depth
timezone: true, // System timezone
touchPoints: true, // Touch point capability
hardware: true, // CPU cores and device memory
doNotTrack: true, // Do Not Track setting
canvas: true, // Canvas fingerprinting
webGL: true, // WebGL vendor and renderer
colorGamut: true, // Color gamut capabilities
plugins: true, // Browser plugins
fonts: true, // System fonts
audio: false // Audio processing (off by default)
},
// Component weight factors (higher = more influence)
weights: {
userAgent: 1,
language: 1,
screen: 1,
timezone: 1,
touchPoints: 1,
hardware: 1,
doNotTrack: 1,
canvas: 1,
webGL: 1,
colorGamut: 1,
plugins: 1,
fonts: 1,
audio: 1
},
// Custom entropy sources
customComponents: [],
// Data separator
separator: '||'
});
Method | Description | Return Type | Example |
---|---|---|---|
get([overrideOptions]) |
Generates fingerprint hash | Promise<string> |
fingerprinter.get() |
getRawData() |
Returns raw component data | Promise<Array> |
fingerprinter.getRawData() |
formatHash(hash, format) |
Converts hash format | string|number |
fingerprinter.formatHash(hash, 'base64') |
static createComponent(fn) |
Creates reusable component | Function |
Fingerprint.createComponent(fn) |
Generates and returns the fingerprint hash.
Parameters:
-
overrideOptions
(Object, optional): Runtime options that override constructor options
Returns: Promise<string>
- The fingerprint hash
Example:
// Basic usage
fingerprinter.get().then(hash => console.log(hash));
// With runtime options
fingerprinter.get({
hashAlgorithm: 'SHA-1',
hashLength: 16
}).then(hash => console.log(hash));
Returns the raw fingerprint data before hashing.
Returns: Promise<Array>
- Array of collected data points
Example:
fingerprinter.getRawData().then(data => {
console.log('Raw fingerprint components:', data);
// Analyze components
data.forEach((component, index) => {
console.log(`Component ${index}:`, component);
});
});
Converts the fingerprint hash to various output formats.
Parameters:
-
hash
(String): The fingerprint hash to convert -
format
(String, optional): Output format (default: 'hex')- 'hex': Hexadecimal format (default)
- 'base64': Base64 encoding
- 'int': Integer representation (first 53 bits)
- 'binary': Binary string (0s and 1s)
Returns: The formatted hash (String or Number)
Example:
fingerprinter.get().then(hash => {
console.log('Hex:', hash);
console.log('Base64:', fingerprinter.formatHash(hash, 'base64'));
console.log('Integer:', fingerprinter.formatHash(hash, 'int'));
console.log('Binary:', fingerprinter.formatHash(hash, 'binary'));
});
Creates a reusable component function that can be added to customComponents.
Parameters:
-
fn
(Function): Function that returns a fingerprint component value
Returns: Properly formatted component function
Example:
const screenOrientationComponent = Fingerprint.createComponent(function() {
return screen.orientation ? screen.orientation.type : 'orientation_unsupported';
});
const fingerprinter = new Fingerprint({
customComponents: [screenOrientationComponent]
});
// Available formats
fingerprinter.formatHash(hash, 'hex'); // Default hexadecimal format
fingerprinter.formatHash(hash, 'base64'); // Base64 encoding
fingerprinter.formatHash(hash, 'int'); // Integer representation (first 53 bits)
fingerprinter.formatHash(hash, 'binary'); // Binary string (0s and 1s)
Add your own entropy sources:
const fingerprinter = new Fingerprint({
customComponents: [
// Check for browser features
function() {
return {
speechSynthesis: 'speechSynthesis' in window,
bluetooth: 'bluetooth' in navigator,
serviceWorker: 'serviceWorker' in navigator
};
},
// Any function returning string or object
function() {
return navigator.connection?.effectiveType || 'unknown';
}
]
});
// Creating reusable components
const mediaDeviceComponent = Fingerprint.createComponent(async function() {
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
return 'media_api_unsupported';
}
try {
const devices = await navigator.mediaDevices.enumerateDevices();
const counts = {
audioinput: 0,
audiooutput: 0,
videoinput: 0
};
devices.forEach(device => {
if (counts[device.kind] !== undefined) {
counts[device.kind]++;
}
});
return `media_${counts.audioinput}_${counts.audiooutput}_${counts.videoinput}`;
} catch (e) {
return 'media_error';
}
});
// Use the reusable component
const enhancedFingerprinter = new Fingerprint({
customComponents: [mediaDeviceComponent]
});
const storageComponent = Fingerprint.createComponent(function() {
const storageTypes = {
localStorage: false,
sessionStorage: false,
indexedDB: false
};
try {
// Test localStorage
localStorage.setItem('test', 'test');
localStorage.removeItem('test');
storageTypes.localStorage = true;
} catch (e) {}
try {
// Test sessionStorage
sessionStorage.setItem('test', 'test');
sessionStorage.removeItem('test');
storageTypes.sessionStorage = true;
} catch (e) {}
try {
// Test indexedDB
storageTypes.indexedDB = !!window.indexedDB;
} catch (e) {}
return storageTypes;
});
const fontMetricsComponent = Fingerprint.createComponent(function() {
const testString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const testElement = document.createElement('span');
testElement.style.position = 'absolute';
testElement.style.left = '-9999px';
testElement.style.fontSize = '72px';
testElement.textContent = testString;
document.body.appendChild(testElement);
// Test with different fonts
const fonts = ['monospace', 'sans-serif', 'serif'];
const metrics = {};
fonts.forEach(font => {
testElement.style.fontFamily = font;
metrics[font] = {
width: testElement.offsetWidth,
height: testElement.offsetHeight
};
});
document.body.removeChild(testElement);
return metrics;
});
The library combines these stable browser/hardware characteristics:
- User Agent: Complete browser and OS identification string
- Language: Browser language preferences
- Do Not Track: User's tracking preference setting
- Screen Properties: Resolution, color depth, pixel ratio
- CPU & Memory: Core count and device memory (when available)
- Touch Capability: Maximum touch points supported
- Timezone: User's geographical timezone
- Canvas Rendering: How the browser renders specific shapes and text
- WebGL Information: Graphics card vendor and renderer details
- Color Gamut: Display's color reproduction capabilities
- Browser Plugins: Installed browser extensions and plugins
- Font Availability: System fonts detection
- Audio Processing: How the device processes audio signals (optional)
- Any additional entropy sources added through custom components
Browser | Version | Support Level |
---|---|---|
Chrome | 49+ | ✅ Full |
Firefox | 52+ | ✅ Full |
Safari | 11+ | ✅ Full |
Edge | 79+ | ✅ Full |
Opera | 36+ | ✅ Full |
IE | 11 | |
Chrome for Android | 49+ | ✅ Full |
Safari iOS | 11+ | ✅ Full |
Samsung Internet | 5+ | ✅ Full |
UC Browser | 12+ | ✅ Full |
- Internet Explorer: Limited support. WebGL and some canvas features may be unreliable.
- Safari: Full support, but some font detection features may behave differently.
- Mobile Browsers: Full support on modern mobile browsers.
- Privacy Modes: Fingerprinting works in incognito/private browsing modes.
MIT License - feel free to use and modify as needed.
Developed by Jafran Hasan, Sr Software Developer at WPPOOL.