cdpfleet Docs Sign up free

Examples & benchmarks / #83 · 2026-11-05 · Benchmark · Medium · for web scraping, testing

Brave's fingerprint randomisation per site, per context and per launch, and what public fingerprint pages make of it

Brave adds noise to canvas, audio, cores, memory and the plugin list, keyed to the site and the session. One probe on two made-up sites, the same site again, a second context and a second launch shows exactly when the values change, next to headful Chrome. Then CreepJS, browserleaks, sannysoft, deviceandbrowserinfo and the fingerprint.com playground give their own verdicts on Brave headless, Brave headful and Chrome. Dated 2026-11-05.

Brave Google Chrome

Run on production on 2026-11-05: ✓ Node.js ✓ Python ✓ Java ✓ C# ✓ Go

A benchmark: the results below are what this setup measured on the dates shown, on our own test runs. Sites, networks and browsers change, so rerun the code before you rely on the numbers.

The problem

Brave doesn't hide its fingerprint, it randomises it ("farbling"): canvas and audio output get a little noise, hardwareConcurrency and deviceMemory are made up, and the plugin list gets invented names. Case 66 found Brave's canvas and audio new on every launch, on one site. But the noise is said to be keyed to the site as well, so the useful questions are finer: do two sites in the same session see different values, does the same site see the same ones when you come back, what does a second browser context get, and what do public fingerprint pages conclude when they meet a browser that randomises? This case measures that on a dated day, on public test pages and on two sites served by the program itself.

What we used, and why

WhatWhy
Three setupsbrave with headless: true, brave with headless: false, and chrome with headless: false as the reference. Brave runs with its default Shields; nothing is configured. Every launch uses record: false and the same proxy.
Two made-up sites via context.route()https://site-a.example/ and https://site-b.test/ are two different registrable domains, so the browser treats them as two first-party sites; route.fulfill() serves a one-line page for both, and no request leaves the browser.
A small fingerprinting probeThe same script in every language reads a canvas hash (drawn twice, to check the page agrees with itself), an OfflineAudioContext hash, navigator.hardwareConcurrency, navigator.deviceMemory, a hash of the navigator.plugins names, screen.width × height and outerWidth × outerHeight.
Six visits per setup, each in a new tabLaunch 1: site A, site B, site A again, then site A in a second browser.newContext(). Launch 2 (a new session): site A and site B.
Five public test pages, one load each per setupCreepJS (its headless and stealth scores, the "privacy" it names, its canvas noise estimate and the sections it marks as lies), browserleaks.com/canvas (signature and uniqueness), bot.sannysoft.com, deviceandbrowserinfo.com and the fingerprint.com playground (bot verdict and suspect score only), read the way case 63 reads them.

How it works

  1. For each of the three setups, launch a session and add routes for the two made-up sites to a new context.
  2. Visit site A, site B and site A again, each in a new tab, running the probe; then site A in a second context of the same session.
  3. Close the session, launch a new one, and visit site A and site B again.
  4. In a fresh context of that second session, load each public test page once, wait for its verdict and read it from the page.
  5. Print the probe values of all six visits and the five verdicts per setup.

The code

The same program in five languages (also on GitHub, with the raw output). Set these environment variables first:

// npm install [email protected]
// env: CDPFLEET_API_KEY, PROXY_URL (an http(s) or socks5 proxy; one load per public test page per setup)
import { chromium } from 'playwright';

const KEY = process.env.CDPFLEET_API_KEY;
const PROXY = process.env.PROXY_URL;

const SETUPS = [
  { setup: 'Brave, headless', engine: 'brave', headless: true },
  { setup: 'Brave, headful', engine: 'brave', headless: false },
  { setup: 'Google Chrome, headful', engine: 'chrome', headless: false },
];

// Two made-up sites on different registrable domains, served by page routing: the browser
// treats them as two first-party sites, and no request leaves the browser.
const SITES = { A: 'https://site-a.example/', B: 'https://site-b.test/' };
const HTML = '<!doctype html><title>lab 83</title><p>A page with nothing on it but this probe.</p>';

