How to Use CreepJS to Bypass Browser Fingerprinting


Vilius Dumcius
Key Takeaways
-
CreepJS shows where your browser fingerprints are exposed.
-
CreepJS integrates well with popular browser automation tools for scraping, testing, or research.
-
CreepJS helps developers inspect real browser environments to validate spoofing tools or test privacy setups.
In This Article
Every time you open a browser and visit a website, your device leaves behind tiny marks. These marks form a digital ID called a browser fingerprint. Many websites use this ID to track, identify, or analyze users.
CreepJS is a tool that helps users defend against this kind of tracking. It analyzes how the browser behaves by showing exposed details to each tracking element. After that, you can use specific tools to make it harder for websites to recognize you in different sessions.
Here, you will learn what browser fingerprinting is, how CreepJS works, and how developers can use it safely and effectively.
What is Browser Fingerprinting?
Browser fingerprinting is a method used by websites to collect details about your device and browser. These details can include screen size, installed fonts, plugins, system time zone, GPU model, and much more. When combined, these traits form a browser fingerprint that’s uniquely yours.
Technically, these traits are collected using scripts. The collected data is run through hashing algorithms, which turn it into a fingerprint ID. It essentially functions as a digital label, tracking you across various websites, even without cookies.
Here are some common browser fingerprinting techniques:
- Canvas fingerprinting (drawing invisible images)
- Font detection and plugin checks
- Audio context fingerprinting
- Time zone and language settings
- User-agent and OS data
- Web graphics library fingerprints
Websites use browser fingerprints to detect fraud, stop bots, and serve targeted content. But they can also track users without their consent.
That’s where tools like CreepJS come in handy, analyzing where you’re exposed. Then, you can use browser automation tools to tweak those browser fingerprints so they don’t trace back to you.
Introduction to CreepJS
CreepJS is an open-source fingerprint analysis tool. It’s built on top of Puppeteer, one of the most popular browser automation tools. In crude terms, CreepJS shows the data that your browser exposes to scripts.
Once you have analyzed the fingerprint data, you can use browser automation tools like Puppeteer to modify the browser fingerprints with plugins to help you browse more privately.
It works by tweaking various parts of the browser environment, such as:
- Canvas data
- Audio signals
- Plugin lists
- Fonts
- WebGL fingerprints
These tweaks help prevent your browser from being uniquely identified. CreepJS is especially useful in security testing, research, and browser automation tools.
Setting Up Puppeteer with Stealth Plugin for Fingerprint Spoofing
Here, we will cover the necessary tools and provide a working script to spoof browser fingerprints using Puppeteer and the stealth plugin.
Before you start, install the following:
- Node.js: a JavaScript runtime environment that allows you to run scripts locally.
- npm: Node’s package manager used to install libraries such as Puppeteer.
- Puppeteer: a headless browser automation library built by Google.
- puppeteer-extra and puppeteer-extra-plugin-stealth: tools that add fingerprint spoofing capabilities to Puppeteer.
How to Install It
In your terminal, run this command:
npm install puppeteer-extra puppeteer-extra-plugin-stealth
Note: if Puppeteer is not included in your package, you can also run:
npm install puppeteer
Example Setup Script
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
puppeteer.use(StealthPlugin());
(async () => {
const browser = await puppeteer.launch({
headless: false // Set to true if you don't need to see the browser
});
const page = await browser.newPage();
await page.goto('https://abrahamjuliot.github.io/creepjs/');
// Wait for 10 seconds using a Promise
await page.goto('https://abrahamjuliot.github.io/creepjs/', {
waitUntil: 'networkidle2'
});
await new Promise(resolve => setTimeout(resolve, 10000));
// Take a screenshot of the page
await page.screenshot({ path: 'creepjs_screenshot.png' });
await browser.close();
})();
This script launches a new browser, spoofs the browser environment, and opens a website with altered browser fingerprint data. If you wish, you can modify it even further for scraping, automation, or privacy testing.
How CreepJS Can Be Used to Bypass Fingerprinting
First of all, CreepJS is a browser fingerprint analysis tool - it doesn’t spoof fingerprints itself but instead reveals what data your browser exposes. Developers and researchers use it to inspect how detectable a browser is based on traits like:
- Canvas rendering output
- Audio context properties
- WebGL fingerprinting
- Plugin and font detection
- Timezone, language, and device data.
These details are gathered and displayed in structured form, allowing users to understand how unique their browser appears to tracking systems.
Below is a hypothetical example of how fingerprinting traits can change when spoofing is applied using tools such as puppeteer-extra-plugin-stealth.
1. Default Browser Fingerprinting
{
"canvas": "hash123abc",
"webgl": "Intel HD Graphics 4000",
"plugins": ["Chrome PDF Viewer", "Native Client"],
"fonts": ["Arial", "Verdana"],
"timezone": "UTC+3"
}
2. With a Fingerprint Spoofing Tool
{
"canvas": "hash789xyz",
"webgl": "AMD Radeon 5600",
"plugins": [],
"fonts": ["Roboto", "Courier"],
"timezone": "UTC-5"
}
These changes result in completely different browser fingerprinting data, which makes it difficult for tracking systems to link you to your past activities.
So, CreepJS doesn’t spoof the fingerprint itself. Instead, it reveals what’s exposed, and then you can use other tools for actual spoofing, such as puppeteer-extra-plugin-stealth.
These tools use custom scripts behind the scenes to adjust each browser trait. The goal is not just to hide but to look believable at the same time. That means that the analyzed browser fingerprint still appears normal, even though it’s fake.
If you want to see how a fingerprinting checker works, try this TCP/IP fingerprint checker tool .
Here’s an easy setup for fingerprint spoofing and checking:
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
puppeteer.use(StealthPlugin());
// ===== CUSTOMIZABLE FINGERPRINT CONFIGURATION =====
const FINGERPRINT_CONFIG = {
// User Agent - Customize to match different browsers/OS
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
// Screen dimensions
screen: {
width: 1920,
height: 1080,
colorDepth: 24,
pixelDepth: 24
},
// Viewport size
viewport: {
width: 1366,
height: 768
},
// Timezone spoofing
timezone: 'America/New_York', // Options: 'Europe/London', 'Asia/Tokyo', 'America/Los_Angeles', etc.
// Language settings
languages: ['en-US', 'en'],
// Geolocation (if enabled)
geolocation: {
latitude: 40.7128,
longitude: -74.0060,
accuracy: 100
},
// Canvas fingerprint spoofing
spoofCanvas: true,
// WebGL fingerprint spoofing
spoofWebGL: true,
webglVendor: 'Intel Inc.',
webglRenderer: 'Intel(R) UHD Graphics 620',
// Memory spoofing
deviceMemory: 8, // GB
hardwareConcurrency: 4, // CPU cores
// Platform spoofing
platform: 'Win32',
// Enable/disable various spoofing methods
enableSpoofing: {
userAgent: true,
screen: true,
timezone: true,
canvas: true,
webgl: true,
fonts: true,
plugins: true,
hardware: true,
battery: true
}
};
(async () => {
console.log('🎭 Starting Customizable Fingerprint Spoofer...');
console.log('📋 Current Configuration:');
console.log(JSON.stringify(FINGERPRINT_CONFIG, null, 2));
const browser = await puppeteer.launch({
headless: false,
slowMo: 50,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-blink-features=AutomationControlled',
`--lang=${FINGERPRINT_CONFIG.languages[0]}`
]
});
const page = await browser.newPage();
// Apply fingerprint spoofing
await applyFingerprintSpoofing(page, FINGERPRINT_CONFIG);
console.log('🔍 Navigating to CreepJS...');
try {
await page.goto('https://abrahamjuliot.github.io/creepjs/');
console.log('✅ Page loaded successfully');
console.log('⏳ Waiting 20 seconds for fingerprint analysis...');
// Wait for analysis to complete
await new Promise(resolve => setTimeout(resolve, 20000));
// Extract some basic results
const results = await page.evaluate(() => {
const trustScore = document.querySelector('#fingerprint-data .visitor-entropy');
const lies = Array.from(document.querySelectorAll('.lies')).map(el => el.textContent.trim());
return {
trustScore: trustScore ? trustScore.textContent.trim() : 'Not found',
detectedLies: lies.length > 0 ? lies : ['None detected'],
url: window.location.href,
userAgent: navigator.userAgent
};
});
console.log('📊 Quick Results:');
console.log(`Trust Score: ${results.trustScore}`);
console.log(`Detected Issues: ${results.detectedLies.length > 1 ? results.detectedLies.join(', ') : 'None'}`);
// Take screenshot
await page.screenshot({
path: 'fingerprint_spoofed_results.png',
fullPage: true
});
console.log('📸 Screenshot saved to: fingerprint_spoofed_results.png');
console.log('🎯 Analysis complete! Check the browser window and screenshot for detailed results.');
} catch (error) {
console.error('❌ Error:', error.message);
}
// Keep browser open for manual inspection
console.log('🔍 Browser will remain open for manual inspection. Close when done.');
// Uncomment the line below to auto-close after 60 seconds
// setTimeout(() => browser.close(), 60000);
})();
// ===== FINGERPRINT SPOOFING FUNCTIONS =====
async function applyFingerprintSpoofing(page, config) {
console.log('🎭 Applying fingerprint spoofing...');
// Set User Agent
if (config.enableSpoofing.userAgent) {
await page.setUserAgent(config.userAgent);
console.log('✅ User Agent spoofed');
}
// Set Viewport
await page.setViewport(config.viewport);
// Set Geolocation
await page.setGeolocation(config.geolocation);
// Set Language
await page.setExtraHTTPHeaders({
'Accept-Language': config.languages.join(',')
});
// Advanced spoofing via page.evaluateOnNewDocument
await page.evaluateOnNewDocument((config) => {
// Screen spoofing
if (config.enableSpoofing.screen) {
Object.defineProperty(screen, 'width', { value: config.screen.width });
Object.defineProperty(screen, 'height', { value: config.screen.height });
Object.defineProperty(screen, 'colorDepth', { value: config.screen.colorDepth });
Object.defineProperty(screen, 'pixelDepth', { value: config.screen.pixelDepth });
}
// Hardware spoofing
if (config.enableSpoofing.hardware) {
Object.defineProperty(navigator, 'deviceMemory', { value: config.deviceMemory });
Object.defineProperty(navigator, 'hardwareConcurrency', { value: config.hardwareConcurrency });
Object.defineProperty(navigator, 'platform', { value: config.platform });
}
// Timezone spoofing
if (config.enableSpoofing.timezone) {
const originalDateTimeFormat = Intl.DateTimeFormat;
Intl.DateTimeFormat = function(...args) {
if (args.length === 0 || (args[0] && args[0].timeZone === undefined)) {
args[1] = args[1] || {};
args[1].timeZone = config.timezone;
}
return new originalDateTimeFormat(...args);
};
// Spoof Date.prototype.getTimezoneOffset
const originalGetTimezoneOffset = Date.prototype.getTimezoneOffset;
Date.prototype.getTimezoneOffset = function() {
// Return offset for spoofed timezone (simplified)
const timezoneOffsets = {
'America/New_York': 300, // EST
'Europe/London': 0, // GMT
'Asia/Tokyo': -540, // JST
'America/Los_Angeles': 480 // PST
};
return timezoneOffsets[config.timezone] || originalGetTimezoneOffset.call(this);
};
}
// Canvas fingerprint spoofing
if (config.enableSpoofing.canvas) {
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData;
HTMLCanvasElement.prototype.toDataURL = function(...args) {
// Add slight noise to canvas output
const originalResult = originalToDataURL.apply(this, args);
return originalResult.replace(/.$/, Math.random().toString(36).substr(2, 1));
};
CanvasRenderingContext2D.prototype.getImageData = function(...args) {
const imageData = originalGetImageData.apply(this, args);
// Add minimal noise to image data
for (let i = 0; i < imageData.data.length; i += 4) {
if (Math.random() < 0.001) { // Very small chance to modify pixel
imageData.data[i] = Math.min(255, imageData.data[i] + Math.floor(Math.random() * 3) - 1);
}
}
return imageData;
};
}
// WebGL spoofing
if (config.enableSpoofing.webgl) {
const originalGetParameter = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function(parameter) {
if (parameter === 37445) { // UNMASKED_VENDOR_WEBGL
return config.webglVendor;
}
if (parameter === 37446) { // UNMASKED_RENDERER_WEBGL
return config.webglRenderer;
}
return originalGetParameter.call(this, parameter);
};
}
// Plugin spoofing
if (config.enableSpoofing.plugins) {
Object.defineProperty(navigator, 'plugins', {
value: [
{
name: 'Chrome PDF Plugin',
filename: 'internal-pdf-viewer',
description: 'Portable Document Format'
}
]
});
}
// Battery API spoofing
if (config.enableSpoofing.battery && 'getBattery' in navigator) {
const originalGetBattery = navigator.getBattery;
navigator.getBattery = async function() {
const battery = await originalGetBattery.call(this);
return {
...battery,
level: 0.85,
charging: true,
chargingTime: 3600,
dischargingTime: Infinity
};
};
}
// Languages spoofing
Object.defineProperty(navigator, 'languages', { value: config.languages });
Object.defineProperty(navigator, 'language', { value: config.languages[0] });
}, config);
console.log('✅ Advanced fingerprint spoofing applied');
}
// ===== USAGE INSTRUCTIONS =====
/*
HOW TO CUSTOMIZE:
1. CHANGE USER AGENT:
- Modify `FINGERPRINT_CONFIG.userAgent`
- Use different browser signatures from: https://www.whatismybrowser.com/guides/the-latest-user-agent/
2. CHANGE SCREEN RESOLUTION:
- Modify `FINGERPRINT_CONFIG.screen` values
- Common resolutions: 1920x1080, 1366x768, 1440x900
3. CHANGE TIMEZONE:
- Modify `FINGERPRINT_CONFIG.timezone`
- Valid zones: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
4. CHANGE LOCATION:
- Modify `FINGERPRINT_CONFIG.geolocation`
- Use coordinates from Google Maps
5. ENABLE/DISABLE SPOOFING:
- Toggle options in `FINGERPRINT_CONFIG.enableSpoofing`
6. WEBGL SPOOFING:
- Change webglVendor and webglRenderer to match different graphics cards
- Examples: "NVIDIA Corporation" / "GeForce GTX 1060"
TESTING DIFFERENT PROFILES:
- Create multiple config objects for different "personas"
- Test mobile vs desktop fingerprints
- Compare results with and without spoofing
*/
Use Cases for Developers and Researchers
CreepJS is a helpful tool in many development and research environments:
- Privacy exposure analysis. Developers use CreepJS to see what data their apps or browsers expose to fingerprinting scripts.
- Stealth plugin validation. Researchers can use CreepJS to verify whether spoofing tools (like stealth plugins or anti-detect browsers) are working as expected.
- Environment fingerprint comparison. QA teams can compare fingerprint outputs across different setups to understand behavioral differences in browser detection.
If you’re interested in exploring similar tools, check out our list of top anti-detect browsers .
Conclusion
CreepJS is a powerful tool for analyzing browser fingerprints. It lets users and developers understand what identifying traits are exposed to websites. While it doesn’t spoof or modify browser fingerprints, it’s an essential tool in testing and validating privacy setups or anti-fingerprinting tools.

Author
Vilius Dumcius
Product Owner
With six years of programming experience, Vilius specializes in full-stack web development with PHP (Laravel), MySQL, Docker, Vue.js, and Typescript. Managing a skilled team at IPRoyal for years, he excels in overseeing diverse web projects and custom solutions. Vilius plays a critical role in managing proxy-related tasks for the company, serving as the lead programmer involved in every aspect of the business. Outside of his professional duties, Vilius channels his passion for personal and professional growth, balancing his tech expertise with a commitment to continuous improvement.
Learn More About Vilius Dumcius