Audio Fingerprinting: How the AudioContext Signal Works
How browser audio fingerprinting works, how much entropy it adds, and how to collect it — with working code.
Audio fingerprinting is one of the signals a browser exposes for visitor identification — alongside canvas, WebGL, and installed fonts — produced by the Web Audio API rather than anything played through a speaker. This article covers how an AudioContext produces that signal, why the output differs from one machine to the next, how much entropy it's actually worth, and what browser defences have done to it — with working code you can run yourself.
What Is Audio Fingerprinting?
Browser audio fingerprinting renders a short signal through the Web Audio API and hashes the output — it measures how a browser's audio stack processes sound, producing a value that's consistent for a given machine and browser but differs across others. Nothing plays through the speakers: the signal is rendered entirely in software, off-screen and inaudible, and read back as data.
It's one signal within browser fingerprinting, the broader practice of identifying a returning visitor from characteristics their browser exposes. Audio sits alongside the other signals covered in our overview of browser fingerprinting techniques — this page goes deep on how the audio signal specifically works.
How the AudioContext Signal Is Produced
The standard approach uses an offline AudioContext: generate a waveform with an oscillator, run it through a DynamicsCompressorNode, render the result, and hash the output buffer. Nothing is audible — OfflineAudioContext processes the signal as fast as possible in memory rather than playing it in real time. This is the mechanism behind what's sometimes called the audiocontext fingerprint — the same underlying technique, named for the API that produces it.
The output varies by machine for reasons that sit below the level most developers ever touch. Browser audio engines trace back to a small number of shared codebases, and small implementation differences have accumulated across forks and versions since. The oscillator and compressor nodes involve floating-point arithmetic, and floating-point rounding isn't identical across CPU architectures and SIMD instruction sets — a chip that vectorizes the math differently produces a measurably different result from the same input. On top of that, the underlying audio chipset and its driver introduce their own small variations in how a signal is processed. None of this is a bug; it's the ordinary consequence of the same computation running on different hardware and software stacks, and it's stable for a given machine and browser combination even though it differs across combinations.
That combination of stability and variation is what makes the signal usable at all. Render the same oscillator-through-compressor signal twice on one machine in one browser, and the output matches — no randomness is involved unless a browser deliberately introduces it. Render it on a different CPU, a different audio driver, or even a different major version of the same browser engine, and the output shifts. A tracking signal needs exactly that combination: consistent enough to recognize a return visit, sensitive enough to differ between visitors.
How Much Entropy Does Audio Actually Contribute?
Audio is a moderate-entropy signal — useful, but nowhere near as discriminating on its own as canvas or font rendering. Its value comes from where it sits in the stack rather than from raw uniqueness: audio is produced by the DSP and audio-hardware path, while canvas fingerprinting and WebGL are produced by GPU rendering. Because those are largely separate subsystems, a machine that happens to share a canvas hash with another visitor often won't share an audio hash too — so combining them narrows the pool further than either signal would alone.
ThumbmarkJS's open-source library collects audio alongside canvas, WebGL, fonts, screen, and locale signals and hashes them together, reaching roughly 80% uniqueness across a large visitor population; adding server-side signals through the API raises that to around 99%. Audio is one contributor to that figure, not the source of it — which is exactly why the fingerprint stays usable even when a browser has normalized or blocked the audio component specifically. Running across 60,000+ websites, that component mix is also the practical proof that a moderate signal like audio still earns its place: it's cheap to collect and it fails independently of the other components, which is what keeps the combined figure high.
Consider two visitors on similar laptops who happen to share a GPU model and driver version — their canvas and WebGL output could plausibly collide. If their audio chipsets or CPU architectures differ even slightly, their audio hashes still diverge, so the combined fingerprint separates them anyway. That's the practical case for collecting a moderate-entropy signal at all: it doesn't need to be strong by itself, it needs to fail independently of the signals it's paired with.
Audio Fingerprinting Protection: What Browsers Do About It
Browser defences here lean toward normalizing the signal rather than removing it outright, and the distinction matters for how you should collect it:
Firefox. With
privacy.resistFingerprintingenabled, Firefox doesn't disable the Web Audio API — Mozilla considered that approach and chose not to ship it, reasoning that the entropy at stake didn't justify breaking legitimate uses like video calling. Instead, RFP standardizes parameters that would otherwise vary (locking the sample rate, for instance) and patches the underlying math operations to strip out hardware-specific floating-point variation. The result is a signal that's consistent across machines with RFP enabled, rather than absent.Brave. Brave's "farbling" applies a randomized fudge factor to the audio output, seeded per browsing session, so the hash changes from one session to the next even on the same machine. The degree of perturbation scales with Brave's shields settings, from a lighter default to a stricter mode.
Tor Browser. Tor Browser ships Firefox's resistFingerprinting protections enabled by default, so it inherits the same normalization approach as Firefox RFP rather than disabling the API separately. That still leaves some platform-level variation — architecture and OS differences that RFP doesn't try to mask because doing so would break other things — but it removes the finer-grained hardware entropy the signal would otherwise carry.
Verify current behaviour before you rely on any of this in production; browser privacy engineering shifts, and normalization approaches in particular tend to get refined over time. The practical effect across all three is the same: a normalized or randomized audio component still returns a value, it carries less machine-specific information than it would in an unprotected browser.
Should You Still Collect Audio in 2026?
Yes, as one signal among many. It's useful precisely because it's independent of the rendering-based signals — a visitor whose canvas or WebGL output has been randomized may still contribute a clean audio signal, and vice versa. It's never sufficient on its own, and it needs graceful degradation: when a browser normalizes or blocks the component, a well-built fingerprint falls back on the remaining signals rather than failing outright.
That degradation needs to be active, not passive. A fixed sample rate or a value that matches the known Firefox RFP baseline is a signal in itself — it tells you the component has been normalized, so weighting it down (or excluding it from the hash) preserves the accuracy of the combined fingerprint instead of letting a flattened value quietly dilute it. The same logic applies to Brave's farbled output once it's recognizable as such. Treat audio as a component to monitor for its own reliability, not only a value to collect.
Collecting the Audio Signal in Practice
A raw audio fingerprint is a short piece of vanilla JavaScript. This illustrates the mechanism — render, read back, hash — and isn't production-grade: it has no fallback for browsers that normalize the output and no error handling. The oscillator and compressor settings below aren't arbitrary; a triangle wave through a compressor with these threshold, knee, and ratio values is the combination most fingerprinting implementations converge on, because it reliably drives the dynamics-processing math hard enough to expose floating-point differences without producing a signal so extreme that browsers clip it identically everywhere.
// Illustrative audio fingerprint — render, read back, hash. Not production-grade.
async function audioHash() {
const context = new OfflineAudioContext(1, 5000, 44100);
const oscillator = context.createOscillator();
oscillator.type = 'triangle';
oscillator.frequency.value = 1000;
const compressor = context.createDynamicsCompressor();
compressor.threshold.value = -50;
compressor.knee.value = 40;
compressor.ratio.value = 12;
oscillator.connect(compressor);
compressor.connect(context.destination);
oscillator.start(0);
const buffer = await context.startRendering();
const samples = buffer.getChannelData(0);
let hash = 0;
for (let i = 0; i < samples.length; i++) {
hash = (hash << 5) - hash + Math.floor(samples[i] * 100000);
hash |= 0; // force 32-bit integer
}
return hash.toString(16);
}In production you want the audio signal collected, stabilized, and combined with the other components rather than used alone. ThumbmarkJS returns it as one entry under result.components, so you can read the audio value directly while the library handles rendering and fallback:
// The same signal in context, via the ThumbmarkJS open-source library
import { Thumbmark } from '@thumbmarkjs/thumbmarkjs';
const tm = new Thumbmark();
const result = await tm.get();
result.thumbmark; // combined fingerprint hash
result.components.audio.sampleHash; // the audio component value
// get() never throws — check result.error for component failuresThis page covers the technique; for a full walkthrough of wiring a fingerprint into a real flow, see our guide to implementing browser fingerprinting in JavaScript, which owns the build end to end.
Conclusion
Audio fingerprinting is a moderate-entropy signal whose real value is independence, not raw strength — it draws on a different part of the stack than the GPU-rendering signals, so it holds up even when they've been randomized or blocked, and vice versa. Collect it as one component in a combined fingerprint, expect browsers to normalize rather than remove it, and build in a fallback for when they do.
To see your own audio component inside a real fingerprint, see your own fingerprint components in the live demo, or read the collection code in the open-source library on GitHub.
Frequently Asked Questions
Can audio fingerprinting be blocked?
Yes: Firefox's resist-fingerprinting mode, Brave's audio farbling, and Tor Browser all normalize or perturb the signal rather than leaving it untouched. Normalizing standardizes the output so it's the same across many machines, which reduces its value for identification without necessarily eliminating it; randomizing changes the hash from session to session, which breaks stability entirely.
Does audio fingerprinting require playing sound?
No. It uses an offline AudioContext, which renders and processes the signal entirely in memory — nothing plays through the speakers, and the user never hears anything.
How unique is an audio fingerprint on its own?
Not very. It's a moderate-entropy signal, most valuable combined with other components because it draws on a different part of the browser and audio-hardware stack than rendering-based signals. On its own, a fingerprint — audio included — identifies a browser environment, never a device or a person.