// What a fingerprinting script reads, the same in every language: a canvas hash (drawn twice),
// an OfflineAudioContext hash, cores, memory, the plugin list, the screen and the window size.
const PROBE = `(async () => {
  const fnv = (s) => { let h = 0x811c9dc5; for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 0x01000193) >>> 0; } return h.toString(16).padStart(8, '0'); };
  const draw = () => {
    const c = document.createElement('canvas'); c.width = 240; c.height = 60;
    const x = c.getContext('2d'); x.textBaseline = 'top'; x.font = '16px Arial';
    x.fillStyle = '#f60'; x.fillRect(100, 1, 62, 20);
    x.fillStyle = '#069'; x.fillText('cdpfleet fp 83 <@>', 2, 15);
    x.fillStyle = 'rgba(102, 204, 0, 0.7)'; x.fillText('cdpfleet fp 83 <@>', 4, 17);
    return c.toDataURL();
  };
  const audio = async () => {
    try {
      const ctx = new OfflineAudioContext(1, 44100, 44100);
      const o = ctx.createOscillator(); o.type = 'triangle'; o.frequency.value = 10000;
      const k = ctx.createDynamicsCompressor();
      k.threshold.value = -50; k.knee.value = 40; k.ratio.value = 12; k.attack.value = 0; k.release.value = 0.25;
      o.connect(k); k.connect(ctx.destination); o.start(0);
      const d = new Float32Array(500); (await ctx.startRendering()).copyFromChannel(d, 0, 4500);
      let s = ''; for (let i = 0; i < 500; i++) s += d[i].toFixed(10) + ',';
      return fnv(s);
    } catch (e) { return 'error: ' + e.name; }
  };
  const c1 = draw(), c2 = draw();
  const plugins = Array.from(navigator.plugins).map((p) => p.name);
  return {
    site: location.hostname,
    canvas: fnv(c1), canvas_same_in_page: c1 === c2,
    audio: await audio(),
    cores: navigator.hardwareConcurrency, memory: navigator.deviceMemory ?? null,
    plugins: fnv(plugins.join(',')), plugin_names: plugins,
    screen: screen.width + 'x' + screen.height, window: outerWidth + 'x' + outerHeight,
  };
})()`;

// Each public test page's own verdict, read from its DOM; "ready" is polled until the page has
// finished its checks. The same expressions run in every language.
const PAGES = [
  {
    key: 'creepjs', url: 'https://abrahamjuliot.github.io/creepjs/',
    ready: "/\\d+% stealth/.test(document.body.innerText) && /privacy: \\S/.test(document.body.innerText)",
    // A section CreepJS caught lying gets its hash marked with the "lies" class.
    read: "(() => { const t = document.body.innerText.replace(/\\s+/g, ' '); const m = /(\\d+)% like headless[\\s\\S]*?(\\d+)% headless:[\\s\\S]*?(\\d+)% stealth/.exec(t); const privacy = /privacy: (\\S+)/.exec(t); const noise = /rendering: (\\d+% \\w+ noise)/.exec(t); return { like_headless_pct: m ? +m[1] : null, headless_pct: m ? +m[2] : null, stealth_pct: m ? +m[3] : null, privacy: privacy ? privacy[1] : null, canvas_noise: noise ? noise[1] : null, lies: Array.from(document.querySelectorAll('.lies')).map((e) => (e.previousElementSibling ? e.previousElementSibling.innerText.trim() : '?')) }; })()",
  },
  {
    key: 'browserleaks', url: 'https://browserleaks.com/canvas',
    ready: "/Uniqueness\\s+\\d/.test(document.body.innerText)",
    read: "(() => { const t = document.body.innerText; const sig = /Signature\\s+([0-9A-Fa-f]{32})/.exec(t); const u = /Uniqueness\\s+([^\\n]+)/.exec(t); return { signature: sig ? sig[1] : null, uniqueness: u ? u[1].trim() : null }; })()",
  },
  {
    key: 'sannysoft', url: 'https://bot.sannysoft.com/',
    ready: "document.querySelectorAll('td.passed, td.failed').length > 10",
    read: "(() => { const rows = Array.from(document.querySelectorAll('tr')).filter((tr) => tr.querySelector('td.passed, td.failed, td.warn')); const failed = rows.filter((tr) => tr.querySelector('td.failed')).map((tr) => tr.cells[0].innerText.replace(/\\s+/g, ' ').trim()); return { checks: rows.length, failed: failed.length, failed_names: failed }; })()",
  },
  {
    key: 'deviceandbrowserinfo', url: 'https://deviceandbrowserinfo.com/are_you_a_bot',
    ready: "document.body.innerText.indexOf('\"isBot\"') >= 0",
    read: "(() => { const t = document.body.innerText; const s = t.indexOf('{', t.indexOf('\"isBot\"') - 10); let depth = 0, e = s; for (; e < t.length; e++) { if (t[e] === '{') depth++; if (t[e] === '}' && --depth === 0) break; } try { const j = JSON.parse(t.slice(s, e + 1)); return { is_bot: j.isBot, signals: Object.keys(j.details || {}).filter((k) => j.details[k] === true) }; } catch (err) { return { is_bot: null, signals: [] }; } })()",
  },
  {
    key: 'fingerprint', url: 'https://demo.fingerprint.com/playground',
    ready: "/Suspect Score \\d+/.test(document.body.innerText.replace(/\\s+/g, ' '))",
    // Only the bot verdict and the suspect score are read (the page also names proxy networks).
    read: "(() => { const t = document.body.innerText.replace(/\\s+/g, ' '); const bot = /\\bBot (.+?) VPN /.exec(t); const score = /Suspect Score (\\d+)/.exec(t); return { bot: bot ? bot[1].replace(/[^\\x20-\\x7e]/g, '').replace(/\\s+/g, ' ').trim() : null, suspect_score: score ? +score[1] : null }; })()",
  },
];

