# WhiskerJS > WhiskerJS is an open-source (Apache-2.0) browser library that reads device and browser signals in a web page and returns them as one plain, versioned JSON result: 46 components, a 128-bit visitorId, a group-by-group structuredId and a list of integrity flags. It is a collector, not a scoring engine: it never sends anything, never stores anything and never decides "human or bot". The site that uses it sends the result to its own server, which decides. Key facts (version 0.1.0, signalsVersion 5, idVersion 2): - Status: in development. Not yet published to npm or any registry; build it from source. The npm package is coming. - Licence: Apache License 2.0. Two small parts are adapted from MIT-licensed projects (Math operations from FingerprintJS 5.3.0, media MIME lists from fpscanner 1.0.8) with their notices kept. - 46 components; 37 stable ones form the visitorId, each in one of 7 groups (gpu, audio, fonts, device, browser, locale, prefs), the parts of the structuredId; 9 are reported but kept out of both ids. - 14 integrity flags (signs of automation or tampering). Flags are hints for the server, never a verdict. - Privacy: no network requests, no telemetry, no storage (no cookies, localStorage, sessionStorage or IndexedDB), no permission prompts, no console output. Large values leave the page only as the first 128 bits of SHA-256. - Optional anti-replay binding: the server's nonce and timestamp are echoed in the result with a digest over the whole result. It stops replay of an old result; it is not a signature. - Privacy browsers are not worked around: Brave farbling and Firefox resistFingerprinting (also Tor Browser) make WhiskerJS exclude the affected components. - No accuracy, stability or uniqueness figures are published yet: the head-to-head measurement against other libraries has not run. - Ids describe a browser setup, not a person, and are comparable only within the same signalsVersion and idVersion. ## Docs - [Overview](https://whiskerjs.com/docs.md): WhiskerJS documentation: what the library is, what it returns, and where to read more. - [Getting started](https://whiskerjs.com/docs/getting-started.md): Build WhiskerJS from source, add it to a page, collect once and read the result. - [How it works](https://whiskerjs.com/docs/how-it-works.md): The WhiskerJS collection pipeline: timeouts and budgets, statuses and reason codes, hashing, exclusions, noise handling and the clean iframe realm. - [Signals](https://whiskerjs.com/docs/signals.md): Every WhiskerJS component: what it reads, why it helps, typical values, its group and whether it is part of the visitorId. - [Identifiers](https://whiskerjs.com/docs/identifiers.md): visitorId and structuredId: how they are derived, how to compare two results for similarity, what changes an id and why versions bump. - [Integrity checks](https://whiskerjs.com/docs/integrity.md): Every WhiskerJS integrity flag: what fires it, what it means and its known false positives. - [Privacy](https://whiskerjs.com/docs/privacy.md): What WhiskerJS collects and never collects, how it minimises data, and the disclosure a site should give its users. - [Integration](https://whiskerjs.com/docs/integration.md): Sending WhiskerJS results to your own server, storing ids, the onResult hook, the anti-replay binding, recommended server checks and what never to trust from the client. - [FAQ](https://whiskerjs.com/docs/faq.md): Short answers about WhiskerJS: bots, people, npm, network, null ids, changing ids, private windows, noisy components, Safari, speed and faking. - [API reference](https://whiskerjs.com/docs/api.md): WhiskerJS API reference: load(), collect(), bindingInput(), every option, type, constant and default, for version 0.1.0 and signalsVersion 5. ## Facts - [WhiskerJS facts: licence, version, signals, privacy, status](https://whiskerjs.com/facts.md): Short, citable facts about WhiskerJS: licence, version, number of signals and checks, privacy stance, what it does not do, and its release status. ## Integration guides - [WhiskerJS integration guides: browser frameworks and server checks](https://whiskerjs.com/guides.md): Guides for adding WhiskerJS to plain JavaScript, React, Next.js, Vue, Svelte and Astro, and for verifying its anti-replay binding in Node, Go, PHP and Python. - [WhiskerJS with Astro: a client script in an Astro page](https://whiskerjs.com/guides/astro.md): Add WhiskerJS to an Astro page with a bundled client script that collects on form submit with a server nonce and posts the result. Tested with Astro 7. - [WhiskerJS with plain JavaScript: ES modules or a bundler](https://whiskerjs.com/guides/javascript.md): Add WhiskerJS to a plain HTML page with its ES module files or a bundler, collect on form submit with a server nonce, and send the result with your own request. - [WhiskerJS with Next.js: a client component and route handlers](https://whiskerjs.com/guides/nextjs.md): Use WhiskerJS in a Next.js App Router app: a 'use client' login form that collects on submit, and route handlers that issue the nonce and verify the binding. - [WhiskerJS with React: collect device signals on form submit](https://whiskerjs.com/guides/react.md): A React login form that loads WhiskerJS once, collects on submit with a nonce from your server and posts the result with the form. Tested with React 19. - [WhiskerJS with Svelte 5: collect device signals on submit](https://whiskerjs.com/guides/svelte.md): A Svelte 5 login component with runes that loads WhiskerJS on first use, collects on submit with a server nonce and posts the result. Tested with Vite. - [Verify the WhiskerJS anti-replay binding in Go](https://whiskerjs.com/guides/verify-go.md): Issue a single-use nonce and verify the WhiskerJS anti-replay binding in Go with the standard library, keeping JSON numbers exact. Tested against real results. - [Verify the WhiskerJS anti-replay binding in Node](https://whiskerjs.com/guides/verify-node.md): Issue a single-use nonce and verify the WhiskerJS anti-replay binding in Node with the library's own bindingInput and COMPONENT_NAMES. Tested on real results. - [Verify the WhiskerJS anti-replay binding in PHP](https://whiskerjs.com/guides/verify-php.md): Issue a single-use nonce in the PHP session and verify the WhiskerJS anti-replay binding with core PHP functions. Tested with PHP 8.3 against real results. - [Verify the WhiskerJS anti-replay binding in Python](https://whiskerjs.com/guides/verify-python.md): Issue a single-use nonce and verify the WhiskerJS anti-replay binding in Python with the standard library only. Tested against real results from three browsers. - [WhiskerJS with Vue: a login form with script setup](https://whiskerjs.com/guides/vue.md): A Vue 3 login component that loads WhiskerJS on first use, collects on submit with a server nonce and posts the result. Tested with Vue 3.5 and Vite. ## Signals (one page per component) - [Browser fingerprint signals in WhiskerJS: all 46 explained](https://whiskerjs.com/signals.md): Every signal WhiskerJS reads at signalsVersion 5: what it measures, which identifier group it joins, whether it is hashed, and one page per signal. ## Glossary - [Browser fingerprinting glossary: terms used by WhiskerJS](https://whiskerjs.com/glossary.md): Plain definitions of the terms the WhiskerJS docs use: visitor id, structured id, entropy, canvas noise, farbling, resistFingerprinting, Client Hints, GREASE. ## Browsers - [Browser support for WhiskerJS: what works where](https://whiskerjs.com/browsers.md): How WhiskerJS behaves in Chrome, Safari, every iOS browser, Firefox, Firefox resistFingerprinting, Tor Browser, Brave, Edge and Samsung Internet. ## Use cases - [Use cases: device signals for fraud and abuse checks](https://whiskerjs.com/use-cases.md): How WhiskerJS device signals, integrity flags, structuredId and anti-replay fit fraud, account takeover, multi-accounting, bonus abuse, bots and payments. - [Account takeover: spotting a new device at login](https://whiskerjs.com/use-cases/account-takeover.md): Use WhiskerJS at login to tell a known device from a new one, see which signal group changed, and stop replayed results with the anti-replay binding. - [Bonus and promotion abuse: repeat claims by device](https://whiskerjs.com/use-cases/bonus-abuse.md): Spot repeat claims of sign-up bonuses, trials, coupons and referral rewards with WhiskerJS device signals and structuredId similarity, decided on your server. - [Bot and headless browser detection with integrity flags](https://whiskerjs.com/use-cases/bot-detection.md): What WhiskerJS integrity flags say about automation and headless browsers, their documented false positives, and why a clean result proves nothing. - [Device signals for fraud prevention](https://whiskerjs.com/use-cases/fraud-prevention.md): Use WhiskerJS device signals, integrity flags, structuredId similarity and anti-replay as inputs to your own fraud rules, with the decision kept server-side. - [Multi-accounting: many accounts, one device](https://whiskerjs.com/use-cases/multi-accounting.md): Find accounts that share a browser setup with WhiskerJS visitorId and structuredId, weigh the integrity flags, and keep the decision on your server. - [Payment fraud: device context at checkout](https://whiskerjs.com/use-cases/payment-fraud.md): Add WhiskerJS device signals to checkout risk checks: known devices, structuredId similarity, integrity flags and anti-replay, beside your provider's checks. ## Privacy and compliance (informational, not legal advice) - [Privacy and compliance for device fingerprinting](https://whiskerjs.com/privacy.md): Informational guides to device fingerprinting under GDPR and ePrivacy, POPIA and CCPA/CPRA, cookieless setups and privacy notices. Not legal advice. - [Device fingerprinting under CCPA and CPRA (California)](https://whiskerjs.com/privacy/ccpa-cpra.md): Informational guide: device and probabilistic identifiers under the CCPA as amended by the CPRA, notice at collection, security and integrity, sale and sharing. - [Fingerprinting without cookies: what changes](https://whiskerjs.com/privacy/fingerprinting-without-cookies.md): A cookie stores an identifier; a fingerprint measures the device. Why no cookies does not mean no consent rules, and who stores what. - [Device fingerprinting under GDPR and ePrivacy](https://whiskerjs.com/privacy/gdpr-eprivacy.md): Informational guide: ePrivacy Article 5(3) and the GDPR applied to device fingerprinting for security and fraud prevention, consent and legitimate interests. - [Device fingerprinting under POPIA (South Africa)](https://whiskerjs.com/privacy/popia.md): Informational guide: South Africa's POPIA applied to device signals: personal information, the eight conditions, section 11 justification, notice, retention. - [Privacy notice text for device fingerprinting](https://whiskerjs.com/privacy/privacy-notice.md): Privacy notice text to adapt for sites using WhiskerJS for security, a checklist of what to fill in, and notes for the EU, UK, South Africa and California. ## Comparison - [Comparison: WhiskerJS and other open-source fingerprint libraries](https://whiskerjs.com/compare.md): The signals WhiskerJS and eleven open-source fingerprint libraries collect, their licences, their own stability claims and which send data home by default. - [WhiskerJS and BotD: bot detection compared](https://whiskerjs.com/compare/botd.md): WhiskerJS 0.1.0 integrity flags and the BotD 2.0.0 bot classifier compared: what each checks, verdict versus flags, network defaults and each project's own words. - [WhiskerJS and ClientJS: feature comparison](https://whiskerjs.com/compare/clientjs.md): WhiskerJS 0.1.0 and ClientJS 0.2.1 compared: two Apache-2.0 browser fingerprint libraries, their signals, hashes, maintenance and the effect of browser updates. - [WhiskerJS and FingerprintJS: feature comparison](https://whiskerjs.com/compare/fingerprintjs.md): WhiskerJS 0.1.0 and FingerprintJS 5.3.0 side by side: licence, signals, noise handling, identifiers, network defaults and each project's own claims. - [WhiskerJS and fpscanner: feature comparison](https://whiskerjs.com/compare/fpscanner.md): WhiskerJS 0.1.0 and fpscanner 1.0.8 compared: structured ids, anti-replay, automation checks, cross-checks, payload protection and network defaults. - [Open-source browser fingerprinting libraries compared](https://whiskerjs.com/compare/open-source-alternatives.md): Open-source browser fingerprint libraries read on 2026-10-24: licence, last release, what each collects, its own claims and its network defaults. - [WhiskerJS and ThumbmarkJS: feature comparison](https://whiskerjs.com/compare/thumbmarkjs.md): WhiskerJS 0.1.0 and ThumbmarkJS 1.12.0 compared: signals, canvas noise handling, stability options, identifiers, telemetry defaults and each project's own claims. ## Roadmap - [WhiskerJS roadmap: what comes next and what stays out](https://whiskerjs.com/roadmap.md): The WhiskerJS roadmap: what is planned for the next weeks and months, what comes later, what the library will not do, and the public sources behind each choice. ## Changelog - [What's new in WhiskerJS](https://whiskerjs.com/whats-new.md): What changed in WhiskerJS from signalsVersion 1 to 5 and idVersion 1 to 2. ## Other pages - [Live demo](https://whiskerjs.com/demo/): runs the real library in your browser and shows every component, both ids and the flags; nothing is sent. - [Sitemap](https://whiskerjs.com/sitemap.xml): every page with its last change date. ## Optional - [apple_pay: the Apple Pay availability signal](https://whiskerjs.com/signals/apple-pay.md): How WhiskerJS reads Apple Pay support without showing a payment sheet: ApplePaySession, the highest supported version and canMakePayments(). - [audio_latency: AudioContext base latency signal](https://whiskerjs.com/signals/audio-latency.md): How WhiskerJS reads AudioContext.baseLatency only in Safari and on Android, why other browsers are skipped, and why it stays out of the ids. - [audio: the offline audio fingerprint signal](https://whiskerjs.com/signals/audio.md): WhiskerJS renders a triangle wave through a compressor in an OfflineAudioContext and hashes the last 500 samples. Nothing is played. Support and stability. - [browser_class: how WhiskerJS classes the browser](https://whiskerjs.com/signals/browser-class.md): How WhiskerJS decides between brave, firefox_rfp, firefox, safari, chromium and other, why iOS browsers count as safari, and what the class controls. - [canvas_readback: canvas tamper probe signal](https://whiskerjs.com/signals/canvas-readback.md): How WhiskerJS paints two known colours into a 1x1 canvas and reads them back to see whether canvas reads are altered, and what exact and altered mean. - [canvas: the 2D canvas fingerprint signal](https://whiskerjs.com/signals/canvas.md): How WhiskerJS reads the canvas signal: a fixed 2D scene drawn twice, compared for noise, and reported only as a SHA-256 digest. Support, stability and privacy. - [color_depth: screen colour depth signal](https://whiskerjs.com/signals/color-depth.md): WhiskerJS reads screen.colorDepth, usually 24 or 30 bits. What it tells apart, why it is in the device group, how it fails and why it is low risk for privacy. - [color_gamut: the screen colour gamut signal](https://whiskerjs.com/signals/color-gamut.md): How WhiskerJS reads the color-gamut media query (rec2020, p3, srgb), what each value means about the display, and when it changes. - [content_blockers: ad and content blocker probe](https://whiskerjs.com/signals/content-blockers.md): How WhiskerJS detects cosmetic content blocking with eight off-screen bait elements, without any request, and why the result stays out of the ids. - [cpu_architecture: x86 or ARM from a NaN bit](https://whiskerjs.com/signals/cpu-architecture.md): WhiskerJS computes Infinity minus Infinity in a Float32Array and reads the NaN's high byte: 255 on x86, 127 on ARM, even when the user agent hides it. - [device_memory: approximate device memory signal](https://whiskerjs.com/signals/device-memory.md): WhiskerJS reads navigator.deviceMemory, a coarse memory bucket in GB. Chromium only by design: why Safari, iOS and Firefox report unavailable. - [dynamic_range: the HDR display signal](https://whiskerjs.com/signals/dynamic-range.md): How WhiskerJS reads the dynamic-range media query (high or standard), what HDR support means for the value, and why it can change with the monitor. - [font_preferences: default font settings signal](https://whiskerjs.com/signals/font-preferences.md): WhiskerJS measures one text in the browser default, serif, sans-serif, monospace and system fonts and at 1 px, revealing font settings. Digest only, no prompt. - [fonts_canvas: font detection with canvas measureText](https://whiskerjs.com/signals/fonts-canvas.md): WhiskerJS detects 54 font families a second way, with canvas measureText at 72 px, so page CSS cannot disturb it. Reported as a digest, excluded in Brave. - [fonts: installed font detection by span width](https://whiskerjs.com/signals/fonts.md): WhiskerJS checks 54 font families by measuring hidden text spans against generic fallbacks and reports a digest of the found list. How it works, Brave, privacy. - [forced_colors: the forced colours accessibility signal](https://whiskerjs.com/signals/forced-colors.md): How WhiskerJS reads the forced-colors media query (active or none), what forced colour modes such as Windows contrast themes mean, and the privacy angle. - [hardware_concurrency: logical CPU threads signal](https://whiskerjs.com/signals/hardware-concurrency.md): WhiskerJS reads navigator.hardwareConcurrency, the logical CPU thread count. Why it helps, why Brave and Firefox RFP are excluded, the impossible_hardware flag. - [heap_limit: JavaScript heap size limit signal](https://whiskerjs.com/signals/heap-limit.md): WhiskerJS reads performance.memory.jsHeapSizeLimit, the JavaScript heap limit Chromium sets for the page. Chromium only. What it shows and when it changes. - [intl_locale: Intl locale, calendar and hour cycle signal](https://whiskerjs.com/signals/intl-locale.md): WhiskerJS reads the resolved Intl locale, calendar, numbering system, hour cycle and number locale. How these follow regional settings and when they change. - [keyboard_layout: the active keyboard layout signal](https://whiskerjs.com/signals/keyboard-layout.md): How WhiskerJS reads the character 19 physical keys produce from navigator.keyboard.getLayoutMap(), without a prompt, and why it stays out of the ids. - [languages: the browser language list signal](https://whiskerjs.com/signals/languages.md): WhiskerJS reads navigator.languages joined with commas, or navigator.language. Why the list helps, what changes it, and how to compare it with Accept-Language. - [math: the JavaScript Math precision signal](https://whiskerjs.com/signals/math.md): How WhiskerJS hashes the last digits of 24 Math results on fixed inputs, why they differ between JavaScript engines, and when they change. - [media_codecs: audio and video codec support signal](https://whiskerjs.com/signals/media-codecs.md): How WhiskerJS probes 20 audio and video MIME types with canPlayType and MediaSource.isTypeSupported, without loading media, and hashes the answers. - [pdf_viewer: the built-in PDF viewer signal](https://whiskerjs.com/signals/pdf-viewer.md): What navigator.pdfViewerEnabled says, why it is true or false in different browsers, how WhiskerJS reports it and when it is unavailable. - [permissions: permission states without prompts](https://whiskerjs.com/signals/permissions.md): How WhiskerJS reads the state of 24 permissions with navigator.permissions.query, which never prompts, and why the digest is kept out of the ids. - [pixel_ratio: devicePixelRatio and page zoom signal](https://whiskerjs.com/signals/pixel-ratio.md): Why WhiskerJS reports devicePixelRatio but keeps it out of the visitorId: it changes with page zoom. Rounding, exclusions and example values. - [platform: the navigator.platform signal](https://whiskerjs.com/signals/platform.md): What navigator.platform reports (MacIntel, Win32, Linux x86_64, iPhone), why it is in the WhiskerJS id, and how it is cross-checked for spoofing. - [plugins: the navigator.plugins signal](https://whiskerjs.com/signals/plugins.md): How WhiskerJS hashes navigator.plugins (names, file names, MIME types), why it is excluded under Brave, and how plugin lists are checked for fakes. - [prefers_contrast: the contrast preference signal](https://whiskerjs.com/signals/prefers-contrast.md): How WhiskerJS reads the prefers-contrast media query (more, less, custom, none), what each value means and why it is an accessibility setting. - [private_click: Safari Private Click Measurement signal](https://whiskerjs.com/signals/private-click.md): How WhiskerJS detects WebKit's Private Click Measurement through attributionSourceId on an unattached link, and what the value means. - [reduced_motion: the reduced motion preference signal](https://whiskerjs.com/signals/reduced-motion.md): How WhiskerJS reads the prefers-reduced-motion media query (reduce or none), what the setting means for users, and why it is in the prefs group. - [screen_frame: taskbar and dock space signal](https://whiskerjs.com/signals/screen-frame.md): How WhiskerJS computes the screen area kept by the taskbar, dock or menu bar from screen and avail values, and why it is kept out of the ids. - [screen_resolution: screen size signal, rotation-proof](https://whiskerjs.com/signals/screen-resolution.md): WhiskerJS reads screen.width and screen.height and reports them larger side first, so rotating a phone does not change the value. Support, Firefox RFP, privacy. - [speech_voices: installed text-to-speech voices signal](https://whiskerjs.com/signals/speech-voices.md): How WhiskerJS hashes the list of speech synthesis voices without speaking, why it waits up to 600 ms for voiceschanged, and why it is outside the ids. - [storage: storage and cookie availability signal](https://whiskerjs.com/signals/storage.md): How WhiskerJS checks whether localStorage, sessionStorage, IndexedDB and cookies are available without reading or writing any of them. - [time_zone: IANA time zone signal](https://whiskerjs.com/signals/time-zone.md): WhiskerJS reads the IANA time zone from Intl, with a UTC offset fallback. What changes it, why Firefox resistFingerprinting is excluded, server checks. - [touch_support: touch points and touch events signal](https://whiskerjs.com/signals/touch-support.md): WhiskerJS reads navigator.maxTouchPoints, whether a TouchEvent can be created and whether ontouchstart exists. How phones, laptops and desktops differ. - [ua_client_hints: User-Agent Client Hints signal](https://whiskerjs.com/signals/ua-client-hints.md): How WhiskerJS reads User-Agent Client Hints: brands without versions and GREASE, mobile, platform, architecture, bitness, model and form factors. - [ua_versions: full browser and OS versions signal](https://whiskerjs.com/signals/ua-versions.md): How WhiskerJS reports full brand versions and the platform version from Client Hints, why they stay out of the ids, and the he=blocked marker. - [vendor_flavors: browser-specific globals signal](https://whiskerjs.com/signals/vendor-flavors.md): Which of ten browser-specific globals such as chrome, safari, opr, __gCrWeb or __firefox__ exist on the page, and why that tells browser builds apart. - [vendor: the navigator.vendor signal](https://whiskerjs.com/signals/vendor.md): What navigator.vendor reports in Chromium, Safari and Firefox, why WhiskerJS writes an empty value as empty, and how it feeds the browser class. - [webgl_image: the WebGL rendered image signal](https://whiskerjs.com/signals/webgl-image.md): How WhiskerJS draws a small shaded WebGL triangle twice, compares the pixels for noise and reports a digest. Support, exclusions, stability and privacy. - [webgl_params: WebGL limits and extensions signal](https://whiskerjs.com/signals/webgl-params.md): WhiskerJS reads 21 WebGL parameters, shader precisions and the sorted extension list, and reports them as one digest. What it shows and how stable it is. - [webgl_renderer: the WebGL GPU renderer string](https://whiskerjs.com/signals/webgl-renderer.md): WhiskerJS reads the unmasked WebGL renderer string naming the GPU and graphics back end. How it is read, why Firefox differs, the software_renderer flag. - [webgl_vendor: the WebGL GPU vendor string](https://whiskerjs.com/signals/webgl-vendor.md): WhiskerJS reads the unmasked WebGL vendor string, such as Google Inc. (Apple) or Apple Inc. How it is read, where it is excluded and what it tells your server. - [webgpu: WebGPU adapter info and limits signal](https://whiskerjs.com/signals/webgpu.md): WhiskerJS asks WebGPU for an adapter and reads its info, features and seven limits, without requesting a device. Support, failures and privacy, from the code. - [WhiskerJS in Brave: farbling and the seven excluded signals](https://whiskerjs.com/browsers/brave.md): How WhiskerJS detects Brave, why it leaves out seven farbled components (audio, canvas, fonts, plugins, CPU threads, WebGL image), and what it still reads. - [WhiskerJS in Chrome on Android: what it reads on phones](https://whiskerjs.com/browsers/chrome-android.md): What WhiskerJS reads in Chrome on Android: Client Hints with the device model, audio latency, touch support, what varies on phones and why nothing is excluded. - [WhiskerJS in Chrome on desktop: signals, flags and limits](https://whiskerjs.com/browsers/chrome-desktop.md): What WhiskerJS reads in desktop Chrome: every Chromium-only API, nothing excluded, the flags automation and headless Chrome raise, and the lab sample. - [WhiskerJS in Microsoft Edge: a Chromium browser](https://whiskerjs.com/browsers/edge.md): What WhiskerJS reads in Microsoft Edge: it is classed chromium like Chrome, with every Chromium API, nothing excluded, and Client Hints brands from Edge itself. - [WhiskerJS with Firefox resistFingerprinting and Tor Browser](https://whiskerjs.com/browsers/firefox-rfp-and-tor.md): How WhiskerJS detects Firefox resistFingerprinting and Tor Browser, the exact trait test, the nine excluded components and why it errs towards stock Firefox. - [WhiskerJS in Firefox: signals, WebGL strings and limits](https://whiskerjs.com/browsers/firefox.md): What WhiskerJS reads in stock Firefox: WebGL strings without the deprecated debug extension, no Chromium-only APIs, and how it is told apart from RFP. - [WhiskerJS on iPhone and iPad: Safari, Chrome, Firefox, Edge](https://whiskerjs.com/browsers/safari-ios.md): Why WhiskerJS classes Chrome, Firefox and Edge on iOS as Safari, what WebKit offers and lacks, how iOS browsers differ, and the iPhone lab sample. - [WhiskerJS in Safari on macOS: signals, limits and lab sample](https://whiskerjs.com/browsers/safari-macos.md): What WhiskerJS reads in Safari on the Mac: Apple Pay and Private Click Measurement, no Chromium-only APIs, canvas noise handling and the lab sample. - [WhiskerJS in Samsung Internet: Chromium on Android](https://whiskerjs.com/browsers/samsung-internet.md): What WhiskerJS reads in Samsung Internet: classed chromium, Chromium APIs, audio latency on Android, the samsungAr global in vendor_flavors, and no exclusions. - [WhiskerJS browser support matrix: 46 signals in 9 browsers](https://whiskerjs.com/browsers/support-matrix.md): Which of the 46 WhiskerJS signals are read, unavailable, excluded or variable in Chrome, Safari, iOS browsers, Firefox, Tor Browser, Brave, Edge and Samsung Internet.