Scrapeless Wiki

What Is Performance Fingerprinting? – Definition and How It Works

Informational P3 what is performance fingerprinting

Learn how timing measurements expose real hardware and virtualisation, and why this defeats property spoofing.

Performance fingerprinting measures how fast a browser actually executes work, rather than reading what it claims about itself. That distinction is what makes it hard to defeat.

1. Measuring Instead of Asking

Every other fingerprinting surface reads a declaration β€” a user agent string, a core count, a renderer name β€” and declarations can be patched.

Performance fingerprinting runs a workload and times it:

function benchmark() {
  const t0 = performance.now();
  let x = 0;
  for (let i = 0; i < 3_000_000; i++) x = (x * 31 + i) % 1_000_003;
  const cpu = performance.now() - t0;

  const t1 = performance.now();
  const a = new Float64Array(1 << 16);
  for (let i = 0; i < a.length; i++) a[i] = Math.sqrt(i);
  const mem = performance.now() - t1;

  return {cpu, mem};
}

A patched hardwareConcurrency claiming 16 cores cannot make the loop finish faster. The measurement contradicts the claim, and the contradiction is the finding.

2. What Timing Reveals

Measurement Reveals
Integer loop time Raw CPU speed
Typed-array work Memory bandwidth
Canvas or WebGL render time GPU versus software rendering
Crypto operation time Hardware acceleration presence
JIT warm-up curve Engine and version behaviour
Timer resolution Browser and platform

Render timing is particularly telling: software rasterisation is dramatically slower than a real GPU, so a session claiming a high-end desktop that renders slowly is inconsistent.

3. Virtualisation and Throttling Show Up

Containers and VMs behave measurably differently from bare metal:

  • CPU quotas produce characteristic stalls when the quota is exhausted.
  • Shared, oversubscribed hosts show high variance between runs.
  • Software rendering is orders of magnitude slower for graphics work.
  • Timer behaviour can differ under virtualisation.

A fleet of sessions on one oversubscribed host will also show correlated slowdowns, which is a pattern across sessions rather than within one.

4. Timer Resolution Is Itself a Signal

Browsers deliberately coarsened performance.now() resolution to mitigate timing attacks such as Spectre, and the exact granularity differs by browser, version, and whether cross-origin isolation is active.

const deltas = new Set();
let last = performance.now();
for (let i = 0; i < 5000; i++) {
  const now = performance.now();
  if (now !== last) { deltas.add(now - last); last = now; }
}
// the smallest observed delta approximates the clock granularity

The observed granularity should match the claimed browser. A mismatch indicates a spoofed user agent.

5. Why This Is the Hardest Surface to Fake

To defeat timing measurements you would have to make slow hardware appear fast, which is not something a JavaScript override can do. The options are all unattractive:

  • Patch performance.now() to lie β€” detectable, since it is a native function and its behaviour is cross-checkable against Date.now() and other clocks.
  • Slow down deliberately to match a claimed weaker device β€” possible, but it makes everything slower and must be applied consistently.
  • Actually provide the hardware β€” the only clean answer.

That last option is the practical recommendation: give the environment real CPU, real memory, and hardware-accelerated rendering, and the measurements agree with the claim without any patching.

6. Beyond Detection: It Affects Your Data

Performance also determines whether pages finish loading correctly. An underprovisioned container produces:

  • Timeouts on heavy pages that a normal machine handles.
  • Truncated rendering where a wait expires mid-load.
  • Flaky extraction that varies between runs for no content reason.

So provisioning adequate resources is a data-quality decision before it is a stealth one β€” and the symptoms of underprovisioning look exactly like site changes.

7. Practical Guidance

  1. Provision real resources β€” several CPUs, adequate memory, GPU acceleration where possible.
  2. Do not patch timing APIs. The cross-checks are easy and the failure is obvious.
  3. Keep claimed hardware consistent with what the environment can actually do.
  4. Avoid oversubscribed hosts for a fleet, since correlated slowness is a cross-session pattern.
  5. Measure your own environment and compare against a normal desktop, so you know what you look like.

8. Summary

Performance fingerprinting times real work β€” CPU loops, memory throughput, rendering, crypto, and timer granularity β€” instead of reading declarations, which is why it defeats property spoofing.

A patched core count cannot make a loop run faster, so the only clean response is provisioning genuine CPU, memory, and hardware-accelerated rendering β€” which also removes the timeouts and truncated renders that underprovisioned containers produce and that look deceptively like site changes.