Anti-Bot

What Is AudioContext Fingerprinting?

What Is AudioContext Fingerprinting? — conceptual illustration
On this page

AudioContext fingerprinting plays a silent waveform through the Web Audio API, then reads back the resulting floating-point samples and hashes them. The output is determined by the exact audio subsystem — operating system audio mixer, DSP library, CPU floating-point behaviour, and audio driver. Two devices with otherwise-identical fingerprints produce subtly different audio hashes, and headless browsers without a real audio stack produce a small set of giveaway values.

Quick facts

ReadsFloating-point output of a known oscillator + biquad filter chain
Why it worksAudio subsystem produces hardware/OS-dependent rounding differences
Headless tellOfflineAudioContext returns one of ~3 known hashes when no real audio stack exists
Used byPerimeterX, DataDome, Akamai (as one of dozens of signals)
DefeatsVanilla headless Chrome, most stealth plugins

How the probe works

The standard probe uses OfflineAudioContext — a Web Audio API that renders samples without actually playing them, so the user hears nothing. The script creates an oscillator at a known frequency (typically 1000 Hz), routes it through a DynamicsCompressorNode or BiquadFilterNode with known parameters, renders ~5000 samples, and hashes them with SHA-256.

The hash is stable per (browser, OS, CPU architecture, audio driver) and varies between them. Two iPhones produce the same hash; an iPhone and an Android produce different hashes; a real macOS user and a headless Chrome on the same machine produce different hashes because the audio fallback path is different.

The headless tell

Headless Chrome on a server with no audio device falls back to a stub audio backend. The stub produces a small set of known hashes — roughly three distinct values across the entire population of headless Chrome instances on Linux servers. Anti-bot vendors maintain a blocklist of these specific hashes and flag any request matching them.

Even with --use-fake-device-for-media-stream and similar Chrome flags, the OfflineAudioContext path is independent of media-device flags. The fix is one of: (1) run on a machine with a real audio device passed through to the browser, (2) install a virtual audio driver (PulseAudio dummy sink, BlackHole on macOS) that produces real-machine-like output, or (3) use a tool that patches AudioContext at the engine level (Camoufox, CloakBrowser).

Why naive spoofing fails

Spoofing AudioContext in JavaScript is detectable in two ways. First, Function.prototype.toString() on the patched method reveals the patch — real Chrome's AudioContext.prototype.createOscillator.toString() returns "function createOscillator() { [native code] }"; a JS replacement returns the patch source. Second, the timing of OfflineAudioContext.startRendering() on a real audio stack vs a JS-stubbed one differs by orders of magnitude, and that timing is itself fingerprinted.

The only reliable mitigation is patching at the browser-engine level (below the JS layer) so toString() still returns [native code] and the render timing matches a real machine. This is what differentiates Camoufox / PatchRight from playwright-extra-plugin-stealth.

Code example

javascript
// The standard AudioContext probe used by major anti-bot vendors
async function audioFingerprint() {
  const ctx = new OfflineAudioContext(1, 5000, 44100);
  const osc = ctx.createOscillator();
  osc.type = 'triangle';
  osc.frequency.value = 1000;

  const compressor = ctx.createDynamicsCompressor();
  compressor.threshold.value = -50;
  compressor.knee.value = 40;
  compressor.ratio.value = 12;
  compressor.attack.value = 0;
  compressor.release.value = 0.25;

  osc.connect(compressor);
  compressor.connect(ctx.destination);
  osc.start(0);

  const buf = await ctx.startRendering();
  // sum a stable slice — anti-bot vendors usually hash samples 4500-5000
  let sum = 0;
  for (let i = 4500; i < 5000; i++) sum += Math.abs(buf.getChannelData(0)[i]);
  return sum.toString();
}
// Headless Chrome on Linux servers returns ~3 distinct values — blocked everywhere.

Related terms

Concept map

How AudioContext Fingerprinting connects

The terms most directly tied to this one. Hover a node to see its neighbours, click to preview, drag to rearrange.

0 terms · 0 connections
You are here · Anti-Bot
Building map…

Frequently asked questions

Why don't scrapers just disable the Web Audio API?

Disabling Web Audio means OfflineAudioContext returns undefined or throws, which is a stronger signal than any specific hash. Real browsers always have a working Web Audio API. The detection asks "what does it produce", not "does it exist" — disabling is worse than failing the probe.

How distinctive is the audio hash compared to canvas?

Less distinctive between real users (collision rates around 1-in-1000 for popular configurations) but more distinctive between real and headless (the headless cluster is tiny and well-known). It is most useful as a headless-detection signal rather than a unique identifier.

Can I run a virtual audio device to fix this?

Yes, on Linux PulseAudio with a dummy sink produces real-machine-like output, and on macOS BlackHole works similarly. The catch is that the hash needs to be coherent with the rest of the fingerprint — a Linux PulseAudio hash on a request claiming to be Windows is its own tell.

Last updated: 2026-05-27