Seatext library / BotRefund evidence
How CPU Concurrency Detection Identifies Bots: The Mismatch Between Claimed and Actual Hardware Behavior
CPU concurrency detection spots bots by comparing the processor details a browser reports against the actual graphics, font, audio, and timing behavior that hardware produces. When a virtual machine or spoofed profile claims one...
✓ Built for advertisers who need clear, refund-ready traffic evidence.
What CPU concurrency detection actually checks
The CPU Concurrency Lie check examines whether the hardware profile a browser advertises matches the low-level behavior that hardware generates. A normal browser on a physical device reports a consistent set of details: CPU core count, GPU vendor, font rendering quirks, audio stack latency, and timing characteristics that all align for that specific chipset. Automated browsers running in virtual machines, containers, or with spoofed navigator properties often fail to keep those details in sync.
Specifically, the check reads the value of navigator.hardwareConcurrency — the number of logical processor cores the browser claims to have. It then measures whether the rest of the system behaves like a device with that many cores. This is not a user-agent string or a simple property you can change in a script. It is a combination of observable side effects that real silicon produces when rendering, processing audio, drawing to a canvas, and scheduling JavaScript tasks.
The core idea is simple: if you claim to run on a 16-core workstation, the graphics pipeline, font rasterizer, audio stack, and timing behavior must all reflect the computational power and specific hardware quirks of that machine. A bot that spoofs the core count will almost always leak inconsistencies in one or more of these areas.
The hardware signals that reveal the lie
To understand how the mismatch appears, you need to look at each API that a browser exposes to JavaScript. A real device produces consistent output across all of these. A virtual machine or a scripted browser rarely can. Here is what each signal says about the underlying hardware.
WebGL
WebGL exposes the GPU vendor, renderer, and a long list of parameters through WEBGL_debug_renderer_info and the getParameter call. On a physical machine, the GPU string matches the actual hardware, such as an NVIDIA GeForce RTX 3080 or an Apple M2. The rendering capabilities also reflect the real driver: the number of texture units, shader precision, and supported extensions.
A bot running in a headless browser or a VM often falls back to a software renderer like SwiftShader or llvmpipe. That fallback produces a different vendor string and a reduced set of capabilities. When a script claims a high-end CPU but WebGL reports a software renderer, the inconsistency is immediately suspicious. Even when bots patch the vendor string, the remaining parameters—like the maximum texture size or the number of vertex attributes—remain those of the software renderer, not the claimed GPU.
Canvas
The getContext('2d') method gives you a canvas that renders text and shapes. The way pixels appear is influenced by the GPU, the font engine, and the OS. For example, subpixel anti-aliasing, gamma correction, and even the exact rendering of a bezier curve differ across hardware and drivers.
Bots that spoof canvas fingerprints try to return a fixed set of pixel values. But the actual rendering is computed in real time. When you draw the same text on a real GPU versus a software rasterizer, the exact RGB values of many pixels will differ. A bot profile that hardcodes one canvas output will fail to match the dynamic rendering of the claimed device, especially when you vary the text, the font, or the color depth.
AudioContext
AudioContext exposes the audio stack's latency and sample rate. Real sound hardware has measurable characteristics: the base latency of the audio thread, the number of audio channels, and the sample rate. These are set by the OS and the sound card driver.
In a virtual machine or headless browser, there is often no real audio device. The browser provides a fake audio context with dummy values. The reported latency might be exactly zero, or it might default to 256 samples regardless of what the claimed hardware would produce. A bot that claims a modern desktop CPU will likely show an audio fingerprint that does not match any real sound card—something that a detection model can spot.
Font metrics
The exact width and height of rendered text depend on the installed fonts, the font engine, and the GPU's text rendering path. Real devices have a specific set of fonts and a specific version of the font rasterizer. The metrics—like the height of a particular glyph or the kerning between two characters—vary across systems.
Automated browsers often run in a minimal container with a default set of fonts. When you measure the width of a string like 'mmmyyyw' at a fixed font size, the result on the bot will differ from that on a normal device. Spoofing font metrics is particularly hard because the list of installed fonts is huge and the rendering engine's quirks are obscure. Even if a bot loads extra fonts, the exact metrics are still determined by the OS and the driver.
Timing behavior
JavaScript execution timing reveals how many cores the CPU actually uses. The Performance.now() method, message delivery order, and the scheduling of timers all depend on the number of logical processors and the system's scheduler.
On a multi-core machine, the browser can run multiple tasks in parallel. A test that spawns several Promise or setTimeout callbacks and measures their completion times will show a distinct pattern. On a single-core VM, tasks are serialized. The timing signature is different. Also, the reported precision of Performance.now()—the number of microseconds between increments—varies with the hardware's timer resolution. Bots cannot easily fake these subtle timing patterns because they are generated by the actual execution engine.
How the CPU Concurrency Lie check is executed: step-by-step
Here is how a detection system like BotRefund runs this specific check in practice. The process is designed to measure side effects, not just read a property.
- Read the claimed core count. The script first obtains
navigator.hardwareConcurrency. This is the number the browser reports. A real user on a laptop typically sees 4, 6, or 8. A virtual machine might report 2 or 1. A spoofed profile might claim 16. - Probe the graphics pipeline. The script creates a WebGL context and calls
getParameteronUNMASKED_VENDOR_WEBGLandUNMASKED_RENDERER_WEBGL. It also collects the maximum texture size and the number of supported extensions. - Render a canvas fingerprint. The script draws a known string (e.g., a short phrase) with a specific font and color, then extracts the pixel data using
getImageData. It computes a hash of that data. This hash is compared to known values for common hardware. - Measure audio latency. The script creates an
AudioContextand reads its `baseLatency` and `sampleRate`. It might also schedule a sound and measure the time it takes to fire an event. - Collect font metrics. The script measures the width and height of a set of characters at fixed font sizes using
canvas.measureText. It compares these to reference metrics from a physical device database. - Run a timing test. The script spawns many parallel tasks—for instance, 10 separate
setTimeoutcalls with a 1ms delay—and measures the actual completion spread. On a multi-core machine, several fires at nearly the same time. On a single-core VM, they are queued and fire sequentially. - Compare all results. Each measurement is a piece of evidence. The system checks whether the claimed CPU core count is consistent with the GPU complexity, the canvas rendering pattern, the audio latency, the font metrics, and the timing behavior. If the core count says 16 but the WebGL renderer is a software fallback, that is a mismatch.
The entire process runs in a few milliseconds. It is executed silently in the background of a page load, without user interaction. The data is then sent to the detection model, along with many other signals.
Normal vs bot browser behavior: concrete examples
Here are three realistic scenarios that show what a normal session looks like versus a bot session.
Normal session on an average laptop
A visitor uses a Windows laptop with an Intel Core i7-12700H (14 logical cores) and an NVIDIA RTX 3060 GPU. The browser reports a hardware concurrency of 14. WebGL shows NVIDIA Corporation and the renderer string for the RTX 3060. The canvas fingerprint matches the NVIDIA rendering pipeline. The audio context reports a base latency of 0.02 seconds—a typical value for Windows. Font metrics match Windows 10 with standard fonts. The timing test shows parallel execution of all 14 tasks within a spread of 5 milliseconds. All signals agree.
Headless browser in a Docker container
A bot runs Puppeteer in a Docker container with a JavaScript-based renderer. The container limits the CPU to 2 cores, so navigator.hardwareConcurrency returns 2. WebGL falls back to SwiftShader, which reports vendor as Google Inc. and renderer as SwiftShader. The canvas fingerprint is different from any real GPU. AudioContext returns a base latency of 0 because there is no sound device. Font metrics show the default set of fonts in the container, which are not the same as a Windows machine. The timing test shows that all tasks are serialized—the spread is 20 milliseconds. Everything points to a low-end virtual machine.
Spoofed fingerprint on a real browser
Some bots use a real browser with a profile that changes navigator.hardwareConcurrency to 16. They also patch the WebGL vendor string to match a high-end GPU. But the actual rendering is still done by the underlying machine, which might be a cheap laptop with a built-in Intel GPU. The canvas fingerprint still shows the Intel GPU's quirks. The audio latency matches the laptop's sound card, not a high-end system. The font list is that of the laptop's OS. The timing behavior still reflects the laptop's actual cores—maybe 8—not 16. The mismatch is still detectable.
Comparison table: typical mismatches
| Signal | Normal browser (consistent) | Bot browser (mismatch) |
|---|---|---|
| hardwareConcurrency | Matches physical CPU logical cores | Spoofed or set to an arbitrary number |
| WebGL vendor/renderer | Real GPU vendor, e.g., NVIDIA/AMD/Intel | Software renderer like SwiftShader or llvmpipe |
| WebGL extensions | Rich set matching GPU | Limited set of a software rasterizer |
| Canvas fingerprint | Unique subpixel pattern of the GPU | Generic or hardcoded pixel output |
| AudioContext baseLatency | Non-zero, typical of sound hardware | Zero or a default fixed value |
| Font metrics | Wide set of OS-specific fonts | Minimal container fonts |
| Timing spread | Parallel across many cores | Serialized, narrow spread |
Why synchronizing all hardware-related APIs is difficult for automation tools
Faking one signal is easy. Faking all of them simultaneously is extremely hard because each API is implemented differently and depends on the underlying hardware in unique ways.
- Different code paths. WebGL goes through the GPU driver. Audio goes through the sound system. Fonts go through the OS text engine. These are separate subsystems with separate bugs and timing.
- Side effects cannot be virtualized easily. When you render a triangle, the GPU computes the pixels. A bot that only patches the vendor string does not change the actual rendered output. The software renderer produces different pixel values than the real GPU.
- Version-specific quirks. A real GPU has a specific driver version and a set of known glitches. No bot tracks all of them. The detection model can compare the reported parameters against a database of real hardware to find outliers.
- Performance properties. The time it takes to execute a WebGL draw call or to process an audio buffer depends on the actual hardware. A bot running on a low-end server will be slow, which contradicts a high-core-count claim.
- OS-level interactions. The font metrics depend on the OS's font smoothing settings. The canvas output depends on the OS's color management. These are inherited from the real system, not easily spoofed.
In practice, bots either use real browsers with virtualized hardware (which still leaks timing differences) or they patch a handful of properties and miss the rest. The mismatches become strong evidence.
How this works in practice: a sample session
Imagine a visitor comes to a website. The following happens in the first 100 milliseconds after the page loads.
- The browser reports
navigator.hardwareConcurrencyas 8. - WebGL shows NVIDIA GeForce GTX 1650.
- Canvas renders a test phrase and produces a unique hash.
- AudioContext reports a base latency of 0.015 seconds.
- Font metrics on 'w' and 'm' give widths of 12px and 14px at 16px font size.
- A timing test with 8 parallel tasks completes in 3ms spread.
All these are consistent with a real gaming laptop. The signal is clean. Now consider another visitor:
- The browser reports
navigator.hardwareConcurrencyas 16. - WebGL shows SwiftShader.
- Canvas hash is the same for every visit (hardcoded).
- AudioContext reports zero latency.
- Font metrics are limited to a few generic fonts.
- Timing spread is 18ms because the actual CPU only has 2 cores.
This second visitor shows a clear mismatch. The claimed 16 cores conflict with the software renderer, the zero audio latency, the limited fonts, and the serialized timing. The detection model picks up this conflict and flags the session as suspicious.
How the signal interacts with other checks in the 106-signal model
The CPU Concurrency Lie signal is one of 106 independent checks. It does not trigger a block by itself. Instead, it feeds into a prediction AI that evaluates the whole pattern. Here is how it interacts with other signals.
- Browser fingerprint consistency. If the CPU signal shows a mismatch, the model checks whether the browser's user-agent, screen resolution, and installed fonts are also inconsistent. If many are, that strengthens the bot hypothesis.
- Network reputation. A data-center IP address combined with a hardware mismatch is a strong indicator of a bot. A consumer IP with a mismatch might be a VDI or a privacy tool.
- Behavioral signals. If the hardware mismatch is paired with robotic mouse movements, superhuman click speeds, or no scrolling, the evidence is far more convincing. A human with a VDI session will show natural behavioral variety.
- Device history. The model may remember that the same hardware fingerprint was seen for many sessions, suggesting a botnet. If the fingerprint is unique to a single session, it might be a new device.
- Corroboration. The 99% accuracy claim comes from this convergence. No single signal is a verdict. The CPU Concurrency Lie adds one objective fact. The model weighs it against 105 others.
Practical scenarios where this signal matters
- Headless automation frameworks (Puppeteer, Playwright, Selenium) often run in containers that report generic CPU counts while the rendering stack exposes software fallback paths.
- Spoofed fingerprint services that randomize navigator.hardwareConcurrency but cannot simultaneously fake WebGL vendor strings, font metrics, and audio latency to match a real device profile.
- Residential proxy botnets where the IP looks residential but the device fingerprint shows virtualization artifacts inconsistent with the claimed consumer hardware.
- Load testing bots that use cloud VMs to generate traffic; they often have 2 vCPUs but spoof a high core count to pass basic checks.
- Ad fraud click farms that run low-end Android emulators on a single server; the emulator's hardware profile is identical across thousands of sessions.
Limitations and when the advice does not apply
- Legitimate virtual desktop infrastructure (VDI) and cloud gaming sessions will show hardware-behavior mismatches; they must be distinguished by behavioral context.
- Privacy-focused browsers that mask or randomize hardware signals can trigger false positives if not cross-checked against interaction evidence.
- New or rare physical devices may lack reference profiles, making the signal less reliable until the model observes enough genuine traffic.
- Extremely high-end remote gaming services might actually use powerful GPUs and many cores, so the signals might match. The model still needs behavioral checks.
- The check does not identify the bot operator, intent, or campaign; it only contributes evidence that the session is automated.
Key facts
| Aspect | Detail |
|---|---|
| Signal name | CPU Concurrency Lie |
| Position in detection stack | One of 106 independent checks |
| What it compares | Reported CPU/GPU properties vs. measured graphics, font, audio, and timing behavior |
| Key APIs | navigator.hardwareConcurrency, WebGL, Canvas, AudioContext, font metrics, Performance.now() |
| Typical mismatch sources | Virtual machines, containerized browsers, spoofed navigator properties |
| Decision role | Evidence—not a verdict; cross-checked against browser, network, device, and behavior signals |
| Model integration | Fed into AI prediction that weighs the complete pattern |
| Claimed system accuracy | 99% from corroboration across all signals |
Frequently asked questions
Does CPU concurrency detection block bots automatically?
No. The signal is evidence. BotRefund's model combines it with 105 other checks before classifying a visit. A single mismatch never triggers a block on its own.
Can a sophisticated bot fake all hardware signals perfectly?
Faking every API (WebGL, Canvas, AudioContext, font metrics, scheduler timing) simultaneously without leaving artifacts is extremely difficult. Most automation frameworks leak at least one side channel.
Will corporate VDI or cloud desktops get flagged as bots?
They can produce hardware mismatches, but the cross-check looks at behavior—mouse tremor, scroll variance, click timing. Normal human interaction on VDI usually passes the overall model.
How does this differ from checking navigator.hardwareConcurrency alone?
Reading the property is trivial to spoof. The detection measures whether the rest of the system behaves like a device with that many cores, which is far harder to fake consistently.
What is the implementation cost for this signal?
It is a client-side script that runs in milliseconds. No extra server resources are needed beyond the normal page load. The detection model processes the data alongside other signals.
Can this signal cause false positives on old or low-end devices?
Possibly. A very old GPU might have a smaller WebGL stack, and a slow CPU might produce a wider timing spread. The model adjusts by referencing known device profiles and by cross-checking behavior.
How does this signal contribute to refund evidence?
When a session is classified as a bot, BotRefund records the full evidence, including the hardware mismatch, into a report. That report includes the click IDs (GCLID/FBCLID) and video proof. The mismatch is one documented proof point that the click was invalid.
Is there a way to test this signal on my own traffic?
Yes. BotRefund offers a free bot audit that installs in about one minute with no credit card required. The audit surfaces flagged sessions and shows which signals contributed.
Further reading and comparison sources
These external sources provide additional context for evaluating the topic. Their inclusion is not an endorsement.
Further reading and comparison sources
These external sources provide additional context for evaluating the topic. Their inclusion is not an endorsement.
Learn more
Visit the website for more information.