Arkose FP fingerprint documentation

Research notes on Arkose Labs' FunCaptcha fingerprinting. Entries below describe each signal; live JSON reflects this browser session.

Page last updated [loading…]

How to read this page

  • Open DevTools (Ctrl+Shift+I) for logs and related source detail.
  • Use the sidebar (tools block and filter) to jump between signals and other pages.

api_type

Static value "js".

f

MurmurHash3-128 hex digest of the raw fe values, joined with ;. Arrays use normal JavaScript string coercion, so [1, false, false] becomes "1,false,false".

n timestamp

Base64 encoded UNIX timestamp in seconds.

wh Window Hash

Window hash:

  1. Own property names of window, excluding any key matching ^(f_|arkoseLabsClientApi|webpack).* (Arkose globals and webpack chunk stuff).
  2. Sort that list lexicographically, join with |, MurmurHash3-128 with seed 420.
  3. Separately, walk the prototype chain from window: for each prototype, append Object.getOwnPropertyNames(proto) in engine order (not globally sorted). Join those names with | and MurmurHash3-128 again with seed 420.
  4. Concatenate the two digests with |.

enhanced_fp

enhanced_fp.webgl_extensions

Collects supported operations by your GPU via the WebGL API (webgl_extensions, webgl_renderer, webgl_hash_webgl, and related keys). This could, in theory, be used to correlate your CFP (canvas fingerprint) as described in this paper by Google.

webgl_extensions: semicolon-separated list from getSupportedExtensions(). Other WebGL keys from the same collector are under each heading below.

enhanced_fp.webgl_extensions_hash

128-bit MurmurHash3 digest of the semicolon-separated extension string in webgl_extensions.

enhanced_fp.webgl_renderer

From getParameter(RENDERER). Often a masked or generic string; see also: webgl_unmasked_renderer when WEBGL_debug_renderer_info is available.

enhanced_fp.webgl_vendor

From getParameter(VENDOR). Paired with unmasked vendor when the debug extension exists ( webgl_unmasked_vendor).

enhanced_fp.webgl_version

From getParameter(VERSION). WebGL and underlying GL version string the implementation reports.

enhanced_fp.webgl_shading_language_version

From getParameter(SHADING_LANGUAGE_VERSION). GLSL dialect string for this context.

enhanced_fp.webgl_aliased_line_width_range

getParameter(ALIASED_LINE_WIDTH_RANGE) after a small clear and depth setup, stored as [min, max].

enhanced_fp.webgl_aliased_point_size_range

Same formatting as line width range, but for getParameter(ALIASED_POINT_SIZE_RANGE).

enhanced_fp.webgl_antialiasing

getContextAttributes().antialias mapped to yes or no.

enhanced_fp.webgl_bits

Comma-separated ALPHA_BITS, BLUE_BITS, DEPTH_BITS, GREEN_BITS, RED_BITS, STENCIL_BITS.

enhanced_fp.webgl_max_params

Comma-separated limits: max anisotropy (from EXT_texture_filter_anisotropic if present, else null in that slot), then combined texture units, max cubemap size, fragment uniform vectors, renderbuffer size, texture image units, max texture size, varyings, vertex attribs, vertex texture units, and vertex uniform vectors.

enhanced_fp.webgl_max_viewport_dims

getParameter(MAX_VIEWPORT_DIMS) as [width, height].

enhanced_fp.webgl_unmasked_vendor

UNMASKED_VENDOR_WEBGL via WEBGL_debug_renderer_info. The live box stays null when that extension is missing or throws.

enhanced_fp.webgl_unmasked_renderer

UNMASKED_RENDERER_WEBGL from the same extension: the GPU string Chromium usually exposes for fingerprinting.

enhanced_fp.webgl_vsf_params

Vertex shader, float precisions: comma-separated precision, rangeMin, rangeMax triplets for HIGH_FLOAT, MEDIUM_FLOAT, LOW_FLOAT from getShaderPrecisionFormat. Stays null if that API is missing.

enhanced_fp.webgl_vsi_params