// 503 means the fleet is momentarily busy: wait Retry-After and try again.
async function launch(engine, headless) {
  for (let attempt = 1; ; attempt++) {
    const res = await fetch(`https://starter.cdpfleet.com/${engine}/session`, {
      method: 'POST',
      headers: { 'x-api-key': KEY, 'content-type': 'application/json' },
      body: JSON.stringify({ proxy: PROXY, record: false, headless }),
    });
    if (res.ok) return res.json();
    if (![429, 503].includes(res.status) || attempt === 5) throw new Error(`launch ${res.status} ${await res.text()}`);
    await new Promise((r) => setTimeout(r, (Number(res.headers.get('retry-after')) || 5) * 1000));
  }
}

async function siteContext(browser) {
  const context = await browser.newContext();
  for (const url of Object.values(SITES)) await context.route(`${url}**`, (route) => route.fulfill({ contentType: 'text/html', body: HTML }));
  return context;
}

// One visit = a new tab in the given context, the probe, the tab closed.
async function visit(context, label, launchNo, contextNo, site) {
  const page = await context.newPage();
  try {
    await page.goto(SITES[site]);
    return { visit: label, launch: launchNo, context: contextNo, ...(await page.evaluate(PROBE)) };
  } finally {
    await page.close();
  }
}

const out = { setups: [] };
for (const s of SETUPS) {
  const row = { setup: s.setup, engine: s.engine, headless: s.headless, visits: [], pages: {} };
  // Launch 1: site A, site B, site A again in a new tab, then site A in a second context.
  let session = await launch(s.engine, s.headless);
  let browser = await chromium.connect(session.wsUrl, { headers: { 'x-api-key': KEY } });
  try {
    const one = await siteContext(browser);
    row.visits.push(await visit(one, 'site A', 1, 1, 'A'));
    row.visits.push(await visit(one, 'site B', 1, 1, 'B'));
    row.visits.push(await visit(one, 'site A again', 1, 1, 'A'));
    const two = await siteContext(browser);
    row.visits.push(await visit(two, 'site A, second context', 1, 2, 'A'));
  } finally {
    await browser.close();
  }
  // Launch 2: sites A and B again, then each public test page once, in a fresh context.
  session = await launch(s.engine, s.headless);
  browser = await chromium.connect(session.wsUrl, { headers: { 'x-api-key': KEY } });
  try {
    const three = await siteContext(browser);
    row.visits.push(await visit(three, 'site A, next launch', 2, 1, 'A'));
    row.visits.push(await visit(three, 'site B, next launch', 2, 1, 'B'));
    const page = await (await browser.newContext()).newPage();
    for (const p of PAGES) {
      try {
        // A proxy tunnel drop is tried once more; a page that loaded is never reloaded.
        try { await page.goto(p.url, { timeout: 60000 }); } catch { await page.goto(p.url, { timeout: 60000 }); }
        await page.waitForFunction(p.ready, null, { timeout: 45000 });
        row.pages[p.key] = await page.evaluate(p.read);
      } catch (err) {
        row.pages[p.key] = { error: err.message.split('\n')[0].slice(0, 120) };
      }
    }
  } finally {
    await browser.close();
  }
  out.setups.push(row);
}
console.log(JSON.stringify(out, null, 2));

