AudioContext.baseLatency is the processing latency, in seconds, that a Web Audio context adds before its output reaches the operating system's audio subsystem. Chrome works it out from the audio callback's buffer size and the sample rate. Both belong to the computer's audio hardware, not to the browser profile. So every profile on one machine reports the same baseLatency, and when the output device changes the figure can change for all of them at once.

Its sibling, outputLatency, behaves the same way and has one more twist. We claim both per profile in our engine, in patch 0112, and getting the second one right took two attempts.

What baseLatency and outputLatency measure

The Web Audio specification splits the delay between a page scheduling a sound and the sound coming out of a speaker into two parts.

PropertyCoversIn Chrome
baseLatencythe context's own processing, up to the audio subsystembuffer size divided by sample rate, known when the context is created
outputLatencyfrom the audio subsystem to the device playing the first sample0 until the audio callback has run, then the hardware's estimate

The figure is a short division. A callback of 256 frames at 48,000 Hz gives 0.005333333333333333. Reading it costs a page three lines:

const ctx = new AudioContext()
ctx.baseLatency     // a figure straight away
ctx.outputLatency   // 0 until something has played

There is no permission prompt and no user gesture involved. The context can stay suspended and the read still works.

Every profile is drawn from one real computer, not from separate listsIn Mosaic: Machines that exist. GPU, screen, CPU and fonts from one real device. Free holds 3 profiles. Pro is $49 a month for any number.

How it works: Machines that exist

Why the figure tracks the computer, not the profile

Most fingerprint values a profile can claim are about the machine it pretends to be. These two are about the machine it runs on. The buffer size and the sample rate come from the output device and its driver. Any number of profiles opened on one computer read the same pair of floats.

That makes the pair a join key rather than a weak signal. A site that sees two supposedly unrelated visitors with identical audio latencies has one more reason to think they sit at the same desk. And because the figures follow the output device, they change when it does: plug in headphones or switch to a different output and every profile on the machine can move together.

The audio noise our engine adds doesn't help here. Patch 0007 perturbs the samples a page renders and reads back, which is what an OfflineAudioContext fingerprint hashes. Timing is a different surface. Without its own claim, a page could read a per-profile audio hash beside the computer's honest latency, which is a mismatch of its own.

How we draw a latency per profile

Each profile gets its pair from its own seed when it launches. The draw picks a buffer of 128, 256 or 512 frames and a sample rate of 44,100 or 48,000 Hz, and sends the quotients as launch switches. The pair doesn't change between launches, and it doesn't change when you plug in headphones.

The first version of that draw printed the figure with toFixed(6). That produced 0.005333, where branded Chrome on the same machine said 0.005333333333333333. No division of whole frames by a real sample rate produces a number that stops at six decimals, so the rounded value was one a real browser could never report. It was the one audio value where we disagreed with Chrome in kind rather than in noise. We now send the whole quotient, printed the shortest way that round-trips to the same double, which is how the engine would print it.

outputLatency has a value and a moment

outputLatency caught us a second way. Chrome computes it from a position the audio callback writes. On a context that has not rendered anything, it answers 0. Our patch returned the profile's figure from the first line of the function, before any of that work. Same flags, same page, one launch each:

branded Chrome 153, suspended          outputLatency 0
our engine,         suspended          outputLatency 0.010666666666666666
branded Chrome 153, after rendering    outputLatency 0.024

A number where every Chrome we measured has a 0 is a positive identification. The patch now lets the real state decide when there is a latency to report, and the switch decides only what it is. On the rebuilt engine a suspended context reads 0, and a context that has rendered reads 0.021333, the profile's claim rather than the hardware's 0.024. baseLatency needs no such gate, because Chrome knows the buffer size when the context is built and reports a non-zero figure from the first read.

How to check your own

Open the same page in two browser profiles on one computer and log both properties. Do it once with the context suspended and once after an oscillator has played for a second at a gain nobody can hear. Then switch the output device and repeat. If both profiles print the same figures, and both change when the device changes, the pair is identifying the computer.

It is the same class of fault as a value pinned across every profile: nothing leaks in, but one figure is shared by everything on the machine, and a site can read that as well as a leak. The rest of each profile's hardware, from the GPU to the fonts, is drawn from real devices.