Vertex shader int precisions: same layout as webgl_vsf_params but for HIGH_INT, MEDIUM_INT, LOW_INT.

enhanced_fp.webgl_fsf_params

Fragment shader float precisions (same triplet pattern as vertex floats).

enhanced_fp.webgl_fsi_params

Fragment shader int precisions (mirrors webgl_vsi_params for the fragment stage).

enhanced_fp.webgl_hash_webgl

MurmurHash3 x64 over Object.entries(webglBlob).join(",") right before this key is assigned, so the digest does not include itself.

enhanced_fp.user_agent_data_brands

Checks the brands property of navigator.userAgentData.

enhanced_fp.user_agent_data_mobile

Checks the mobile property of navigator.userAgentData.

From navigator.connection.downlink (Mbps, NetworkInformation).

From navigator.connection.downlinkMax. See the collector for null vs -1 when the value is missing or not finite.

enhanced_fp.network_info_rtt

navigator.connection.rtt (round-trip ms). Separate from network_info_rtt_type.

enhanced_fp.network_info_save_data

navigator.connection.saveData when exposed.

enhanced_fp.network_info_rtt_type

This value has been repurposed for use inside the virtual machine. It takes the first 3 characters of webgl_extensions_hash and webgl_hash_webgl then concatenates them.

enhanced_fp.screen_pixel_depth

screen.pixelDepth. This value has been repurposed for use inside the virtual machine. It takes the pixel depth and multiplies by 3.

enhanced_fp.navigator_device_memory

navigator.deviceMemory when it's a number.

enhanced_fp.navigator_languages

navigator.languages.join(",") when available.

enhanced_fp.window_inner_width

window.innerWidth is the layout viewport width in pixels.

enhanced_fp.window_inner_height

window.innerHeight is the layout viewport height in pixels.

enhanced_fp.window_outer_width

window.outerWidth is the outer browser window width in pixels (includes browser UI).

enhanced_fp.window_outer_height

window.outerHeight is the outer browser window height in pixels (includes browser UI).

enhanced_fp.browser_detection_firefox

Detects Firefox by checking the User-Agent for "Firefox".

enhanced_fp.browser_detection_brave

Detects Brave Browser via the brave window object.

enhanced_fp.9f41a2c

Detects Perplexity's Comet Browser by checking the document's theme. This is similar to an old approach demonstrated by Castle's Research Team.

enhanced_fp.5c273b3

Detects Genspark AI Browser via the navigator.genspark property.

enhanced_fp.ce4046e

Detects Sigma Browser via the window.__SIGMA__ object.

enhanced_fp.f58835f

Notice "f58835f" is now MD5 hashed as of 2.16.0.

A hash of supported browser APIs. Collects the availability of various features, each checked with !!window.FeatureName or presence on navigator. Includes:

Results are concatenated into strings like "permission_status: true", serialized to JSON, then MD5 hashed.

enhanced_fp.browser_object_checks

  • Checks for global objects belonging to different browsers.
  • Sorts them.
  • Joins them with ",".
  • MD5 hashes them.

See the console for more details.

enhanced_fp.29s83ih9

Checks for different sandbox environments such as JSDom.

enhanced_fp.audio_codecs

Notice "audio_codecs_extended" is no longer included in the payload to reduce payload size.

Creates an <audio> element and checks with canPlayType for a short list including: ogg, mp3, wav, m4a, and aac.

enhanced_fp.audio_codecs_extended_hash

Hash of the extended audio probe. The full JSON used to exist as audio_codecs_extended, but only the MD5 is sent now.

The extended probe walks a much longer internal MIME list. For each MIME string it stores both <audio>.canPlayType and MediaSource.isTypeSupported. Then the JSON is hashed using MD5.

enhanced_fp.video_codecs

Notice "video_codecs_extended" is no longer included in the payload to reduce payload size.

Small video codec probe. Creates a <video> element and checks with canPlayType for common formats including: ogg, h264, webm, mpeg4v, mpeg4a, and theora.

enhanced_fp.video_codecs_extended_hash

Hash of the extended video probe.

