Chrome on Android runs the same engine as desktop Chrome, so WhiskerJS reads almost the same set of signals, including the Chromium-only ones such as the device memory and Client Hints. On a phone, Client Hints usually say more about the device (it is mobile, and often which model). WhiskerJS also reads the audio output latency here, which it skips on desktop Chrome. Nothing is excluded on purpose.
At a glance
- Browser class:
chromium(the user agent has aChrome/<number>token);chromium_webviewfor Android WebView (in-app browsers). - Excluded components: none.
- Read here but skipped on desktop Chrome:
audio_latency(the user agent says Android). - Likely different from desktop:
touch_support,ua_client_hints(mobile, model, form factors),plugins,keyboard_layout. - Lab sample: none for Android yet.
What works
- Chromium-only components:
device_memory(from Chromium 146 with the tag;c146, buckets 2, 4 or 8 on Android),heap_limit,ua_client_hintsandua_versionsread the same APIs as on desktop. Inua_client_hints,mobile=1, themodeland theformfactors come from the browser’s own answer togetHighEntropyValues(), so they often tell phone models apart better than the user agent string. audio_latency: WhiskerJS creates anAudioContext, readsbaseLatency, and closes the context at once. Nothing is played. It is outside both ids because it follows the audio output device (headphones, speaker, Bluetooth).touch_support:navigator.maxTouchPoints, whether aTouchEventcan be created, and whetherontouchstartexists; a phone typically gives something likepoints=5,event=1,start=1.screen_resolution: the larger side first, so rotating the phone does not change it.- Graphics, audio rendering, fonts, font preferences, Math, codecs, locale and the display preference queries are read as on any current browser.
What is unavailable or blocked
keyboard_layoutusesnavigator.keyboard.getLayoutMap(), an API meant for physical keyboards; expect it to beunavailableon Android. It is outside the ids either way.plugins: mobile builds often list no plugins, and then the component reports the plain valuenone.apple_payandprivate_clickreport the plain valuenone.webgpu: availability depends on the Chrome version, the Android version and the GPU; it isunavailable(no_apiorno_context) where there is no adapter.ua_client_hintsandua_versionsreporthe=blockedwhen a Permissions Policy refuses the detailed hints.
What WhiskerJS excludes and why
Nothing. The chromium row of the exclusion table is empty. If the browser or an extension adds noise to canvas or WebGL readback, the double render turns canvas or webgl_image into noisy (render_mismatch), and the known-answer probes catch noise that is the same on both reads (seeded_noise, also for audio), instead of letting the noise change the id on every run.
Android WebView
Pages shown inside Android apps run in Android WebView, which is Chromium too. WhiskerJS classes it chromium_webview (since signalsVersion 6) when the user agent’s platform part carries the wv token (kept by the reduced WebView user agent) or navigator.userAgentData has the brand Android WebView. Chrome for Android has neither and stays chromium. The chromium_webview row is empty: WebView randomises nothing, and the class itself tells your server that the visit comes from an in-app browser.
Integrity flags to expect
headless_markerschecks for a missingwindow.chromeonly when the user agent is desktop Chrome: user agents withMobileorAndroidare skipped by that part of the check, so normal Android Chrome does not raise it that way. A 0x0 outer window still raises it.automation_webdriverwhen the browser is controlled through WebDriver or a similar protocol, for example in device test farms.software_rendererin emulators that render WebGL in software, andvm_rendererin the Android emulator (Android Emulator,OpenGL ES Translator).ua_ch_mismatchwhen the user agent disagrees with Client Hints. “Request desktop site” (a Linux user agent with the platformAndroid) is accepted, and the check does not run on Android WebView, where apps set their own user agent.media_query_mismatchwhen a coarse pointer is reported with no touch points, or the CSS device size disagrees withscreen, as bad mobile emulation does.native_tamperingand related lie checks if something overrides browser functions.
None of them is a verdict; see Integrity checks.
Early lab observations
There is no lab data for Chrome on Android yet. The early, small sample at signalsVersion 1 covered four pairs only: Mac Chrome, Mac Safari, iPhone Chrome and iPhone Safari. The table below is filled from the code, not from measurements on Android.
Testing it yourself
Open the live demo on the phone, run it a few times, rotate the phone, switch between headphones and the speaker, and watch which components move: screen_resolution should stay the same and audio_latency may change, which is why it is outside the ids. The lab mode copies one line per run for your own records. Nothing is sent anywhere.
Support table for Chrome on Android
Expected status of every component in this browser at signalsVersion 9, from the support matrix (updated 2026-10-26). Basis "code" means expected from the library code and documentation, not yet measured; "lab" means seen in the early lab sample.
| Component | Status | Basis | Note |
|---|---|---|---|
apple_pay | none | code | No ApplePaySession: reports the plain value none. |
audio | ok | code | noisy / seeded_noise if the audio known-answer probe sees noise. |
audio_latency | ok | code | Read when the user agent says Android. |
browser_class | ok | code | Class chromium; chromium_webview in Android WebView (in-app browsers). |
canvas | ok | code | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
canvas_readback | ok | code | |
color_depth | ok | code | |
color_gamut | ok | code | |
content_blockers | ok | code | none, or the bait names a content blocker hid. |
cpu_architecture | ok | code | |
device_memory | ok | code | From Chromium 146 the value carries the tag ;c146 (new buckets). |
dynamic_range | ok | code | |
font_preferences | ok | code | |
fonts | ok | code | |
fonts_canvas | ok | code | |
forced_colors | ok | code | |
hardware_concurrency | ok | code | Read 16 times; noisy / read_varies if the reads disagree. Some browsers cap or round the value. |
heap_limit | ok | code | |
intl_locale | ok | code | |
keyboard_layout | varies | code | Chromium API meant for physical keyboards; on Android expect unavailable. |
languages | ok | code | |
math | ok | code | |
media_codecs | ok | code | |
noise_profile | ok | code | canvas=exact,webgl=exact,audio=exact on a stock browser; webgl=na without WebGL. |
pdf_viewer | ok | code | |
permissions | ok | code | |
pixel_ratio | ok | code | |
platform | ok | code | |
plugins | varies | code | Mobile builds often list no plugins and then report the plain value none. |
prefers_contrast | ok | code | |
private_click | none | code | No attributionSourceId on anchors: reports the plain value none. |
reduced_motion | ok | code | |
screen_frame | ok | code | |
screen_resolution | ok | code | |
speech_voices | ok | code | Digest of the voice list, or none; some browsers fill the list late. |
storage | ok | code | |
time_zone | ok | code | |
touch_support | ok | code | |
ua_client_hints | ok | code | he=blocked when a Permissions Policy refuses the detailed hints. |
ua_versions | ok | code | |
vendor | ok | code | |
vendor_flavors | ok | code | |
webgl_image | ok | code | noisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback. |
webgl_params | ok | code | Where WebGL 1 is available; unavailable / no_context without it. |
webgl_renderer | ok | code | |
webgl_vendor | ok | code | |
webgpu | varies | code | Depends on browser version, operating system and GPU; needs a secure context. unavailable / no_api without navigator.gpu, no_context without an adapter. |
Questions and answers
Does rotating the phone change the id?
No. screen_resolution reports the larger side first, so portrait and landscape give the same value. pixel_ratio and screen_frame are outside the ids anyway.
Why is audio_latency read on Android but not on desktop Chrome?
Desktop Chrome prints a console warning when a page creates an AudioContext without a user gesture, and WhiskerJS writes nothing to the console. The library reads the latency only for Safari and for user agents that say Android.
What about in-app browsers on Android?
Pages inside Android apps run in Android WebView. WhiskerJS recognises it by the wv token in the user agent or the Android WebView brand in userAgentData and reports the class chromium_webview (since signalsVersion 6). Nothing is excluded: WebView randomises nothing, and the class itself tells your server it is an in-app browser.
Why does device_memory end in ;c146?
Chromium 146 changed the memory buckets; on Android they are 2, 4 or 8 GB. From that version WhiskerJS tags the value, for example 8;c146, so a server can tell which scheme it comes from. Expect one id change per user at the update to 146.
Is there lab data for Android?
Not yet. The early lab sample covered Mac Chrome, Mac Safari, iPhone Chrome and iPhone Safari only.