A modern, privacy-conscious alternative to browser fingerprinting for unique user identification. TraceJS provides a robust and ethical approach to device identification while respecting user privacy.
- 🔒 Privacy-focused device identification
- 🎨 Advanced canvas fingerprinting
- 🖥️ Hardware-specific characteristics detection
- 🌐 Browser and OS information gathering
- 🎵 Audio capabilities fingerprinting
- 📊 Detailed fingerprint strength scoring
- 🧪 Real-time entropy analysis
- 🔍 Behavioral fingerprinting
- 📱 Cross-browser compatibility
- 🛡️ GDPR/CCPA compliant consent management
- ⚡ Asynchronous and performant
- 📖 TypeScript support
- 🔄 Consistent fingerprinting for authentication workflows
- 💾 Smart caching system for stable identification
Install TraceJS using npm:
npm install @elhamdev/tracejs
Or using yarn:
yarn add @elhamdev/tracejs
import { FingerprintService } from 'tracejs';
// Initialize the fingerprint service
const fingerprintService = new FingerprintService();
// Generate a simple fingerprint
const fingerprint = await fingerprintService.generateFingerprint();
console.log('Device Fingerprint:', fingerprint);
// Get detailed fingerprint information
const detailedFingerprint = await fingerprintService.getDetailedFingerprint();
console.log('Detailed Information:', detailedFingerprint);
You can customize the fingerprinting process by passing options to the constructor:
const options = {
battery: false, // Disable battery fingerprinting
screen: false // Disable screen fingerprinting
};
const fingerprintService = new FingerprintService(options);
TraceJS now provides enhanced customization capabilities for specific fingerprinting modules.
Control exactly which battery data is collected and how it's processed:
import { FingerprintService, BatteryOptions, BatteryData } from 'tracejs';
const batteryOptions: BatteryOptions = {
// Select which properties to include (all true by default)
includeCharging: true,
includeLevel: true,
includeChargingTime: true,
includeDischargingTime: true,
// Privacy enhancement - round battery level to nearest 10%
anonymizeLevel: true,
// Enable real-time battery status tracking
trackStatusChanges: true,
// Optional callback for battery changes
onBatteryChange: (batteryData: BatteryData) => {
console.log('Battery status changed:', batteryData);
},
// Override the fingerprint strength score (optional)
customStrengthScore: 5
};
const fingerprintService = new FingerprintService({
battery: batteryOptions
});
// Alternatively, you can listen for battery changes after initialization
const removeListener = fingerprintService.onBatteryChange((batteryData: BatteryData) => {
console.log('Battery update:', batteryData);
});
// Later, to stop listening:
removeListener();
TraceJS can now create fingerprints based on user behavior patterns, providing much stronger identification:
import { FingerprintService, BehaviorOptions, BehaviorProfile } from 'tracejs';
const behaviorOptions: BehaviorOptions = {
// Enable specific tracking methods
trackMouse: true,
trackKeyboard: true,
trackTouch: true,
// Configure privacy level
privacyMode: 'balanced', // 'minimal', 'balanced', or 'full'
// Configure data collection
sampleRate: 100, // milliseconds between samples
trainingDuration: 10000, // how long to collect data before generating profile (ms)
// Receive updates when profile is created
onProfileUpdate: (profile: BehaviorProfile) => {
console.log('User behavior profile updated:', profile);
}
};
const fingerprintService = new FingerprintService({
behavior: behaviorOptions
});
// Or listen for profile updates separately
const cleanup = fingerprintService.onBehaviorProfileUpdate((profile) => {
console.log('New behavior profile:', profile);
// Access specific metrics
if (profile.mouse?.averageSpeed) {
console.log('Mouse speed:', profile.mouse.averageSpeed);
}
if (profile.keyboard?.typingSpeed) {
console.log('Typing speed:', profile.keyboard.typingSpeed);
}
});
// Call cleanup when done to remove event listeners
cleanup();
Assess the quality and uniqueness of your fingerprint:
import { FingerprintService } from 'tracejs';
const fingerprintService = new FingerprintService();
// Generate a fingerprint
const fingerprint = await fingerprintService.generateFingerprint();
// Analyze its entropy and uniqueness
const analysis = await fingerprintService.analyzeFingerprint();
console.log(`Entropy: ${analysis.entropyBits} bits`);
console.log(`Quality: ${analysis.quality.rating}`);
console.log(`Description: ${analysis.quality.description}`);
// Adjust your fingerprinting methods based on the analysis
if (analysis.entropyBits < 40) {
console.log('Consider enabling additional fingerprinting methods for stronger identification');
}
TraceJS provides fingerprint consistency suitable for authentication workflows:
import { FingerprintService } from 'tracejs';
// Initialize the fingerprint service
const fingerprintService = new FingerprintService();
// On user login, generate a fingerprint
const loginFingerprint = await fingerprintService.generateFingerprint();
console.log('Login Fingerprint:', loginFingerprint);
// Send to your backend along with credentials
await loginUser(username, password, loginFingerprint);
// Later, on the same device (even days/weeks later)
// The fingerprint will remain consistent
const logoutFingerprint = await fingerprintService.generateFingerprint();
console.log('Logout Fingerprint:', logoutFingerprint);
// loginFingerprint === logoutFingerprint (unless hardware/browser changes significantly)
// Use for logout authentication
await logoutUser(sessionToken, logoutFingerprint);
How the consistency system works:
- Fingerprints are cached locally for 30 days by default
- Behavioral profiles remain stable between sessions
- Hardware-specific characteristics provide long-term stability
- Cache is safely invalidated if hardware or browser changes significantly
- Origin-specific cache keys prevent cross-site tracking
Ensure GDPR, CCPA, and other privacy regulation compliance:
import { FingerprintService, ConsentOptions, ConsentCategory } from 'tracejs';
const consentOptions: ConsentOptions = {
// Automatically detect user's region based on locale
autoDetectRegion: true,
// Map fingerprinting methods to consent categories
categoryMapping: {
battery: 'functionality',
screen: 'functionality',
canvas: 'analytics',
audio: 'analytics',
behavior: 'personalization'
},
// Define required categories that don't need consent
requiredCategories: ['essential'],
// Get notifications when consent changes
onConsentChange: (categories) => {
console.log('Consent updated:', categories);
}
};
const fingerprintService = new FingerprintService({
battery: true,
screen: true,
behavior: true,
consent: consentOptions
});
// Get the consent manager to interact with it
const consentManager = fingerprintService.getConsentManager();
// Check if consent has expired
if (consentManager?.needsConsentRenewal()) {
// Show consent UI to user
showConsentForm();
}
// Update consent when user makes choices
function onUserConsentFormSubmit(choices) {
consentManager?.updateMultipleConsent({
functionality: choices.includes('functionality'),
analytics: choices.includes('analytics'),
advertising: choices.includes('advertising'),
personalization: choices.includes('personalization')
});
}
// Get current consent state
const consentState = consentManager?.getConsentState();
console.log('Current consent:', consentState);
constructor(options: FingerprintOptions = {})
Options:
battery
: boolean | BatteryOptions (default: true) - Enable/disable battery fingerprinting or customize itscreen
: boolean (default: true) - Enable/disable screen fingerprinting
async generateFingerprint(): Promise<string>
Returns a unique hash representing the device fingerprint.
async getDetailedFingerprint(): Promise<{
fingerprint: string;
characteristics: Partial<BrowserCharacteristics>;
strength: FingerprintStrength;
}>
Returns detailed information about the fingerprint, including:
- The fingerprint hash
- Collected characteristics
- Fingerprint strength assessment
onBatteryChange(listener: (data: BatteryData) => void): (() => void) | null
Registers a listener for battery status changes. Returns a function to remove the listener, or null if battery fingerprinting is disabled.
Configure the battery fingerprinting module:
interface BatteryOptions {
// Which battery properties to include in fingerprinting
includeCharging?: boolean; // Include charging status
includeLevel?: boolean; // Include battery level
includeChargingTime?: boolean; // Include time until fully charged
includeDischargingTime?: boolean; // Include time until battery depleted
// Optional anonymization settings
anonymizeLevel?: boolean; // Round battery level to nearest 10%
// Event tracking options
trackStatusChanges?: boolean; // Track battery status changes
onBatteryChange?: (batteryData: BatteryData) => void; // Callback for changes
// Custom strength scoring
customStrengthScore?: number; // Override default strength score
}
// The BatteryData type provides a type-safe structure for battery information
interface BatteryData {
charging?: boolean; // Whether the device is charging
level?: number; // Battery level between 0 and 1
chargingTime?: number; // Seconds until fully charged
dischargingTime?: number; // Seconds until battery depleted
}
The following characteristics may be collected:
userAgent
: Browser user agent stringlanguage
: Browser languageplatform
: Operating system platformhardwareConcurrency
: Number of logical processorsdeviceMemory
: Amount of device memorytimezone
: User's timezonetouchPoints
: Maximum touch pointsgpuVendor
: GPU vendor informationgpuRenderer
: GPU renderer informationcanvas
: Canvas fingerprintaudio
: Audio capabilities- And more...
TraceJS provides utilities to maintain consistency in fingerprints:
// These are typically used internally, but can be accessed for custom implementations
import { saveToCache, getFromCache, generateCacheKey } from 'tracejs/utils/cache';
// Generate a consistent cache key for your application
const cacheKey = generateCacheKey('my_feature');
// Save data to the cache (persists for 30 days by default)
saveToCache(cacheKey, { userData: 'example' });
// Retrieve cached data
const cachedData = getFromCache(cacheKey);
console.log(cachedData); // { userData: 'example' } or null if expired/not found
// Retrieve with custom validity period (in milliseconds)
const cachedDataWithCustomValidity = getFromCache(cacheKey, 60 * 60 * 1000); // 1 hour
TraceJS is designed with privacy in mind:
- No personal data collection
- No cross-site tracking
- No persistent storage
- Transparent fingerprinting methods
- Compliant with privacy regulations
We welcome contributions to TraceJS! Here's how you can help:
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Install dependencies (
npm install
) - Make your changes
- Run tests (
npm test
) - Ensure linting passes (
npm run lint
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
# Clone the repository
git clone https://github.com/ElhamDevelopmentStudio/tracejs.git
# Install dependencies
npm install
# Build the project
npm run build
# Run tests
npm test
# Run linting
npm run lint
- Follow TypeScript best practices
- Use ESLint for code linting
- Write comprehensive tests for new features
- Document new functionality
- Follow semantic versioning
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Elhamullah Hossaini
- Report issues on GitHub Issues
- For security issues, please email security@tracejs.com
- Join our community discussions on GitHub Discussions
- Thanks to all contributors who have helped shape TraceJS
- Special thanks to the open-source community for their valuable feedback and contributions