The source still builds the full snapshot from a longer video MIME list. Each entry records <video>.canPlayType plus MediaSource.isTypeSupported, then hashes the JSON.

enhanced_fp.media_query_dark_mode

Queries for dark mode using:

matchMedia("(prefers-color-scheme: dark)").matches;

enhanced_fp.f9bf2db

Checks various CSS media queries shown below:

  • pc = prefers-contrast
  • ah = any-hover
  • ap = any-pointer
  • p = pointer
  • h = hover
  • u = update
  • ic = inverted-colors
  • prm = prefers-reduced-motion
  • prt = prefers-reduced-transparency
  • s = scripting
  • fc = forced-colors

JSON object of the short keys above mapped to the first matching media value; the payload stores the stringified object as enhanced_fp.f9bf2db.

enhanced_fp.headless_browser_phantom

True when any of callPhantom, _phantom, _phantomas, calledPhantom is present on window (Phantom-style stacks).

enhanced_fp.headless_browser_selenium

Selenium / WebDriver heuristics on window and document (named globals, document hooks, attribute markers, navigator.webdriver). Differs from the packed bitmask in enhanced_fp.862f2c1.

enhanced_fp.headless_browser_nightmare_js

Checks if window.__nightmare is present.

enhanced_fp.862f2c1

Checks the various objects on the document and window related to browser automation frameworks. Including:

  • Selenium / ChromeDriver: $cdc_* on document, cdc_* property names on window, __$webdriverAsyncExecutor, and __webdriver* hooks.
  • Watir (Ruby): __lastWatirAlert, __lastWatirConfirm, __lastWatirPrompt.
  • WatiN (.NET): watinExpressionError, watinExpressionResult.
  • Geb (Groovy / JVM): geb, fmget_targets.
  • Spynner: spynner_additional_js_loaded.
  • Awesomium (embedded Chromium): awesomium on window.
  • Chrome internals tied to automation: $chrome_asyncScriptInfo on document.
  • Blender: blender on window.
  • Unknown: window.OSMJIF and document.hidden.

Same function also ORs bits for domAutomation / domAutomationController (Chrome-ish automation), window.external mentioning Sequentum, and Electron-style process / window.close signatures.

enhanced_fp.1l2l5234ar2

Checks if you have DevTools open or are using Puppeteer.

enhanced_fp.document__referrer

document.referrer with the query string removed.

enhanced_fp.window__ancestor_origins

Copy of location.ancestorOrigins when the API exists; otherwise null. This signal isn't accurate this environment.

enhanced_fp.window__tree_index

Intended to detect phishing pages that have embedded the CAPTCHA. This signal isn't accurate this environment.

enhanced_fp.window__tree_structure

Recursive walk from top over child frames; result is JSON.stringify of nested arrays (empty string if access throws). Pairs with window__tree_index, which stores each frame's index in its parent's frames list up to top.

enhanced_fp.window__location_href

Current frame location.href: strip query, then strip fragment. Differs from the host value in client_config__sitedata_location_href when the challenge runs in an iframe.

enhanced_fp.client_config__sitedata_location_href

Host location.href at embed time, query stripped only (See: window__location_href for fragment handling).

enhanced_fp.client_config__language

config.language from setConfig (or null).

enhanced_fp.client_config__surl

Optional surl from config, query stripped. Pairs with enhanced_fp.c8480e29a.

enhanced_fp.c8480e29a

MD5 hashed surl.

md5(surl) + (surl ? "\u2062" : "\u2063");

enhanced_fp.client_config__triggered_inline

!!config.inlineRunOnTrigger

enhanced_fp.mobile_sdk__is_sdk

Boolean isSDK from config when it is actually a boolean; otherwise false. You can find more details in the Arkose Mobile SDK (Android) FP docs

enhanced_fp.audio_fingerprint

Checks the audio fingerprint using the Web Audio API.

More details about audio fingerprinting can be found in the following articles:

  1. How the Web Audio API is used for audio fingerprinting
  2. How We Bypassed Safari 17's Advanced Audio Fingerprinting Protection

enhanced_fp.navigator_battery_charging

