Browsers · WhiskerJS 0.1.0

Chrome on Android

Chrome on Android offers the Chromium APIs WhiskerJS reads, plus the audio output latency, which the library reads only on Android and Safari.

In plain words

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 a Chrome/<number> token); chromium_webview for 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_hints and ua_versions read the same APIs as on desktop. In ua_client_hints, mobile=1, the model and the form factors come from the browser’s own answer to getHighEntropyValues(), so they often tell phone models apart better than the user agent string.
  • audio_latency: WhiskerJS creates an AudioContext, reads baseLatency, 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 a TouchEvent can be created, and whether ontouchstart exists; a phone typically gives something like points=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_layout uses navigator.keyboard.getLayoutMap(), an API meant for physical keyboards; expect it to be unavailable on Android. It is outside the ids either way.
  • plugins: mobile builds often list no plugins, and then the component reports the plain value none.
  • apple_pay and private_click report the plain value none.
  • webgpu: availability depends on the Chrome version, the Android version and the GPU; it is unavailable (no_api or no_context) where there is no adapter.
  • ua_client_hints and ua_versions report he=blocked when 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_markers checks for a missing window.chrome only when the user agent is desktop Chrome: user agents with Mobile or Android are 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_webdriver when the browser is controlled through WebDriver or a similar protocol, for example in device test farms.
  • software_renderer in emulators that render WebGL in software, and vm_renderer in the Android emulator (Android Emulator, OpenGL ES Translator).
  • ua_ch_mismatch when the user agent disagrees with Client Hints. “Request desktop site” (a Linux user agent with the platform Android) is accepted, and the check does not run on Android WebView, where apps set their own user agent.
  • media_query_mismatch when a coarse pointer is reported with no touch points, or the CSS device size disagrees with screen, as bad mobile emulation does.
  • native_tampering and 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.

ComponentStatusBasisNote
apple_paynonecodeNo ApplePaySession: reports the plain value none.
audiookcodenoisy / seeded_noise if the audio known-answer probe sees noise.
audio_latencyokcodeRead when the user agent says Android.
browser_classokcodeClass chromium; chromium_webview in Android WebView (in-app browsers).
canvasokcodenoisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback.
canvas_readbackokcode
color_depthokcode
color_gamutokcode
content_blockersokcodenone, or the bait names a content blocker hid.
cpu_architectureokcode
device_memoryokcodeFrom Chromium 146 the value carries the tag ;c146 (new buckets).
dynamic_rangeokcode
font_preferencesokcode
fontsokcode
fonts_canvasokcode
forced_colorsokcode
hardware_concurrencyokcodeRead 16 times; noisy / read_varies if the reads disagree. Some browsers cap or round the value.
heap_limitokcode
intl_localeokcode
keyboard_layoutvariescodeChromium API meant for physical keyboards; on Android expect unavailable.
languagesokcode
mathokcode
media_codecsokcode
noise_profileokcodecanvas=exact,webgl=exact,audio=exact on a stock browser; webgl=na without WebGL.
pdf_viewerokcode
permissionsokcode
pixel_ratiookcode
platformokcode
pluginsvariescodeMobile builds often list no plugins and then report the plain value none.
prefers_contrastokcode
private_clicknonecodeNo attributionSourceId on anchors: reports the plain value none.
reduced_motionokcode
screen_frameokcode
screen_resolutionokcode
speech_voicesokcodeDigest of the voice list, or none; some browsers fill the list late.
storageokcode
time_zoneokcode
touch_supportokcode
ua_client_hintsokcodehe=blocked when a Permissions Policy refuses the detailed hints.
ua_versionsokcode
vendorokcode
vendor_flavorsokcode
webgl_imageokcodenoisy / render_mismatch or seeded_noise if an extension or setting adds noise to readback.
webgl_paramsokcodeWhere WebGL 1 is available; unavailable / no_context without it.
webgl_rendererokcode
webgl_vendorokcode
webgpuvariescodeDepends 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.