What we got

SetupSite A vs site B (one session)Site A again (new tab)Site A, second contextSite A, next launchCores · memory · screen (6 visits)CreepJS: privacy · lies · headlessbrowserleaks canvassannysoft · deviceandbrowserinfo · fingerprint.com
Brave, headlesscanvas, audio, cores, memory, plugins, window size differall the samecanvas, audio, cores, memory, plugins, window size differcanvas, audio, cores, plugins, window size differ39, 45, 17, 14, 7 · 16, 8, 4 GB · 1366x768Brave · Screen, Canvas 2d, Audio, Navigator · 67%100% (The signature is unique to our database)4 of 31 failed (User Agent (Old), WebGL Renderer, HEADCHR_UA, CHR_MEMORY) · bot · You are a bad bot (type: headless_chrome), score 41
Brave, headfulcanvas, audio, cores, memory, plugins, window size differall the samecanvas, audio, cores, plugins, window size differcanvas, audio, cores, plugins, window size differ10, 62, 50, 33, 29 · 16, 8, 4 GB · 1366x768Brave · Screen, Canvas 2d, Audio, Navigator · 0%100% (The signature is unique to our database)1 of 31 failed (WebGL Renderer) · bot · Not detected, score 33
Google Chrome, headfulall the sameall the sameall the samecores differ36, 64 · 32 GB · 1280x720unknown · none · 0%99.95% (119 of 258037 user agents have the same signature)1 of 31 failed (WebGL Renderer) · bot · You are a bad bot (type: chromium_automation), score 47

From the Node.js run on 2026-11-05. IP addresses are replaced with placeholders (203.0.113.x); equal addresses stay equal. The other languages produced the same findings.

