Signal · signalsVersion 5

vendor_flavors

Which of ten browser-specific global objects exist on the page, such as window.chrome or the globals iOS browsers inject.

vendor_flavors at a glance (from the library code, signalsVersion 5)
Component namevendor_flavors
In the visitorIdyes
structuredId groupbrowser (engine and build)
Hashingplain value; a digest only when longer than 128 characters or not printable ASCII
Excluded underno browser class
Inner timeout1000 ms
Added insignalsVersion 1
In plain words

Some browsers leave their own named objects on every web page, such as chrome in Chrome or the helper objects that Chrome and Firefox add on iPhone. WhiskerJS checks which of ten such names exist. It is a simple way to tell apart browsers that otherwise look alike, including different apps on iOS that all use Apple’s engine, and in-app browsers.

What it reads

Whether each of these globals exists on the window and is not null or undefined: __crWeb, __firefox__, __gCrWeb, chrome, opr, safari, samsungAr, ucweb, webkit, yandex.

How the technique works

For each name, in the fixed order above, WhiskerJS checks name in window and that the value is not null or undefined. A throwing lookup counts as absent. The found names are joined with commas; if none is found the value is none. Only presence is checked: the objects are not called or inspected.

Why it helps

The globals come from the browser build, not the device: chrome in Chromium browsers, opr in Opera, yandex in Yandex Browser, samsungAr in some Samsung Internet builds, safari in Safari, webkit in some WebKit-based in-app browser views, and __crWeb, __gCrWeb and __firefox__ injected by Chrome and Firefox on iOS. That separates browser apps that share an engine and would otherwise give very similar results.

Stability

Stable for a given browser build. It changes when a browser adds or removes one of these globals in an update. Pages that define a global with one of these names themselves (rare) would change it too.

Because the value lists names rather than reading the objects, a browser that changes what is inside window.chrome between versions does not change it; only a global appearing or disappearing does.

Browser support and what blocks it

Every browser can be checked; the value just differs. Desktop Chrome, Edge and Brave usually show chrome; Safari usually shows safari; Firefox usually shows none; iOS browsers can show their injected helpers. No browser class excludes it.

Privacy

The names describe the browser app, not the user. No global is read beyond checking that it exists.

How WhiskerJS handles noise and failures

Status ruleId When
ok a comma-separated list, or none
excluded caller_excluded you excluded it
timed_out timeout, aborted budget or abort

Errors during a lookup are caught per name. Never hashed in practice. The related headless_markers flag fires when the user agent is desktop Chrome but window.chrome is missing.

Example value

In the container test, headless Chromium and Firefox reported none and headless WebKit reported safari.

Questions and answers

Can vendor_flavors tell Chrome on iPhone from Safari?

Often yes. Chrome and Firefox on iOS inject their own globals (for example __gCrWeb or __firefox__) into pages, which Safari does not have, even though all of them run on WebKit.

What does none mean?

None of the ten globals exists. It is an ok value; headless Chromium without window.chrome reports it, for example.