> ## Content Index
> Fetch the complete content index at: https://roundproxies.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# How to use CreepJS in 2026: Bypass browser fingerprinting
- URL: https://roundproxies.com/blog/creepjs/
- Published: 2025-12-02T21:41:24.000Z
- Updated: 2026-09-23T13:04:39.000Z
- Description: How to bypass CreepJS browser fingerprinting: read the lie detection report and fix the leaks that give away Puppeteer, Playwright, and Selenium.
- Author: Marius Bernard
- Tags: CreepJs, FingerprintJS, #dated-6921c9cbcfe027cead460d8b

You launch Playwright with a stealth plugin, point it at a protected site, and still get blocked. CreepJS is how you find out why. It runs the same class of JavaScript checks an anti-bot vendor runs, then prints a report of every signal your browser exposes and every place those signals contradict each other.

That second part is what separates it from an ordinary fingerprint viewer. Most tools answer one question: how unique is this browser? CreepJS asks whether the browser is telling the truth. Override `navigator.userAgent` or patch `HTMLCanvasElement.prototype.toDataURL` and the value you hand back can look perfectly ordinary on its own, while the property descriptor, the `toString()` output, and the same computation run inside a Web Worker all disagree with it. CreepJS treats that disagreement as a lie and your trust score drops.

This matters for anyone doing browser automation at scale. Raw Puppeteer, Selenium, and Playwright fail badly, and patching the three or four obvious leaks does not make the rest of the fingerprint believable. Stealth plugins help, but they tend to trade one tell for another: the value gets fixed, the tampering evidence stays.

Below I walk through how to read a CreepJS report section by section, what canvas, WebGL, audio, font, and navigator signals actually reveal, how the common headless setups score, and how to bypass CreepJS browser fingerprinting checks in a way that holds up on real targets. I'll also be blunt about the limit: a clean score is a diagnostic, not a guarantee. Production anti-bot systems weigh TLS fingerprints, IP reputation, and behavior alongside the JavaScript layer. Failing CreepJS is a reliable sign you'll be blocked. Passing it only means you cleared the first gate.