Raw output (Node.js)
{
  "setups": [
    {
      "setup": "Brave, headless",
      "engine": "brave",
      "headless": true,
      "visits": [
        {
          "visit": "site A",
          "launch": 1,
          "context": 1,
          "site": "site-a.example",
          "canvas": "3929b51c",
          "canvas_same_in_page": true,
          "audio": "7d88c56c",
          "cores": 39,
          "memory": 16,
          "plugins": "3517aa9c",
          "plugin_names": [
            "SRIMtWq",
            "PDF Viewer",
            "Online com.adobe.pdf extension",
            "Chromium PDF Viewer",
            "Microsoft Edge PDF Viewer",
            "WebKit built-in PDF",
            "o7GDBfPH"
          ],
          "screen": "1366x768",
          "window": "1287x723"
        },
        {
          "visit": "site B",
          "launch": 1,
          "context": 1,
          "site": "site-b.test",
          "canvas": "a6d8dc39",
          "canvas_same_in_page": true,
          "audio": "ccfc6c8e",
          "cores": 45,
          "memory": 8,
          "plugins": "c18a66df",
          "plugin_names": [
            "Rnb0DozZ",
            "WebKit built-in PDF",
            "OpenSource PDF plug in",
            "myCBfXq",
            "Chromium PDF Viewer",
            "Microsoft Edge PDF Viewer",
            "PDF Viewer"
          ],
          "screen": "1366x768",
          "window": "1283x725"
        },
        {
          "visit": "site A again",
          "launch": 1,
          "context": 1,
          "site": "site-a.example",
          "canvas": "3929b51c",
          "canvas_same_in_page": true,
          "audio": "7d88c56c",
          "cores": 39,
          "memory": 16,
          "plugins": "3517aa9c",
          "plugin_names": [
            "SRIMtWq",
            "PDF Viewer",
            "Online com.adobe.pdf extension",
            "Chromium PDF Viewer",
            "Microsoft Edge PDF Viewer",
            "WebKit built-in PDF",
            "o7GDBfPH"
          ],
          "screen": "1366x768",
          "window": "1287x723"
        },
        {
          "visit": "site A, second context",
          "launch": 1,
          "context": 2,
          "site": "site-a.example",
          "canvas": "0f1dee48",
          "canvas_same_in_page": true,
          "audio": "6cc3bfb5",
          "cores": 17,
          "memory": 4,
          "plugins": "0f8c46b8",
          "plugin_names": [
            "Chromium PDF Viewer",
            "WebKit built-in PDF",
            "Microsoft Edge PDF Viewer",
            "PDF Viewer",
            "Co7GLs1D",
            "Chromium doc extension",
            "v68eu2E"
          ],
          "screen": "1366x768",
          "window": "1287x722"
        },
        {
          "visit": "site A, next launch",
          "launch": 2,
          "context": 1,
          "site": "site-a.example",
          "canvas": "f2fa3d3b",
          "canvas_same_in_page": true,
          "audio": "4957ea93",
          "cores": 14,
          "memory": 16,
          "plugins": "bf2c840b",
          "plugin_names": [
            "PDF Viewer",
            "WebKit built-in PDF",
            "Microsoft Edge PDF Viewer",
            "QQnTJjR",
            "Chromium PDF Viewer",
            "157laVSR",
            "Chromium PDF Viewer"
          ],
          "screen": "1366x768",
          "window": "1283x727"
        },
        {
          "visit": "site B, next launch",
          "launch": 2,
          "context": 1,
          "site": "site-b.test",
          "canvas": "03b82bb5",
          "canvas_same_in_page": true,
          "audio": "59fe9049",
          "cores": 7,
          "memory": 4,
          "plugins": "d777bd16",
          "plugin_names": [
            "Microsoft Edge PDF Viewer",
            "Chromium PDF Viewer",
            "WyhQIECg",
            "Online PDF and PS plug-in",
            "WebKit built-in PDF",
            "PDF Viewer",
            "zhQQnTR"
          ],
          "screen": "1366x768",
          "window": "1284x724"
        }
      ],
      "pages": {
        "creepjs": {
          "like_headless_pct": 50,
          "headless_pct": 67,
          "stealth_pct": 0,
          "privacy": "Brave",
          "canvas_noise": "13% rgba noise",
          "lies": [
            "Screen",
            "Canvas 2d",
            "Audio",
            "Navigator"
          ]
        },
        "browserleaks": {
          "signature": "5665EF9CFB4247140C85C0EF68D6E19A",
          "uniqueness": "100% (The signature is unique to our database)"
        },
        "sannysoft": {
          "checks": 31,
          "failed": 4,
          "failed_names": [
            "User Agent (Old)",
            "WebGL Renderer",
            "HEADCHR_UA",
            "CHR_MEMORY"
          ]
        },
        "deviceandbrowserinfo": {
          "is_bot": true,
          "signals": [
            "hasBotUserAgent",
            "hasInconsistentTimingResolution",
            "isAutomatedWithCDP",
            "isAutomatedWithCDPInWebWorker",
            "hasSuspiciousWeakSignals"
          ]
        },
        "fingerprint": {
          "bot": "You are a bad bot (type: headless_chrome)",
          "suspect_score": 41
        }
      }
    },
    {
      "setup": "Brave, headful",
      "engine": "brave",
      "headless": false,
      "visits": [
        {
          "visit": "site A",
          "launch": 1,
          "context": 1,
          "site": "site-a.example",
          "canvas": "78aaddc1",
          "canvas_same_in_page": true,
          "audio": "260fc5cf",
          "cores": 10,
          "memory": 16,
          "plugins": "7eb2a6c8",
          "plugin_names": [
            "aRvAfPHD",
            "Microsoft Edge PDF Viewer",
            "VpzZz4k",
            "WebKit built-in PDF",
            "PDF Viewer",
            "Chromium PDF Renderer",
            "Chromium PDF Viewer"
          ],
          "screen": "1366x768",
          "window": "1284x726"
        },
        {
          "visit": "site B",
          "launch": 1,
          "context": 1,
          "site": "site-b.test",
          "canvas": "c47f4c44",
          "canvas_same_in_page": true,
          "audio": "8a2ad350",
          "cores": 62,
          "memory": 8,
          "plugins": "acbec43b",
          "plugin_names": [
            "Microsoft Edge PDF Viewer",
            "Chromium PDF Viewer",
            "BMl5cWL",
            "PDF Viewer",
            "nTRQvAny",
            "WebKit built-in PDF",
            "OpenSource com.adobe.pdf Plugin"
          ],
          "screen": "1366x768",
          "window": "1285x722"
        },
        {
          "visit": "site A again",
          "launch": 1,
          "context": 1,
          "site": "site-a.example",
          "canvas": "78aaddc1",
          "canvas_same_in_page": true,
          "audio": "260fc5cf",
          "cores": 10,
          "memory": 16,
          "plugins": "7eb2a6c8",
          "plugin_names": [
            "aRvAfPHD",
            "Microsoft Edge PDF Viewer",
            "VpzZz4k",
            "WebKit built-in PDF",
            "PDF Viewer",
            "Chromium PDF Renderer",
            "Chromium PDF Viewer"
          ],
          "screen": "1366x768",
          "window": "1284x726"
        },
        {
          "visit": "site A, second context",
          "launch": 1,
          "context": 2,
          "site": "site-a.example",
          "canvas": "8b9aa4aa",
          "canvas_same_in_page": true,
          "audio": "b8f8904c",
          "cores": 50,
          "memory": 16,
          "plugins": "f3722525",
          "plugin_names": [
            "WebKit built-in PDF",
            "ylSw3j4F",
            "Microsoft Edge PDF Viewer",
            "uAfPPmy",
            "PDF Viewer",
            "Chromium PDF Viewer",
            "Chromium document plug-in"
          ],
          "screen": "1366x768",
          "window": "1283x728"
        },
        {
          "visit": "site A, next launch",
          "launch": 2,
          "context": 1,
          "site": "site-a.example",
          "canvas": "e89d04a6",
          "canvas_same_in_page": true,
          "audio": "f6955e75",
          "cores": 33,
          "memory": 16,
          "plugins": "c101b944",
          "plugin_names": [
            "PDF Viewer",
            "Chromium PDF Viewer",
            "PPm6dt15",
            "WebKit built-in PDF",
            "Brave Portable Document Format ",
            "Microsoft Edge PDF Viewer",
            "rVp78mT"
          ],
          "screen": "1366x768",
          "window": "1281x725"
        },
        {
          "visit": "site B, next launch",
          "launch": 2,
          "context": 1,
          "site": "site-b.test",
          "canvas": "609dba8e",
          "canvas_same_in_page": true,
          "audio": "f7932c8b",
          "cores": 29,
          "memory": 4,
          "plugins": "8b2aba84",
          "plugin_names": [
            "yhYzCBn",
            "Chromium com.adobe.pdf plug-in",
            "1Do78eu2",
            "WebKit built-in PDF",
            "Microsoft Edge PDF Viewer",
            "Chromium PDF Viewer",
            "PDF Viewer"
          ],
          "screen": "1366x768",
          "window": "1287x728"
        }
      ],
      "pages": {
        "creepjs": {
          "like_headless_pct": 50,
          "headless_pct": 0,
          "stealth_pct": 0,
          "privacy": "Brave",
          "canvas_noise": "11% rgba noise",
          "lies": [
            "Screen",
            "Canvas 2d",
            "Audio",
            "Navigator"
          ]
        },
        "browserleaks": {
          "signature": "81495C5956A1E9C8878409147E273E0F",
          "uniqueness": "100% (The signature is unique to our database)"
        },
        "sannysoft": {
          "checks": 31,
          "failed": 1,
          "failed_names": [
            "WebGL Renderer"
          ]
        },
        "deviceandbrowserinfo": {
          "is_bot": true,
          "signals": [
            "hasInconsistentTimingResolution",
            "isAutomatedWithCDP",
            "isAutomatedWithCDPInWebWorker",
            "hasSuspiciousWeakSignals"
          ]
        },
        "fingerprint": {
          "bot": "Not detected",
          "suspect_score": 33
        }
      }
    },
    {
      "setup": "Google Chrome, headful",
      "engine": "chrome",
      "headless": false,
      "visits": [
        {
          "visit": "site A",
          "launch": 1,
          "context": 1,
          "site": "site-a.example",
          "canvas": "a30ef280",
          "canvas_same_in_page": true,
          "audio": "b7a0343c",
          "cores": 36,
          "memory": 32,
          "plugins": "1b059b58",
          "plugin_names": [
            "PDF Viewer",
            "Chrome PDF Viewer",
            "Chromium PDF Viewer",
            "Microsoft Edge PDF Viewer",
            "WebKit built-in PDF"
          ],
          "screen": "1280x720",
          "window": "1288x805"
        },
        {
          "visit": "site B",
          "launch": 1,
          "context": 1,
          "site": "site-b.test",
          "canvas": "a30ef280",
          "canvas_same_in_page": true,
          "audio": "b7a0343c",
          "cores": 36,
          "memory": 32,
          "plugins": "1b059b58",
          "plugin_names": [
            "PDF Viewer",
            "Chrome PDF Viewer",
            "Chromium PDF Viewer",
            "Microsoft Edge PDF Viewer",
            "WebKit built-in PDF"
          ],
          "screen": "1280x720",
          "window": "1288x805"
        },
        {
          "visit": "site A again",
          "launch": 1,
          "context": 1,
          "site": "site-a.example",
          "canvas": "a30ef280",
          "canvas_same_in_page": true,
          "audio": "b7a0343c",
          "cores": 36,
          "memory": 32,
          "plugins": "1b059b58",
          "plugin_names": [
            "PDF Viewer",
            "Chrome PDF Viewer",
            "Chromium PDF Viewer",
            "Microsoft Edge PDF Viewer",
            "WebKit built-in PDF"
          ],
          "screen": "1280x720",
          "window": "1288x805"
        },
        {
          "visit": "site A, second context",
          "launch": 1,
          "context": 2,
          "site": "site-a.example",
          "canvas": "a30ef280",
          "canvas_same_in_page": true,
          "audio": "b7a0343c",
          "cores": 36,
          "memory": 32,
          "plugins": "1b059b58",
          "plugin_names": [
            "PDF Viewer",
            "Chrome PDF Viewer",
            "Chromium PDF Viewer",
            "Microsoft Edge PDF Viewer",
            "WebKit built-in PDF"
          ],
          "screen": "1280x720",
          "window": "1288x805"
        },
        {
          "visit": "site A, next launch",
          "launch": 2,
          "context": 1,
          "site": "site-a.example",
          "canvas": "a30ef280",
          "canvas_same_in_page": true,
          "audio": "b7a0343c",
          "cores": 64,
          "memory": 32,
          "plugins": "1b059b58",
          "plugin_names": [
            "PDF Viewer",
            "Chrome PDF Viewer",
            "Chromium PDF Viewer",
            "Microsoft Edge PDF Viewer",
            "WebKit built-in PDF"
          ],
          "screen": "1280x720",
          "window": "1288x805"
        },
        {
          "visit": "site B, next launch",
          "launch": 2,
          "context": 1,
          "site": "site-b.test",
          "canvas": "a30ef280",
          "canvas_same_in_page": true,
          "audio": "b7a0343c",
          "cores": 64,
          "memory": 32,
          "plugins": "1b059b58",
          "plugin_names": [
            "PDF Viewer",
            "Chrome PDF Viewer",
            "Chromium PDF Viewer",
            "Microsoft Edge PDF Viewer",
            "WebKit built-in PDF"
          ],
          "screen": "1280x720",
          "window": "1288x805"
        }
      ],
      "pages": {
        "creepjs": {
          "like_headless_pct": 50,
          "headless_pct": 0,
          "stealth_pct": 0,
          "privacy": "unknown",
          "canvas_noise": null,
          "lies": []
        },
        "browserleaks": {
          "signature": "D64418DFFDD77D1444AE9BD3549AEFEE",
          "uniqueness": "99.95% (119 of 258037 user agents have the same signature)"
        },
        "sannysoft": {
          "checks": 31,
          "failed": 1,
          "failed_names": [
            "WebGL Renderer"
          ]
        },
        "deviceandbrowserinfo": {
          "is_bot": true,
          "signals": [
            "hasInconsistentTimingResolution",
            "isAutomatedWithCDP",
            "isAutomatedWithCDPInWebWorker",
            "hasSuspiciousWeakSignals"
          ]
        },
        "fingerprint": {
          "bot": "You are a bad bot (type: chromium_automation)",
          "suspect_score": 47
        }
      }
    }
  ]
}

Takeaways