Checks the charging status of the device's battery.

(await navigator.getBattery()).charging;

enhanced_fp.7541c2s

Notice "media_device_kinds" is no longer included in the payload.

Checks which media devices are available.

enhanced_fp.1f220c9

Notice Not currently part of 4.x.x

  • Checks which permissions the current page has (including accelerometer, gamepad, nfc, etc).
  • JSON stringifies them.
  • MD5 hashes them.

This hasn't been "reverted" in 4.x.x, as some have claimed. ArkoseLabs maintains multiple branches and active deployments. The 4.x.x branch was created from an older revision that predates the 3.5.0 release. Both versions are being developed in parallel and will eventually be merged. Development has been very slow and could take a while to merge all the different active versions (2.x, 3.x, & 4.x).

In addition, ArkoseLabs performs A/B testing on new versions with a limited user base before broader rollout. Clients will eventually have to migrate to the new versions.

Current permissions hash:

enhanced_fp.math_fingerprint

Runs a bunch of math calculations to detect the JavaScript engine based on how the engine handles floating point numbers.

This can be used to detect if the enforcement script is being run in a different environment than it's claimed by the client. For example, calculating the math like V8 (Chrome) but claiming to be JavaScriptCore (Safari).

enhanced_fp.supported_math_functions

Checks what Math functions are supported in the current browser.

enhanced_fp.3f76dd27

Gets the current device's screen orientation (portrait or landscape).

enhanced_fp.5dd48ca0

Checks the existence of:

  • window.RTCPeerConnection;
  • window.mozRTCPeerConnection;
  • window.webkitRTCPeerConnection;

And then stores the result in a number using bit shifting.

enhanced_fp.4b4b269e68

Random UUID that's used as a nonce to prevent replay attacks:

crypto.randomUUID();

enhanced_fp.6a62b2a558

Script version hash. Example: 6c9d6e9be9aa044cc5ce9548b4abe1b0.

Obtained from the filename of the enforcement script:

"enforcement.6c9d6e9be9aa044cc5ce9548b4abe1b0.js";

enhanced_fp.is_keyless

This field is true if no public key is provided in the "[...]/v2/api.js" script url. Instead the public key is provided via setConfig. More information can be found in Arkose's official documentation here.

enhanced_fp.wait_for_settings

Notice Some versions name this client_config__wait_for_settings instead of wait_for_settings.

Same as config.waitForSettings (default false). The client always requests /v2/<publicKey>/settings with GET and a 10s timeout, then applies theme data from the JSON body.

Response headers the script reads on that response:

  • x-amz-cf-id: treated as a request id (attached to errors and passed into the settings handler alongside the body).
  • x-ark-use-setup-session-credentials: if the value is the string true, the client stores includeSetupSessionCreds on global state. That flag is forwarded as the 7th argument to the internal POST helper for /fc/gt2/public_key/<publicKey> (setup session / token flow). There, fetch uses credentials: "include" only when that flag is true and the configured API host string does not end with arkoselabs.com; otherwise it uses "omit".

false: parallel async (settings and fingerprint at the same time).

true: sequential async (fingerprint runs in sync after settings and theme apply; slower).

If you omit the flag on a low-powered device, the client defaults this to true.

enhanced_fp.c2d2015

Collects sensor data (accelerometer, gyroscope, etc) in the format of [sensor name, is function or undefined], filters out undefined values, joins them with commas, and MD5 hashes it.

enhanced_fp.43f2d94

Collects web3 data such as if MetaMask is available. Example: ["MetaMask"].

enhanced_fp.20c15922

Checks if Bluetooth is available.

enhanced_fp.4f59ca8

Checks if Apple Pay is available and what version is supported via window.ApplePaySession.supportsVersion.

enhanced_fp.3ea7194

Checks if the HDR10, HLG, or DolbyVision codecs are supported.

enhanced_fp.05d3d24

