Skip to content

Fingerprint consistency checker

A real browser's fingerprint is full of cross-surface correlations: a Mac reports an Apple GPU, a desktop has no battery, a 4K Retina panel reports a DPR of 2.0. Bot detectors actively look for combinations that violate these correlations — "macOS with an NVIDIA GPU" or "a phone touchscreen on a Linux desktop" — because no real hardware ships that way.

Ghostvault ships a heuristic consistency checker that flags the most obvious impossible combinations before they ever reach the browser. It runs:

  • on every gv_create_account call (over the resolved device_config + profile), and
  • over the warning strings it produces are returned to the caller.

What it checks

The checker is implemented as check_consistency() in src/ghostvault/browser/device_profiles.py. It runs five independent heuristics:

1. OS ↔ GPU vendor

Apple Silicon GPUs only appear on macOS. NVIDIA and AMD GPUs are Windows/Linux territory. The checker cross-references the os argument against webGl:vendor / webGl:renderer.

OS GPU pattern Result
macos NVIDIA Warning: "macOS with an NVIDIA GPU is extremely rare — likely a bot tell"
macos AMD / Radeon Warning: "macOS with an AMD GPU is rare (only Mac Pro with AMD cards)"
macos non-Apple vendor Warning: "macOS usually has vendor 'Apple Inc.', got …"
windows / linux Apple GPU Warning: "{os} with an Apple GPU is impossible"

2. Touch ↔ screen

A desktop OS with navigator.maxTouchPoints > 5 is suspicious unless it's a known touch device (Surface, touchscreen monitor). We can't enumerate every touch model, so only the obviously-wrong combo is flagged.

OS maxTouchPoints Result
linux > 5 Warning: "Linux with > 5 touch points is unusual — most Linux desktops have no touchscreen"

The Surface Laptop 5 profile is the only bundled profile with maxTouchPoints > 0 (it reports 10).

3. DPR range

window.devicePixelRatio outside the realistic range is a strong tell.

DPR Result
< 1.0 Warning: "devicePixelRatio < 1.0 is very rare"
> 3.0 Warning: "devicePixelRatio > 3.0 is unusual (phones cap at ~3x)"

4. Audio sample rate

AudioContext:sampleRate must be a rate real hardware actually uses.

Valid rates: 22050, 32000, 44100, 48000, 88200, 96000, 192000. Anything else produces:

"AudioContext sampleRate {sr} is not a standard rate (44100/48000 are most common)"

5. Core count plausibility

navigator.hardwareConcurrency outside the 1–128 range produces:

"hardwareConcurrency {cores} is implausible (range: 1–128)"

Heuristic, not exhaustive

The checker deliberately does NOT flag battery-on-desktop, because we can't always know the hardware from the config alone. Use a device profile that omits battery keys for desktop hardware — the imac-24, windows-desktop-rtx, linux-workstation, and headless-server profiles all do this correctly.

How warnings are surfaced

Warnings are non-fatal — they never block account creation. They appear in the consistency_warnings field of the gv_create_account response:

{
  "id": "a913fd57244a",
  "name": "Bad",
  "os": "macos",
  "device_profile": null,
  "device_config": {
    "webGl:vendor": "Google Inc. (NVIDIA)",
    "webGl:renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 ...)",
    "window.devicePixelRatio": 4.0,
    "AudioContext:sampleRate": 12345,
    "navigator.hardwareConcurrency": 256
  },
  "consistency_warnings": [
    "macOS with an NVIDIA GPU is extremely rare — likely a bot tell",
    "devicePixelRatio 4.0 > 3.0 is unusual (phones cap at ~3x)",
    "AudioContext sampleRate 12345 is not a standard rate (44100/48000 are most common)",
    "hardwareConcurrency 256 is implausible (range: 1–128)"
  ]
}

When you're scripting with the SDK, the warnings come back as part of the JSON result — parse with json.loads and inspect the list:

import json
result = await gv.create_account(
    name="Bad",
    os="macos",
    device_config={
        "webGl:vendor": "Google Inc. (NVIDIA)",
        "window.devicePixelRatio": 4.0,
    },
)
data = json.loads(_text(result))
if data["consistency_warnings"]:
    print("Bot tells:", data["consistency_warnings"])

Treat non-empty warnings as a bug in your config

Detectors weight impossible combinations heavily. If consistency_warnings is non-empty, the right move is almost always to fix the config — not proceed. Start from a device profile and override only the keys you need.

Examples of impossible combos

Combination Why it's flagged
os=macos + webGl:renderer="ANGLE (NVIDIA, ...)" No Mac ships with an NVIDIA GPU
os=windows + webGl:vendor="Apple Inc." Apple GPUs are Apple-Silicon only
os=linux + navigator.maxTouchPoints=10 Most Linux desktops have no touchscreen
window.devicePixelRatio=4.0 Above the ~3× cap on real phone panels
window.devicePixelRatio=0.5 No real display reports sub-1.0 DPR
AudioContext:sampleRate=12345 Not a rate any DAC produces
navigator.hardwareConcurrency=0 Below the plausible minimum
navigator.hardwareConcurrency=256 Above the plausible maximum