Noise Seed Explained: How Deterministic RNG Controls Fingerprints
Deep dive into how deterministic noise seeds produce consistent Canvas, WebGL, and Audio fingerprints across sessions and CI/CD pipelines.
Introduction
Browser fingerprint protection often relies on adding noise to rendering outputs: slight variations in Canvas pixels, audio processing results, or WebGL rendering data. This noise prevents the original device-specific fingerprint from being captured. However, if that noise is random, the fingerprint changes on every page load, every session, and every browser restart. A changing fingerprint is itself a distinctive signal, because real devices produce stable, consistent output.
BotBrowser solves this with the --bot-noise-seed flag. Instead of applying random noise, BotBrowser uses a deterministic random number generator (RNG) seeded with a user-provided value. The same seed always produces the same noise pattern, which means the same fingerprint is generated every time. This makes fingerprint output stable across sessions, reproducible across machines, and predictable for testing, all while still being different from the original device output.
Privacy Impact
The distinction between random and deterministic noise has significant privacy implications.
Random noise creates a new fingerprint identity on every session. From a tracker's perspective, a fingerprint that changes every visit is suspicious. Real browsers produce stable fingerprints. A user whose Canvas hash changes every page load stands out from the vast majority of visitors whose Canvas hash remains constant for weeks or months. This instability can trigger additional scrutiny and more aggressive tracking techniques.
Deterministic noise, by contrast, produces a stable fingerprint that behaves exactly like a real device. The Canvas hash is consistent across page loads. The Audio fingerprint is the same today as it was yesterday. The WebGL output remains stable between browser restarts. From the perspective of any fingerprinting script, the browser appears to be a normal device with a normal, unchanging fingerprint.
This stability is essential for several use cases:
- Multi-session consistency: Returning to a website with the same fingerprint looks natural. Arriving with a different fingerprint each time suggests privacy tooling.
- Account management: When managing multiple accounts, each account needs its own stable identity. A noise seed per account ensures that each identity has a consistent, distinct fingerprint.
- Testing and QA: Automated tests that verify fingerprint-dependent behavior need reproducible results. Random noise makes tests flaky; deterministic noise makes them reliable.
- Research: Privacy researchers studying fingerprinting need controlled conditions. A fixed noise seed enables exact reproduction of experimental conditions.
Technical Background
How Deterministic RNG Works
A deterministic random number generator (also called a pseudorandom number generator, or PRNG) produces a sequence of numbers that appears random but is entirely determined by its initial state, the seed. Given the same seed, the PRNG always produces exactly the same sequence of numbers, in the same order, regardless of when or where it runs.
BotBrowser uses a cryptographic-quality PRNG seeded with the value provided through --bot-noise-seed. When Canvas rendering needs noise perturbation, it draws from this PRNG. When Audio processing needs variation, it draws from the same PRNG (or a derived one). When WebGL output needs modification, the same deterministic source provides the values.
The key properties are:
- Determinism: Same seed produces same output, always
- Independence: Different seeds produce completely unrelated output
- Uniformity: The noise distribution looks natural, not patterned
- Cross-platform consistency: The same seed produces the same output on any host OS
What Gets Seeded
The noise seed controls all rendering-related variations in BotBrowser:
- Canvas 2D: Pixel-level perturbations in Canvas rendering output. When a page calls
canvas.toDataURL()orcanvas.getImageData(), the returned data includes noise derived from the seed. - WebGL: Shader output, readback data, and renderer-specific variations are determined by the seed.
- Audio: AudioContext processing (oscillator output, analyzer data, dynamic compressor behavior) includes seed-determined variation.
- Fonts: Glyph measurement micro-variations are seeded, ensuring consistent
measureText()results.
Each of these subsystems uses a portion of the PRNG's output stream, ensuring that the noise applied to Canvas does not interfere with the noise applied to Audio, while both remain deterministic for the same seed value.
Seed Space and Collision
The noise seed is an integer value. Different integer values produce completely different fingerprint outputs. There is no predictable relationship between adjacent seed values (seed 42 and seed 43 produce entirely unrelated fingerprints). The space of possible fingerprints is large enough that accidental collisions (two users coincidentally choosing the same seed) are negligible in practice.
Interaction with Profiles
The noise seed works in conjunction with, not as a replacement for, the fingerprint profile. The profile defines the device characteristics: screen resolution, GPU model, platform, browser version, fonts, and all other hardware/software signals. The noise seed controls the rendering variation within that profile's device identity.
Think of it this way: the profile defines what kind of device is being presented, and the noise seed determines the specific rendering characteristics of that particular "instance" of the device. Two instances with the same profile but different seeds look like two different physical devices of the same model. Two instances with the same profile and same seed look like the same device.
Common Protection Approaches and Their Limitations
Random Noise (Without Seed)
Tools that add random noise to Canvas, WebGL, and Audio output create a different fingerprint every time the browser starts. The problems:
- Fingerprint instability triggers tracker suspicion
- Automated tests cannot rely on consistent output
- Session continuity is impossible (each visit looks like a new device)
- Statistical analysis of the noise pattern can reveal its artificial origin
Fixed Synthetic Output
Some tools replace Canvas or Audio output with a single hardcoded value. This produces stability but has its own problems:
- All users of the tool produce the same fingerprint, creating a detectable cluster
- The fixed output may not match the device's other signals (GPU, fonts, OS)
- If the hardcoded data is discovered, all users are immediately identifiable
Extension-Based Noise
Browser extensions that inject noise face the limitations discussed in other articles: they operate at the JavaScript API level, can be detected through property descriptor checks, and cannot control all rendering paths consistently.
No Noise (Profile Only)
Using a profile without any noise produces output determined by the host hardware's rendering pipeline. While the profile controls reported values, the actual rendering still reflects host GPU and font characteristics. Adding seeded noise ensures that rendering output is controlled rather than leaked from the host.
BotBrowser's Engine-Level Approach
The --bot-noise-seed Flag
BotBrowser's --bot-noise-seed flag accepts an integer value that seeds all rendering-related noise:
chrome --bot-profile="/path/to/profile.enc" \
--bot-noise-seed=42 \
--user-data-dir="$(mktemp -d)"
With this configuration:
- Canvas
toDataURL()andgetImageData()return the same data every time - WebGL readback operations produce identical results across sessions
- Audio processing (via AudioContext) generates the same waveform data
- Font metrics are consistent across browser restarts
- The fingerprint hash (Canvas hash, Audio hash, WebGL hash) is stable
Canvas Noise Toggle
BotBrowser provides fine-grained control over Canvas noise through --bot-config-noise-canvas:
# Enable Canvas noise with deterministic seed
chrome --bot-profile="/path/to/profile.enc" \
--bot-noise-seed=42 \
--bot-config-noise-canvas=true
# Disable Canvas noise specifically
chrome --bot-profile="/path/to/profile.enc" \
--bot-noise-seed=42 \
--bot-config-noise-canvas=false
When Canvas noise is enabled, the seed controls the exact perturbation. When disabled, Canvas output is determined entirely by the profile and rendering engine without additional noise.
Multi-Identity Management
For managing multiple distinct identities, assign a unique noise seed to each:
# Identity A: consistent fingerprint for Account A
chrome --bot-profile="/profiles/profile-a.enc" \
--bot-noise-seed=1001 \
--user-data-dir="/data/account-a"
# Identity B: different but equally consistent fingerprint
chrome --bot-profile="/profiles/profile-b.enc" \
--bot-noise-seed=2002 \
--user-data-dir="/data/account-b"
# Identity C: third distinct identity
chrome --bot-profile="/profiles/profile-c.enc" \
--bot-noise-seed=3003 \
--user-data-dir="/data/account-c"
Each identity has its own profile (defining device characteristics) and its own noise seed (defining rendering variations). The fingerprints are distinct from each other and stable across sessions.
Cross-Machine Reproducibility
One of the most powerful properties of deterministic noise is cross-machine reproducibility. The same profile and seed produce the same fingerprint on any host machine, regardless of:
- Host operating system (Windows, macOS, Linux)
- Host GPU model
- Host font set
- Host screen resolution
- Docker container vs. bare metal vs. virtual machine
This makes --bot-noise-seed essential for distributed deployments where multiple machines need to present the same identity, or where a CI/CD pipeline needs to reproduce the exact fingerprint conditions of a production environment.
Configuration and Usage
Basic CLI Usage
# Deterministic fingerprint with seed
chrome --bot-profile="/path/to/profile.enc" \
--bot-noise-seed=42 \
--user-data-dir="$(mktemp -d)"
CI/CD Pipeline Example
# Same profile and seed in CI produces same fingerprint as production
chrome --bot-profile="/profiles/production-identity.enc" \
--bot-noise-seed=98765 \
--bot-time-scale=1.0 \
--bot-fps=60 \
--headless \
--user-data-dir="$(mktemp -d)"
Playwright Integration
const { chromium } = require('playwright-core');
(async () => {
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-noise-seed=42',
],
headless: true,
});
const context = await browser.newContext({ viewport: null });
const page = await context.newPage();
// Canvas hash will be the same every run
const canvasHash = await page.evaluate(() => {
const c = document.createElement('canvas');
c.width = 200;
c.height = 50;
const ctx = c.getContext('2d');
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillStyle = '#333';
ctx.fillText('Deterministic test', 2, 2);
ctx.fillStyle = 'rgba(0, 50, 255, 0.5)';
ctx.fillRect(50, 10, 100, 30);
return c.toDataURL();
});
console.log('Canvas hash:', canvasHash.substring(0, 80) + '...');
await browser.close();
})();
Puppeteer Integration
const puppeteer = require('puppeteer-core');
(async () => {
const browser = await puppeteer.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-noise-seed=42',
'--bot-config-noise-canvas=true',
],
headless: true,
defaultViewport: null,
});
const page = await browser.newPage();
await page.goto('about:blank');
// Audio fingerprint will also be deterministic
const audioHash = await page.evaluate(() => {
return new Promise(resolve => {
const ctx = new OfflineAudioContext(1, 44100, 44100);
const osc = ctx.createOscillator();
osc.type = 'triangle';
osc.frequency.value = 10000;
osc.connect(ctx.destination);
osc.start(0);
ctx.startRendering().then(buffer => {
const data = buffer.getChannelData(0).slice(4500, 5000);
const sum = data.reduce((a, b) => a + Math.abs(b), 0);
resolve(sum.toFixed(10));
});
});
});
console.log('Audio hash:', audioHash);
await browser.close();
})();
Full Deterministic Configuration
For maximum reproducibility, combine noise seed with timing and frame rate control:
chrome --bot-profile="/path/to/profile.enc" \
--bot-noise-seed=42 \
--bot-time-scale=1.0 \
--bot-fps=60 \
--bot-config-noise-canvas=true \
--user-data-dir="$(mktemp -d)"
Verification
To verify deterministic behavior, run the same configuration twice and compare:
// Run 1: Capture fingerprint hashes
const run1Canvas = await page.evaluate(() => {
const c = document.createElement('canvas');
c.width = 200; c.height = 50;
const ctx = c.getContext('2d');
ctx.font = '14px Arial';
ctx.fillText('Test string', 10, 25);
return c.toDataURL();
});
// Run 2: Same profile, same seed, should produce identical hash
// (restart browser between runs)
const run2Canvas = await page.evaluate(() => {
const c = document.createElement('canvas');
c.width = 200; c.height = 50;
const ctx = c.getContext('2d');
ctx.font = '14px Arial';
ctx.fillText('Test string', 10, 25);
return c.toDataURL();
});
console.log('Canvas match:', run1Canvas === run2Canvas);
// Should print: Canvas match: true
What to check:
- Canvas output is identical across browser restarts with the same seed
- Audio processing produces the same hash values across sessions
- WebGL readback data matches between runs
- Different seeds produce different (but individually stable) outputs
- The same seed on different host machines produces the same fingerprint
- Fingerprint testing tools (CreepJS, BrowserLeaks) show stable hashes
Best Practices
-
Choose unique seeds per identity. Each browser identity should have its own noise seed. Using the same seed for multiple identities makes them produce the same rendering output, which can link them.
-
Store seeds securely. The noise seed is part of the identity configuration. Treat it as sensitive data alongside the profile path and user data directory.
-
Use seeds in CI/CD. For automated testing, always specify a noise seed to ensure deterministic results. Without a seed, rendering output may vary between test runs.
-
Combine with
--bot-time-scale. For full determinism, control both rendering noise and timing signals. The noise seed handles Canvas/Audio/WebGL, while--bot-time-scalehandles performance timing. -
Document seed assignments. In multi-identity deployments, maintain a mapping of which seed is assigned to which identity. This ensures you can reproduce any identity's exact fingerprint.
-
Avoid sequential seeds for related identities. While sequential seeds (1, 2, 3) produce unrelated output, using a deliberate mapping (like hashing account identifiers) provides better organizational clarity.
Frequently Asked Questions
Does the noise seed affect page content or rendering quality?
No. The noise is applied at the sub-pixel level for Canvas and at similar precision for Audio and WebGL. The variations are invisible to the human eye and inaudible. Pages look and function identically regardless of the seed value.
Can two users with the same seed be linked?
If two users use the same profile AND the same noise seed, their rendering output will be identical, which could theoretically link them. This is why each identity should use a unique seed. Different profiles with the same seed produce different output because the profile also influences rendering.
What happens without --bot-noise-seed?
Without a noise seed, BotBrowser still applies the profile's device characteristics, but rendering noise (if enabled) may use a session-random seed. This provides different-from-host output but does not guarantee cross-session consistency. For stable fingerprints, always specify a noise seed.
Does the seed need to be a specific type of number?
The seed is an integer. Any integer value works. There is no advantage to choosing large numbers, prime numbers, or any other specific pattern. Simply use a value that is unique per identity.
Can I change the seed to get a new fingerprint?
Yes. Changing the noise seed while keeping the same profile produces a new, distinct fingerprint. This is useful when you need to rotate identities while maintaining the same device class (same profile, different rendering characteristics).
How does --bot-noise-seed interact with --bot-config-noise-canvas?
--bot-config-noise-canvas toggles whether Canvas noise is applied at all. --bot-noise-seed controls the noise pattern when it is applied. If Canvas noise is disabled, the seed still affects Audio and WebGL noise. If Canvas noise is enabled, the seed makes it deterministic.
Is the noise seed compatible with all profiles?
Yes. The noise seed is independent of the profile's device configuration. Any seed works with any profile. The seed controls rendering variation, while the profile controls device identity.
Can fingerprinting services detect that noise is deterministic?
No. The noise pattern produced by a deterministic seed is statistically indistinguishable from natural hardware variation. The determinism is only observable if the same seed is tested multiple times and the exact same output is confirmed, which is the intended behavior (stability, not randomness).
Summary
The --bot-noise-seed flag is the foundation of reproducible fingerprint protection in BotBrowser. By seeding a deterministic RNG that controls Canvas, WebGL, Audio, and font rendering variations, it produces fingerprints that are stable across sessions, reproducible across machines, and indistinguishable from natural device output. Combined with profile management, Canvas protection, Audio fingerprint control, and performance timing, noise seed reproducibility enables consistent, predictable fingerprint identities for privacy protection, multi-account management, testing, and research.