Checks the following CSS properties, sorts, stringify "key=value;key=value", MD5 hash:

  • "(prefers-color-scheme: dark)"
  • "(prefers-reduced-motion: reduce)"
  • "(forced-colors: active)"
  • "(color-gamut: p3)"
  • "(color-gamut: srgb)"
  • "(prefers-contrast: more)"
  • "(inverted-colors: inverted)"
  • "(any-hover: hover)"
  • "(prefers-reduced-data: reduce)"
  • "(prefers-reduced-transparency: reduce)"
  • "(dynamic-range: high)"
  • "(hover: hover)"
  • "(pointer: fine)"
  • "(pointer: coarse)"
  • "(orientation: landscape)"
  • "(display-mode: fullscreen)"
  • "(display-mode: standalone)"
  • "(display-mode: minimal-ui)"
  • "(video-color-gamut: p3)"
  • "(video-color-gamut: srgb)"
  • "(video-color-gamut: rec2020)"
  • "(video-contrast: high)"
  • "(video-dynamic-range: high)"

enhanced_fp.speech_default_voice

System text-to-speech information.

For the hash:

  • Checks the voices you have installed.
  • Joins them with a comma ",".
  • MD5 hashes them.

enhanced_fp.speech_voices_hash

See: enhanced_fp.speech_default_voice.

MD5 hash of comma-joined name,lang pairs from speechSynthesis.getVoices(); null if none.

enhanced_fp.83eb055

Gets the keyboard layout language. Returns false in 2.13.0 because of SecurityError: getLayoutMap() must be called from a top-level browsing context or allowed by the permission policy. since 3.x.x is architected differently.

enhanced_fp.4ca87df3d1

mbio mouse events. See the events page for more details.

function insertEvent() { const n = { timestamp: Date.now() - Qt.timestamp, type: e, x: m.pageX, y: m.pageY, }; Qt["4ca87df3d1"].push(n); _lastMouseMove = n; } if (Qt["4ca87df3d1"].length < 75) { if (e === 0) { if (_lastMouseMove) { if ( Math.sqrt( (m.pageX - _lastMouseMove.x) * (m.pageX - _lastMouseMove.x) + (m.pageY - _lastMouseMove.y) * (m.pageY - _lastMouseMove.y), ) > 5 ) { insertEvent(); } return; } else { insertEvent(); return; } } Qt["4ca87df3d1"].push({ timestamp: Date.now() - Qt.timestamp, type: e, x: m.pageX, y: m.pageY, }); }

enhanced_fp.867e25e5d4

mbio touch events. See the events page for more details.

for (let i = 0; i < v.touches.length; i += 1) { if (Qt["867e25e5d4"].length < 75) { Qt["867e25e5d4"].push({ timestamp: Date.now() - Qt.timestamp, type: e, x: Math.floor(v.touches[i].pageX), y: Math.floor(v.touches[i].pageY), }); } }

enhanced_fp.d4a306884c

mbio key events. See the events page for more details.

const keyboardEventTypes = { Tab: 0, Enter: 1, Space: 3, ShiftLeft: 4, ShiftRight: 5, ControlLeft: 6, ControlRight: 7, MetaLeft: 8, MetaRight: 9, AltLeft: 10, AltRight: 11, Backspace: 12, Escape: 13, }; if (Qt.d4a306884c.length < 75) { Qt.d4a306884c.push({ timestamp: Date.now() - Qt.timestamp, type: e, code: keyboardEventTypes[A.code] ?? 14, }); }

enhanced_fp.vsadsa

When window.navigation exists, the collector reads window.navigation.entries().length; otherwise null.

enhanced_fp.basfas

performance.memory.jsHeapSizeLimit when exposed; the harness returns a tagged tuple [status, value] when the API is missing or blocked.

enhanced_fp.lfasdgs

Client build id from the enforcement bootstrap (header ark-build-id): window.arkl.cbid when present.

fe

Array of "PREFIX:value" strings.

DNT Do Not Track

Reads navigator.doNotTrack, then navigator.msDoNotTrack, then window.doNotTrack, else the string "unknown". Serialized like DNT:1 when the browser reports enabled DNT.

L language

Primary locale string from navigator.language, falling back through userLanguage, browserLanguage, and systemLanguage, else empty. Example: L:en-US.

