Your audio reaction test is measuring your audio stack.
An AudioContext reports two numbers that matter: baseLatency (what the graph itself adds) and outputLatency (the estimate from graph to speaker). On desktop Chrome with the default hint those are typically a few milliseconds each. On Bluetooth headphones they can be 150 to 300 ms, and on some Android devices they are not reported at all.
That range is the entire signal you are trying to measure. A 200 ms audio reaction on wired headphones and a 200 ms audio reaction on Bluetooth are not comparable, and the second is probably closer to 350 ms of real human response.
Ask for the low-latency context
const ctx = new AudioContext({ latencyHint: 'interactive' });
await ctx.resume();
console.log(ctx.baseLatency, ctx.outputLatency);
latencyHint: 'interactive' tells the browser to prefer a small buffer over glitch resistance. The default, balanced, is fine for music and wrong for timing tests.
Schedule the beep, don't fire it
const at = ctx.currentTime + 0.05;
const osc = ctx.createOscillator();
osc.frequency.value = 880;
osc.connect(ctx.destination);
osc.start(at);
const perceived = at + (ctx.outputLatency || ctx.baseLatency || 0);
perceived is your best estimate of when the sound left the machine. Subtract that from the response timestamp instead of from the moment you called start(); otherwise every score silently includes the full output buffer.
Be honest in the UI
If outputLatency is above roughly 50 ms, warn the user that their headphones may be inflating the score. Otherwise players conclude that audio reactions are slower than visual ones, which is generally false - visual and auditory simple reaction times are close, with audio often marginally faster when both are measured properly.
Measure it
No API reports true end-to-end latency, so the only reliable method is a loopback: play a click, record it with the microphone, compare timestamps. That is overkill for a casual test, but it is the only way to know how wrong outputLatency is on a given device.
I apply all of this in a small browser audio reaction test that shows the measured output latency next to the score, so the number arrives with its own error bar. If you build anything that measures human timing with sound, do the same - otherwise you are measuring your audio stack, not your users.
Top comments (0)