Camoufox provides per-context isolation via specific JavaScript functions that allow each Playwright context to have a unique, deterministic fingerprint. This prevents cross-context correlation when running multiple concurrent sessions.
To apply these fingerprints, use context.addInitScript(). This ensures the functions are called on every new page, tab, or navigation before any website scripts execute.
Important Notes:
- Self-Destruction: All fingerprinting functions self-destruct after the first call. They cannot be detected by website code via
typeof window.setXxx after execution. - Guards: Always use
typeof checks (e.g., if (typeof window.setTimezone === 'function')) within your init script to prevent ReferenceError if the patches are not present or if the function has already self-destructed.
const { firefox } = require('playwright');
const browser = await firefox.launch({
executablePath: '/path/to/camoufox',
});
const context = await browser.newContext({
viewport: { width: 1280, height: 720 },
});
// Apply fingerprints via addInitScript — fires on every new page automatically
await context.addInitScript((values) => {
const w = window;
if (typeof w.setFontSpacingSeed === 'function') {
w.setFontSpacingSeed(values.fontSpacingSeed);
}
if (typeof w.setAudioFingerprintSeed === 'function') {
w.setAudioFingerprintSeed(values.audioFingerprintSeed);
}
if (typeof w.setTimezone === 'function') {
w.setTimezone(values.timezone);
}
if (typeof w.setScreenDimensions === 'function') {
w.setScreenDimensions(values.screenWidth, values.screenHeight);
}
if (typeof w.setScreenColorDepth === 'function') {
w.setScreenColorDepth(values.screenColorDepth);
}
if (typeof w.setWebRTCIPv4 === 'function') {
w.setWebRTCIPv4(values.webrtcIPv4);
}
if (typeof w.setNavigatorPlatform === 'function') {
w.setNavigatorPlatform(values.navigatorPlatform);
}
if (typeof w.setNavigatorOscpu === 'function') {
w.setNavigatorOscpu(values.navigatorOscpu);
}
if (typeof w.setNavigatorHardwareConcurrency === 'function') {
w.setNavigatorHardwareConcurrency(values.hardwareConcurrency);
}
if (typeof w.setNavigatorUserAgent === 'function') {
w.setNavigatorUserAgent(values.userAgent);
}
if (typeof w.setWebGLVendor === 'function') {
w.setWebGLVendor(values.webglVendor);
}
if (typeof w.setWebGLRenderer === 'function') {
w.setWebGLRenderer(values.webglRenderer);
}
if (typeof w.setCanvasSeed === 'function') {
w.setCanvasSeed(values.canvasSeed);
}
if (values.fontList && values.fontList.length > 0 && typeof w.setFontList === 'function') {
w.setFontList(values.fontList.join(','));
}
if (values.speechVoices && typeof w.setSpeechVoices === 'function') {
w.setSpeechVoices(values.speechVoices);
}
}, {
fontSpacingSeed: 12345678,
audioFingerprintSeed: 87654321,
timezone: 'America/New_York',
screenWidth: 1920,
screenHeight: 1080,
screenColorDepth: 24,
webrtcIPv4: '203.0.113.1', // your proxy IP
navigatorPlatform: 'MacIntel',
navigatorOscpu: 'Intel Mac OS X 10.15',
hardwareConcurrency: 8,
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:146.0) Gecko/20100101 Firefox/146.0',
webglVendor: 'Intel Inc.',
webglRenderer: 'Intel Iris OpenGL Engine',
canvasSeed: 55555555,
fontList: ['Arial', 'Helvetica', 'Georgia', 'Courier New', 'Verdana', 'Times New Roman'],
speechVoices: 'Microsoft David,Microsoft Zira,Google US English',
});
const page = await context.newPage();
await page.goto('https://example.com');