D color depth

screen.colorDepth, or -1 if missing. Example: D:24.

PR device pixel ratio

window.devicePixelRatio when defined, else empty string. Example: PR:1.

S screen size

Two numbers width,height from screen.width / screen.height, ordered so the larger dimension is first (portrait swaps the pair). Example: S:1920,1080.

AS available screen

Similar to S, but uses screen.availWidth and screen.availHeight when both exist. Example: AS:1920,1050.

TO timezone offset

new Date().getTimezoneOffset() minutes from UTC. This can be correlated with the approximate location of your IP address. Example: TO:300. Live output is the single serialized fe line for this token.

SS sessionStorage

try { !!window.sessionStorage }. On throw, the collector returns true. Example: SS:true.

LS localStorage

Same pattern as SS for window.localStorage. Example: LS:true.

IDB IndexedDB

try { !!window.indexedDB } with the same catch behavior as SS. Example: IDB:true.

B IE addBehavior

Legacy IE surface check: !!document.body && !!document.body.addBehavior. Example: B:false.

ODB openDatabase

!!window.openDatabase (Web SQL). Example: ODB:false.

CPUC cpuClass

navigator.cpuClass when present, else "unknown" (deprecated on modern browsers). Not the same field as H.

PK platform

navigator.platform or "unknown". Example: PK:Win32.

CFP canvas fingerprint

Canvas fingerprint that is hashed using Java's hashCode method.

More details about canvas fingerprinting can be found in this paper by Google. Also this article by Fingerprint. It's worth noting that Google has taken action in recent years to reduce the amount of entropy that can be collected from a canvas.

FR fake resolution

Fake resolution signal: true if the full screen rectangle looks inconsistent with availWidth / availHeight (max or min of screen dimensions compared to avail). Example: FR:false.

FOS fake OS

Fake OS signal: The script guesses the OS family from the navigator.userAgent, then checks it against navigator.platform and navigator.oscpu (when present). Example: FOS:false.

FB fake browser

Fake browser signal: The script checks the browser family from navigator.userAgent, then verifies it against navigator.productSub and other browser behavior. Example: FB:false.

JSF javascript fonts

Checks for the presence of 65 different fonts from a predetermined list. This works by creating a span element with the font family set to the font name, and then checking the width and height of the span. If the width and height are different, then the font is present. This can be used to detect your platform and correlate with other signals that collect similar information. For example, Wingdings is only on Windows.

This can be empty on some sites including R••••x due to display: none on their dialog.

Search for fade modal-modern modal-modern-challenge-captcha in modal on that site for more

Source: { className: "modal-modern modal-modern-challenge-captcha", show: (p || !T) && !L.current, style: { display: T ? "block" : "none" }, onHide: P, backdrop: !!T && "static" } Source: .modal-dialog .modal-content .modal-body .modal-processing { display: none }

P plugins

The P: field is built from navigator.plugins names, sorted.

T touch

Three values joined with commas: max touch points from navigator.maxTouchPoints or navigator.msMaxTouchPoints (or -999 if NaN), whether document.createEvent("TouchEvent") succeeds without throwing, and "ontouchstart" in window. Example: T:0,false,false.

H hardware concurrency

navigator.hardwareConcurrency when defined, else "unknown". Example: H:16.

SWF flash / swfobject

typeof window.swfobject !== "undefined". Legacy; almost always false. Example: SWF:false.

ife_hash

MurmurHash3-128 hex digest of the packaged fe token strings, joined with ", " and seed 38.

jsbd

  • HL (history length): window.history.length;
  • NCE (navigator cookie enabled): navigator.cookieEnabled;
  • DT (document title): document.title;
  • NWD (not webdriver): JSON.stringify(navigator.webdriver);
  • DMTO: 1 (static)
  • DOTO: 1 (static)

Contains a copyright disclaimer that won't be reproduced here in full. Due to incompetence this field is an actually unused but could be in the future. As of 2026-05-11 (first observed in February 2025) this field is offically used.

"Copyright (c) [...]"