**Before you test.** The only official deployment is the GitHub Pages one at [abrahamjuliot.github.io/creepjs](https://abrahamjuliot.github.io/creepjs). Lookalike `.com` and `.org` domains are unauthorized mirrors, and you're handing them your fingerprint data.

## What CreepJS is and why scrapers run it

CreepJS is an open-source fingerprinting audit tool that tells you how obviously automated your browser looks. Abraham Juliot built it to expose leaks in anti-fingerprinting extensions and privacy browsers, but anyone working on a CreepJS bypass for browser fingerprinting uses it in reverse: point a Puppeteer, Playwright, or Selenium session at it and read back the same signals an anti-bot vendor would collect.

Most fingerprint demos answer one question, how unique is this browser. CreepJS asks a second one that matters far more for scraping: is this browser telling the truth? That difference is why a setup can score "rare" on a generic fingerprint page and still get flagged in the first second of a CreepJS run.

### How the lie detection works

The collection stage is ordinary. CreepJS reads Canvas and WebGL output, audio processing results, installed fonts, `navigator` properties, screen dimensions, timezone, and language, then hashes chunks of that data into comparable strings. The interesting part is what it does next.

It asks for the same fact twice, from sources that should agree, and watches for disagreement. A property read directly versus the same value derived indirectly. A computation run on the main thread versus the identical computation run inside a Web Worker, which most patching scripts never touch. When the two answers differ, CreepJS records a lie and the trust score drops.

It also inspects *how* a value was produced. Overriding `navigator.userAgent` or `HTMLCanvasElement.prototype.toDataURL` is the standard move for stealth plugins, and it leaves structural evidence: property descriptors that no longer match a native implementation, and `.toString()` output that reads as JavaScript instead of native code. You do not need a database of correct values to catch that. You only need the browser to contradict itself.

### What the report actually tells you

The page returns a trust score, a list of detected lies with the API each one came from, and separate headless and stealth ratings that estimate whether the session is an automated browser pretending to be a desktop one. Read the lies list first. The score is a summary; the lies list names the specific API you broke, which is the thing you can go fix.

Raw Playwright, Puppeteer, and Selenium fail badly here, and patching a handful of obvious leaks rarely helps, because the fingerprint has to hang together as a whole. Stealth plugins and patched builds improve the numbers while often leaving fresh inconsistencies of their own. Tools that shape the browser deeper in the stack do better because their signals line up without needing JavaScript overrides at runtime.

### Where CreepJS stops being useful

A clean CreepJS report is not a guarantee. Real anti-bot systems also weigh your TLS fingerprint, IP reputation, request cadence, and mouse and scroll behavior, none of which CreepJS measures. I treat it as a bench test: if a target blocks you and your CreepJS run is clean, stop rewriting JavaScript patches and go look at your proxies and your HTTP client. If the report is full of lies, fix those before you touch anything else, because no proxy pool rescues a browser that admits it is instrumented.

**Use the official deployment.** The project README warns that the only sanctioned live version is on GitHub Pages at [abrahamjuliot.github.io/creepjs](https://abrahamjuliot.github.io/creepjs), and treats lookalike `.com` or `.org` domains as unauthorized mirrors that may harvest the fingerprint data you submit. Run your tests against the GitHub Pages build.

## Understanding CreepJS Fingerprinting Techniques

CreepJS goes further than collecting basic browser data: its detection methods catch stealth automation tools too.

### Canvas Fingerprinting

Canvas fingerprinting draws invisible graphics using HTML5 Canvas API. Different hardware and drivers render pixels slightly differently.

CreepJS captures this rendering output and creates a hash. Two identical browsers on different machines produce different hashes due to hardware variations.

This technique exposes:

- Graphics card model
- Driver version differences
- Operating system rendering variations
- Anti-aliasing implementation

### WebGL Fingerprinting

WebGL accesses your GPU directly for 3D rendering. It reveals detailed hardware information that's nearly impossible to spoof convincingly.

CreepJS extracts WebGL parameters including GPU vendor, renderer model, and supported extensions. These details remain consistent across sessions.

Headless browsers often use software rendering instead of hardware acceleration. This creates detectable inconsistencies.

### Audio Context Fingerprinting

The Web Audio API processes sound differently on each device. Hardware variations, audio drivers, and DSP implementations all affect output.

CreepJS generates audio signals and measures processing characteristics. The results form another unique identifier.

This works even when no actual sound plays. The processing happens entirely in memory.

### Navigator Object Analysis

The `navigator` object exposes browser and system details through JavaScript. CreepJS reads dozens of properties from this object.

Key properties include:

- User agent string
- Platform and OS
- Hardware concurrency (CPU cores)
- Device memory
- WebDriver presence flag

Automation tools often modify these properties incorrectly. CreepJS detects inconsistencies between claimed values and actual behavior.

## Setting Up CreepJS for Local Testing

You can test CreepJS three ways: using the live demo, running it locally, or integrating it into automation scripts.

### Using the Live Demo

The simplest method is visiting the official CreepJS site at `https://abrahamjuliot.github.io/creepjs/`.

Wait 5-10 seconds for all tests to complete. The page displays fingerprint data, trust scores, and detected anomalies.

This works for quick checks but doesn't integrate with automation tools.

### Installing CreepJS Locally

Clone the GitHub repository to run CreepJS on your own server:

```bash
git clone https://github.com/abrahamjuliot/creepjs.git
cd creepjs
pnpm install
pnpm build:dev
pnpm start

```

The local server runs on `localhost:8000`. You can now test against your own CreepJS instance.

Local hosting lets you modify detection rules or add custom tests. It also works offline for development environments.

### Running CreepJS in Node.js

For programmatic testing, you can import CreepJS as a module:

```bash
npm install creepjs

```

However, CreepJS primarily runs in browser environments. Server-side usage requires a headless browser to execute the JavaScript.

## How to Use CreepJS with Browser Automation Tools

Testing automation tools with CreepJS reveals which browser properties leak information. Each tool has different detection signatures.

The standard workflow:

1. Launch automated browser
2. Navigate to CreepJS test page
3. Wait for tests to complete
4. Capture results screenshot
5. Analyze trust scores and detected lies

Let's implement this for each major automation framework.

## Testing Puppeteer with CreepJS

Puppeteer controls Chrome or Chromium through the DevTools Protocol. Without modifications, it's easily detected by CreepJS.

### Basic Puppeteer Test

Install Puppeteer first:

```bash
npm install puppeteer

```

Here's a basic test script:

```javascript
const puppeteer = require('puppeteer');

async function testCreepJS() {
  const browser = await puppeteer.launch({
    headless: false
  });
  
  const page = await browser.newPage();
  await page.goto('https://abrahamjuliot.github.io/creepjs/');
  
  // Wait for tests to complete
  await page.waitForTimeout(10000);
  
  // Take screenshot
  await page.screenshot({
    path: 'puppeteer-basic.png',
    fullPage: true
  });
  
  await browser.close();
}

testCreepJS();

```

This script launches Chromium, navigates to CreepJS, and captures results after 10 seconds.

The screenshot will show 100% headless detection and multiple red flags. Puppeteer's default configuration is highly detectable.

### Adding Stealth Plugin

The `puppeteer-extra-plugin-stealth` improves detection evasion:

```bash
npm install puppeteer-extra puppeteer-extra-plugin-stealth

```

Updated script with stealth:

```javascript
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');

puppeteer.use(StealthPlugin());

async function testCreepJSStealth() {
  const browser = await puppeteer.launch({
    headless: false,
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-blink-features=AutomationControlled'
    ]
  });
  
  const page = await browser.newPage();
  
  // Set realistic viewport
  await page.setViewport({
    width: 1920,
    height: 1080
  });
  
  await page.goto('https://abrahamjuliot.github.io/creepjs/', {
    waitUntil: 'networkidle2'
  });
  
  await page.waitForTimeout(10000);
  
  await page.screenshot({
    path: 'puppeteer-stealth.png',
    fullPage: true
  });
  
  await browser.close();
}

testCreepJSStealth();

```

The stealth plugin patches many detection vectors. It removes the `navigator.webdriver` flag, fixes Chrome runtime properties, and normalizes permission APIs.

Results improve dramatically. Headless detection drops from 100% to around 30-40%.

## Testing Playwright with CreepJS

Playwright supports Chromium, Firefox, and WebKit. Its fingerprint differs from Puppeteer's but is still detectable without modifications.

### Basic Playwright Implementation

Install Playwright:

```bash
pip install playwright
playwright install chromium

```

Python test script:

```python
from playwright.sync_api import sync_playwright
import time

def test_creepjs_playwright():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        context = browser.new_context(
            viewport={'width': 1920, 'height': 1080}
        )
        page = context.new_page()
        
        page.goto('https://abrahamjuliot.github.io/creepjs/')
        time.sleep(10)
        
        page.screenshot(path='playwright-basic.png', full_page=True)
        browser.close()

test_creepjs_playwright()

```

This script produces detection rates similar to basic Puppeteer. CreepJS identifies Playwright through automation flags and inconsistent property values.

### Using Playwright-Stealth

The `playwright-stealth` library applies evasion techniques:

```bash
pip install playwright-stealth

```

Enhanced script:

```python
from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync
import time

def test_creepjs_stealth():
    with sync_playwright() as p:
        browser = p.chromium.launch(
            headless=False,
            args=[
                '--disable-blink-features=AutomationControlled',
                '--disable-dev-shm-usage'
            ]
        )
        
        context = browser.new_context(
            viewport={'width': 1920, 'height': 1080},
            user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        )
        
        page = context.new_page()
        stealth_sync(page)
        
        page.goto('https://abrahamjuliot.github.io/creepjs/')
        time.sleep(10)
        
        page.screenshot(path='playwright-stealth.png', full_page=True)
        browser.close()

test_creepjs_stealth()

```

The `stealth_sync` function patches WebDriver flags, Chrome runtime, and navigator properties before page load.

Detection rates drop but don't disappear entirely. Advanced analysis still reveals automation signatures.

## Testing Selenium with CreepJS

Selenium is the oldest browser automation framework. It's also the most detectable without proper configuration.

### Standard Selenium Test

Install dependencies:

```bash
pip install selenium

```

Download ChromeDriver matching your Chrome version from the official site.

Basic test:

```python
from selenium import webdriver
import time

def test_creepjs_selenium():
    driver = webdriver.Chrome()
    driver.get('https://abrahamjuliot.github.io/creepjs/')
    
    time.sleep(10)
    driver.save_screenshot('selenium-basic.png')
    driver.quit()

test_creepjs_selenium()

```

CreepJS immediately detects Selenium. The `navigator.webdriver` property is set to `true`, and multiple Chrome DevTools flags expose automation.

Results show 100% headless detection with extensive red warnings.

### Undetected ChromeDriver

The `undetected-chromedriver` package specifically targets detection bypass:

```bash
pip install undetected-chromedriver

```

Improved implementation:

```python
import undetected_chromedriver as uc
import time

def test_creepjs_undetected():
    options = uc.ChromeOptions()
    options.add_argument('--disable-blink-features=AutomationControlled')
    
    driver = uc.Chrome(options=options, use_subprocess=True)
    driver.get('https://abrahamjuliot.github.io/creepjs/')
    
    time.sleep(10)
    driver.save_screenshot('selenium-undetected.png')
    driver.quit()

test_creepjs_undetected()

```

This package applies several patches, including:

- Removing webdriver flags
- Modifying Chrome DevTools protocol
- Normalizing navigator properties
- Fixing permission API responses

Detection drops. Many sites that block standard Selenium allow undetected-chromedriver through.

## Analyzing CreepJS Results and Trust Scores

Understanding CreepJS output helps identify which fingerprint components need improvement.

### Trust Score Calculation

CreepJS assigns a trust score from 0-100%. Higher scores indicate more natural browser fingerprints.

The score considers:

- Consistency between claimed and actual properties
- Detection of JavaScript tampering
- Presence of automation flags
- Unusual API responses
- Fingerprint uniqueness

Scores above 90% suggest a convincing human-like fingerprint. Below 50% indicates obvious automation or spoofing.

### Lie Detection

CreepJS highlights "lies" when detected values don't match claimed values.

Common lies include:

- User agent claims Windows but APIs reveal Linux
- Headless flag present despite browser window visible
- Canvas rendering inconsistent with claimed GPU
- Screen dimensions don't match reported values

Each lie increases suspicion and lowers trust scores.

### Crowd Blending Score

This metric compares your fingerprint against CreepJS's database of known fingerprints.

Highly unique fingerprints stand out as unusual. Common fingerprints blend with the crowd.

Perfect spoofing requires looking common, not unique. Avoid rare configurations that draw attention.

## Advanced Fingerprint Spoofing Techniques

Basic stealth plugins help but don't eliminate detection. Stronger techniques require deeper modifications.

### Custom User Agent Rotation

Different browsers have distinct fingerprint signatures. Rotating user agents creates variety but requires matching all related properties.

Example configuration:

```javascript
const profiles = [
  {
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    platform: 'Win32',
    vendor: 'Google Inc.',
    deviceMemory: 8,
    hardwareConcurrency: 4
  },
  {
    userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
    platform: 'MacIntel',
    vendor: 'Apple Computer, Inc.',
    deviceMemory: 8,
    hardwareConcurrency: 8
  }
];

function applyProfile(page, profile) {
  await page.setUserAgent(profile.userAgent);
  
  await page.evaluateOnNewDocument((profile) => {
    Object.defineProperty(navigator, 'platform', {
      get: () => profile.platform
    });
    Object.defineProperty(navigator, 'vendor', {
      get: () => profile.vendor
    });
    Object.defineProperty(navigator, 'deviceMemory', {
      get: () => profile.deviceMemory
    });
    Object.defineProperty(navigator, 'hardwareConcurrency', {
      get: () => profile.hardwareConcurrency
    });
  }, profile);
}

```

This ensures all properties match the claimed user agent. Inconsistencies between user agent and actual properties trigger lie detection.

### Canvas Noise Injection

Adding subtle noise to Canvas output makes fingerprints less consistent while maintaining visual accuracy:

```javascript
await page.evaluateOnNewDocument(() => {
  const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
  const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData;
  
  HTMLCanvasElement.prototype.toDataURL = function(...args) {
    const data = originalToDataURL.apply(this, args);
    // Add minimal random variation
    return data.slice(0, -5) + Math.random().toString(36).substr(2, 5);
  };
  
  CanvasRenderingContext2D.prototype.getImageData = function(...args) {
    const imageData = originalGetImageData.apply(this, args);
    
    // Modify 0.1% of pixels randomly
    for (let i = 0; i < imageData.data.length; i += 40) {
      if (Math.random() < 0.1) {
        imageData.data[i] += Math.floor(Math.random() * 3) - 1;
      }
    }
    
    return imageData;
  };
});

```

The noise is invisible to human eyes but prevents exact fingerprint matching across sessions.

### WebGL Parameter Spoofing

Changing WebGL parameters requires consistency with the claimed GPU model:

```javascript
await page.evaluateOnNewDocument(() => {
  const getParameter = WebGLRenderingContext.prototype.getParameter;
  
  WebGLRenderingContext.prototype.getParameter = function(parameter) {
    // UNMASKED_VENDOR_WEBGL
    if (parameter === 37445) {
      return 'Intel Inc.';
    }
    // UNMASKED_RENDERER_WEBGL  
    if (parameter === 37446) {
      return 'Intel(R) UHD Graphics 620';
    }
    
    return getParameter.call(this, parameter);
  };
});

```

Match these values to realistic GPU configurations. Claiming NVIDIA but having Intel rendering characteristics creates obvious lies.

### Timezone and Geolocation Alignment

Your timezone should match your claimed location. Mismatches appear suspicious:

```javascript
const config = {
  timezone: 'America/New_York',
  latitude: 40.7128,
  longitude: -74.0060
};

await page.evaluateOnNewDocument((config) => {
  // Override timezone
  const originalDateTimeFormat = Intl.DateTimeFormat;
  Intl.DateTimeFormat = function(...args) {
    if (!args[1] || !args[1].timeZone) {
      args[1] = args[1] || {};
      args[1].timeZone = config.timezone;
    }
    return new originalDateTimeFormat(...args);
  };
  
  // Override geolocation
  const originalGetCurrentPosition = navigator.geolocation.getCurrentPosition;
  navigator.geolocation.getCurrentPosition = function(success) {
    success({
      coords: {
        latitude: config.latitude,
        longitude: config.longitude,
        accuracy: 10
      }
    });
  };
}, config);

await page.setGeolocation(config);

```

Consistent location data across all APIs makes the fingerprint harder to flag.

## Integrating Proxies for Complete Anonymity

Fingerprint spoofing handles browser-level detection. Proxies handle network-level identification.

### Why Proxies Matter with CreepJS

CreepJS performs WebRTC leak tests that can expose your real IP address even behind VPNs. Proper proxy configuration prevents these leaks.

Network fingerprinting also examines:

- IP address location
- TCP/IP stack signatures
- HTTP header ordering
- TLS fingerprints

Proxies provide different IP addresses and network characteristics for each session.

### Residential Proxy Configuration

Residential proxies use real residential IP addresses from ISPs. They appear as genuine home internet connections.

For fingerprint testing and bypassing, residential proxies from [Roundproxies.com](https://roundproxies.com/) offer:

- Rotating residential IPs
- Geographic targeting
- HTTP/HTTPS support
- SOCKS5 protocol support

Integration with Puppeteer:

```javascript
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');

puppeteer.use(StealthPlugin());

async function testWithProxy() {
  const proxyServer = 'residential.roundproxies.com:12345';
  const proxyUsername = 'your-username';
  const proxyPassword = 'your-password';
  
  const browser = await puppeteer.launch({
    headless: false,
    args: [
      `--proxy-server=${proxyServer}`,
      '--no-sandbox'
    ]
  });
  
  const page = await browser.newPage();
  
  // Authenticate proxy
  await page.authenticate({
    username: proxyUsername,
    password: proxyPassword
  });
  
  await page.goto('https://abrahamjuliot.github.io/creepjs/');
  await page.waitForTimeout(10000);
  
  await page.screenshot({
    path: 'creepjs-with-proxy.png',
    fullPage: true
  });
  
  await browser.close();
}

testWithProxy();

```

The proxy provides a legitimate residential IP address. Combined with fingerprint spoofing, this produces a fingerprint closer to a real desktop session.

### Datacenter vs Residential Proxies

Datacenter proxies use IP addresses from data centers. They're faster and cheaper but more easily detected.

CreepJS doesn't directly test proxy type. However, sites that fingerprint deeply often maintain databases of datacenter IP ranges.

To reduce detection during CreepJS testing:

- Use residential proxies for realistic network fingerprints
- Rotate IPs between test sessions
- Match proxy location to timezone and geolocation settings

[Roundproxies.com](https://roundproxies.com/) offers both residential and datacenter proxies. Residential proxies work best for fingerprint testing because they match typical user network profiles.

### Mobile Proxies for Mobile Fingerprints

Testing mobile browser fingerprints requires mobile-specific network signatures. Mobile proxies route traffic through real mobile devices on carrier networks.

Mobile proxy setup:

```javascript
const mobileProxy = 'mobile.roundproxies.com:12345';

const browser = await puppeteer.launch({
  args: [`--proxy-server=${mobileProxy}`]
});

const page = await browser.newPage();

// Mobile user agent
await page.setUserAgent(
  'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15'
);

// Mobile viewport
await page.setViewport({
  width: 375,
  height: 812,
  isMobile: true,
  hasTouch: true
});

```

Mobile networks have different TCP/IP signatures than residential broadband. Using mobile proxies ensures network-level consistency with mobile browser fingerprints.

## Common CreepJS Detection Patterns

Understanding what CreepJS detects helps you avoid these patterns.

### Automation Flags

The most obvious detection vector is the `navigator.webdriver` flag. Modern browsers set this to `true` when controlled by automation.

Basic stealth plugins remove this flag. However, removing it creates its own pattern. Chrome 89+ should have this property even when `false`.

The solution is setting it to `false` rather than removing it entirely.

### Inconsistent Navigator Properties

Properties like `navigator.platform`, `navigator.userAgent`, and `navigator.vendor` must align logically.

Wrong:

```javascript
navigator.platform = 'Win32'
navigator.userAgent = '...Macintosh; Intel Mac OS X...'

```

This obvious lie triggers immediate detection. Platform should be `MacIntel` for macOS user agents.

### Chrome Runtime Leaks

Automation tools add properties to `window.chrome` that don't exist in normal browsers. CreepJS checks for these.

Proper stealth plugins normalize the chrome object structure to match genuine Chrome installations.

### Permission API Responses

Automated browsers handle permission requests differently than normal browsers. CreepJS tests permissions for notifications, geolocation, and other APIs.

Spoofing must implement realistic permission behaviors matching the claimed browser configuration.

## Troubleshooting Failed Fingerprint Tests

Even with stealth plugins, some configurations still fail CreepJS tests. Here's how to diagnose and fix issues.

### High Headless Detection

If CreepJS reports high headless percentage despite using stealth plugins:

1. Verify plugin installation and initialization
2. Check for outdated plugin versions
3. Review browser launch arguments
4. Test with `headless: false` to confirm detection sources

Some detection vectors only appear in headless mode. Testing with visible browser helps isolate issues.

### Low Trust Score

Trust scores below 50% indicate multiple problems:

1. Check for property inconsistencies (lies)
2. Verify user agent matches all related properties
3. Ensure timezone aligns with geolocation
4. Review canvas and WebGL configurations

Address each detected lie individually. Fixing lies systematically improves the trust score.

### WebRTC Leaks

WebRTC can expose your real IP even when using proxies. CreepJS tests for these leaks.

Disable WebRTC entirely if not needed:

```javascript
await page.goto('about:config');
await page.evaluate(() => {
  // Disable WebRTC
  RTCPeerConnection = undefined;
  RTCDataChannel = undefined;
});

```

Alternatively, configure WebRTC to only use proxy IPs through browser extensions or launch arguments.

### Canvas Fingerprint Uniqueness

Highly unique canvas fingerprints indicate hardware-specific rendering that's difficult to spoof.

Solutions:

- Use canvas noise injection
- Test on different hardware configurations
- Implement software rendering modes

The goal is consistency, not randomness. Random canvas values change on each load, which itself appears suspicious.

## Building Custom CreepJS Testing Scripts

For production use, build automated testing pipelines that regularly validate fingerprint configurations.

### Automated Test Suite

```javascript
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
const fs = require('fs');

puppeteer.use(StealthPlugin());

async function runCreepJSTest(config) {
  const browser = await puppeteer.launch({
    headless: false,
    args: [
      `--proxy-server=${config.proxy}`,
      '--no-sandbox',
      '--disable-setuid-sandbox'
    ]
  });
  
  const page = await browser.newPage();
  
  if (config.proxyAuth) {
    await page.authenticate(config.proxyAuth);
  }
  
  // Apply custom fingerprint
  await applyFingerprint(page, config.fingerprint);
  
  await page.goto('https://abrahamjuliot.github.io/creepjs/', {
    waitUntil: 'networkidle2'
  });
  
  await page.waitForTimeout(12000);
  
  // Extract results
  const results = await page.evaluate(() => {
    const trustScore = document.querySelector('.trust-score');
    const lies = Array.from(document.querySelectorAll('.lies'));
    
    return {
      trustScore: trustScore ? trustScore.textContent : 'N/A',
      liesDetected: lies.length,
      timestamp: new Date().toISOString()
    };
  });
  
  // Save screenshot
  await page.screenshot({
    path: `test-${config.name}-${Date.now()}.png`,
    fullPage: true
  });
  
  await browser.close();
  
  return results;
}

async function applyFingerprint(page, fingerprint) {
  await page.setUserAgent(fingerprint.userAgent);
  await page.setViewport(fingerprint.viewport);
  await page.setGeolocation(fingerprint.geolocation);
  
  await page.evaluateOnNewDocument((fp) => {
    // Apply all custom properties
    Object.defineProperty(navigator, 'platform', {
      get: () => fp.platform
    });
    Object.defineProperty(navigator, 'deviceMemory', {
      get: () => fp.deviceMemory
    });
    Object.defineProperty(navigator, 'hardwareConcurrency', {
      get: () => fp.hardwareConcurrency
    });
  }, fingerprint);
}

// Run tests
const testConfigs = [
  {
    name: 'windows-chrome',
    proxy: 'residential.roundproxies.com:12345',
    proxyAuth: { username: 'user', password: 'pass' },
    fingerprint: {
      userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
      platform: 'Win32',
      deviceMemory: 8,
      hardwareConcurrency: 4,
      viewport: { width: 1920, height: 1080 },
      geolocation: { latitude: 40.7128, longitude: -74.0060 }
    }
  },
  // Add more configurations
];

async function runAllTests() {
  const results = [];
  
  for (const config of testConfigs) {
    console.log(`Testing configuration: ${config.name}`);
    const result = await runCreepJSTest(config);
    results.push({ config: config.name, ...result });
  }
  
  // Save results to file
  fs.writeFileSync(
    'creepjs-test-results.json',
    JSON.stringify(results, null, 2)
  );
  
  console.log('All tests complete. Results saved.');
}

runAllTests();

```

This script tests multiple fingerprint configurations automatically and saves results for analysis.

### Continuous Integration Testing

Integrate CreepJS testing into CI/CD pipelines:

```yaml
# .github/workflows/fingerprint-test.yml
name: Fingerprint Test

on:
  schedule:
    - cron: '0 0 * * *'  # Daily
  push:
    branches: [main]

jobs:
  test-fingerprints:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '16'
      
      - name: Install dependencies
        run: npm install
      
      - name: Run CreepJS tests
        run: node test-creepjs.js
      
      - name: Upload results
        uses: actions/upload-artifact@v2
        with:
          name: creepjs-results
          path: creepjs-test-results.json

```

Regular testing catches fingerprint degradation when browser versions update or detection methods evolve.

## Final Thoughts

CreepJS reveals the extensive data your browser exposes to fingerprinting scripts. Testing with CreepJS helps validate privacy setups and anti-detection configurations.

Key takeaways:

Browser fingerprinting combines dozens of data points into unique identifiers. CreepJS makes this process visible.

Basic automation tools are immediately detected. Stealth plugins improve results but don't eliminate detection.

Advanced spoofing requires consistency across all browser properties. Inconsistencies between claimed and actual values trigger lie detection.

Combining fingerprint spoofing with quality proxies from [Roundproxies.com](https://roundproxies.com/) creates more convincing browser signatures.

Regular testing catches configuration drift as browsers and detection methods evolve.

Use CreepJS as a diagnostic tool to identify and fix fingerprint leaks. The goal is blending with common fingerprints, not creating unique ones.