Skip to content
Undetect Research
Research Intelligence

Same Script, Different Behavior

A practical analysis of divergent JavaScript execution across mobile and desktop platforms, focused on fingerprinting, identity signals, anti-bot behavior, and privacy measurement methodology.

Paper analyzed: Same Script, Different Behavior: Characterizing Divergent JavaScript Execution Across Different Device Platforms, CCS 2025.

Divergent scripts
20.6%

Identically sourced scripts with mobile/desktop divergence

Condition-linked traces
41%

30,981 of 75,148 divergent subsequences tied to explicit client-side branches

Fingerprinting iFlows
76%

Derived flows referencing known fingerprinting APIs

Lesser-known APIs
6%

Conditional paths using platform-revealing APIs

1. Executive Summary

This paper studies a specific but important browser-fingerprinting problem: the same JavaScript file can execute different code paths on mobile and desktop, exposing users to different tracking, fingerprinting, bot-detection, and behavioral-profiling logic depending on platform.

The authors combine static JavaScript analysis with dynamic V8-level execution tracing to identify where execution diverges, what browser/device information caused the branch, and what the platform-exclusive code does. The core contribution is not merely detecting fingerprinting API usage, but tying pre-divergence data sources to post-divergence behavior through a PDG/iFlow pipeline.

The strongest result is that 20.6% of 109,071 identically sourced JavaScript files from the Tranco top 10K crawl showed mobile/desktop execution divergence. Desktop had 67.9% more divergent execution flows than mobile. The important scope qualifier is that 30,981 of 75,148 divergent subsequences, or about 41%, were tied to explicit satisfied client-side conditionals; the authors then derived 28,758 iFlows from that branch-conditioned subset. Among those iFlows, about 76% referenced known fingerprinting APIs, and another 6% involved lesser-known platform-revealing APIs such as DOM, event, performance, viewport, storage, and media-capability interfaces.

Operational takeaway: Single-platform crawling will miss behavior. Desktop-only crawls may overrepresent bot detection, storage, and browser fingerprinting; mobile-only crawls may overrepresent touch/gesture behavioral tracking.

2. Core Research Question

The paper asks: When the same JavaScript is loaded on mobile and desktop, how often does it execute differently, what platform/device signals cause the divergence, and what does the platform-specific code do?

RQ1: Prevalence

How often does identically sourced JavaScript diverge between mobile and desktop execution?

RQ2: Trigger signals

What browser APIs, variables, constants, or information-flow chains feed the conditionals that cause platform-specific execution?

RQ3: Post-divergence behavior

Once execution paths split, are the exclusive code paths doing optimization, tracking, fingerprinting, bot detection, session state tracking, behavioral profiling, or something else?

Why it matters

Platform-specific adaptation can be benign, but the same mechanism can enable device-specific fingerprinting, crawler evasion, bot scoring, or uneven privacy risk.

3. Key Findings

  • Divergence is common. The crawl found 109,071 unique JavaScript resources fetched in both mobile and desktop contexts; 22,495 showed non-zero divergence, meaning 20.6% of identically sourced scripts executed differently across platforms.
  • Desktop has more divergent execution, but attribution is scoped. The authors identified 75,148 divergent subsequences overall: 47,101 desktop and 28,047 mobile. They linked 30,981 of those to explicit satisfied conditional nodes and derived 28,758 iFlows. That 41% condition-linked share should be read as a lower-bound explanation of explicit client-side branching, not as complete attribution of all divergence.
  • Known fingerprinting APIs dominate pre-divergence triggers. Out of 28,758 iFlow chains, 21,455 contained at least one known fingerprinting API.
  • The traced branch subset had high source coverage. For conditional nodes associated with divergent subsequences, the paper reports successful information-flow tracing for almost 92.8%; failures are tied to missing JStap edges, timer-driven behavior, and dynamic JavaScript that does not map cleanly back into the static graph.
  • Divergence affects common shared scripts, not only obscure code. The most frequent script in the corpus was https://www.google-analytics.com/analytics.js, observed on 1,309 websites with a reported average divergence score of 15.6%.
  • Desktop-specific signals include plugin and legacy capability surfaces. Navigator.plugins and PluginArray.length were overwhelmingly desktop-associated in the paper's iFlow table.
  • Lesser-known platform-revealing APIs matter. The authors found 1,748 iFlows involving DOM manipulation, event handling, custom analytics globals, timing APIs, ResizeObserver, storage, navigation timing, and media-capability tests.
  • Post-divergence behavior differs by platform. Desktop-exclusive execution leaned toward browser fingerprinting, bot detection, session state tracking, device/platform identification, and network monitoring. The paper summarizes browser fingerprinting, bot detection, and session-state tracking as 77% desktop-exclusive within those categories, while behavioral tracking was 59% mobile-exclusive.
  • Headless desktop was closer to headful desktop than to mobile. Jaccard similarity was about 0.871 between headless and headful desktop, but only about 0.60-0.62 between mobile and either desktop mode.
  • Temporal stability was tested at the crawl level. Comparing headless-mobile divergence between November 2024 and July 2025, the paper reports no statistically significant difference with p = 0.37.
Distribution of divergence scores for uniquely executed JavaScript files across mobile and desktop platforms.
Figure 3: divergence score distribution for identically sourced scripts; 22,495 of 109,071 scripts had non-zero divergent activity.
Tables 1 and 2 showing divergent subsequences, satisfied conditional nodes, iFlows, and top API contributors.
Tables 1-2: desktop had more divergent subsequences, and most conditional iFlows included known fingerprinting APIs.
Grouped horizontal bar chart comparing mobile and desktop tracking activities in platform-exclusive subsequences.
Figure 4: desktop-exclusive paths skew toward fingerprinting, bot detection, session state, and platform identification; mobile is higher for behavioral tracking.

4. Fingerprinting Signals and Techniques

Signal / techniqueBrowser API or mechanismWhat it revealsIdentifying valueStabilityModern relevanceNotes
Platform/touch gatenavigator.platform, navigator.maxTouchPointsDesktop/mobile or touch-capable classificationMediumMedium-highHigh, retestUsed in Listing 1 to classify mobile and skip Flash/plugin probing.
User agent stringnavigator.userAgentBrowser, OS, mobile/desktop hintsMediumMediumHigh, but changingAppears in iFlows and case studies; used for Android Chrome detection.
Client Hintsnavigator.userAgentData.getHighEntropyValues()Model, platform version, full browser version listHighMedium-highHigh, retest carefullyListing 6 fetches high-entropy hints for Android Chrome.
Performance timingWindow.performance, Performance.now, navigation timingRuntime speed, timing, execution environmentMediumVariableHighTop iFlow contributor; also used in bot-detection heuristics.
Layout/rendering introspectiongetComputedStyle, DOM layoutRendered DOM/layout differencesMediumMediumHighCan reveal platform-specific rendering behavior.
Plugin surfacenavigator.plugins, PluginArray.length, navigator.mimeTypesPlugin support, legacy desktop capabilityHigh on desktopMediumLower for Flash, still useful as absence/presence signalVery desktop-skewed; Listing 1 checks Flash-related APIs on desktop path.
ActiveX fallbackActiveXObjectLegacy IE/Windows/Flash capabilityHigh where presentLow in modern webMostly outdatedStill important historically in the real-world snippet.
Canvas/WebGL profilingcanvas.getContext, WebGL renderer/vendor/extensionsGraphics stack, GPU/driver, headless signalsHighMedium-highHighListing 5 uses canvas/WebGL; desktop-exclusive fingerprinting was more pronounced.
WebDriver/bot flagnavigator.webdriverAutomation/headless signalHigh for bot detectionVariableHighListed in the bot-detection case study.
Behavioral touch trackingtouchstart, touchmove, TouchEvent.clientXGesture behavior, mobile interaction tracesMedium for identity, high for behavior profilingSession-dependentHighMobile-exclusive flows were dominated by behavioral tracking.
Mouse/click/scroll trackingClick, mouse, scroll eventsDesktop interaction behaviorMediumSession-dependentHighPaper contrasts mobile touch events with desktop click observations.
Viewport observationResizeObserver, viewport changesWindow size, responsive layout, orientation behaviorMediumMediumHighFound among lesser-known platform-revealing APIs.
DOM mutation trackingMutationRecord.target, MutationObserverUI state, ad-block/layout changes, dynamic DOMMediumVariableHighMutationRecord.target appears in top iFlow APIs.
Storage/session statelocalStorage, cookies, IndexedDB, database APIsPersistent or session identifiersHigh for linkabilityHigh where storage persistsHighDesktop-exclusive session state tracking was much more common.
Network monitoringConnection speed/type, beacon/background communicationNetwork environment and communication behaviorMediumVariableHighMore frequent on desktop-exclusive paths.
Media capability probingHTMLVideoElement.canPlayType, EME APIsCodec/DRM/platform media supportMediumMediumHighListing 3 and Listing 8 show codec/EME capability checks.
Custom analytics globalsWindow.gaData, Window.gaplugins, Window.isMobileService-specific telemetry/plugin/platform hintsMediumService-dependentHighCategorized as lesser-known platform-revealing interfaces.
Table 3 showing lesser-known API feature usage in desktop and mobile iFlow chains.
Table 3: lesser-known platform-revealing API categories feeding desktop and mobile iFlow chains.

5. Methodology

The paper uses a hybrid static + dynamic analysis pipeline.

System overview showing dynamic execution trace collection, PDG construction, divergence discovery, information flow, and behavior analysis.
Figure 2: the analysis pipeline combines dynamic VisibleV8 traces with static PDGs, then links divergence to iFlows and behavior categories.
  • Execution trace comparison. Execution traces are ordered API calls with character offsets in the JavaScript source. Mobile and desktop traces are compared using a dynamic-programming alignment metric similar to edit distance.
  • Static graph construction. JavaScript is parsed into ASTs and PDGs using a modified JStap pipeline. Dynamic VisibleV8 traces annotate PDG nodes to produce platform-specific execution graphs.
  • Conditionality analysis. Given a divergent API node, the algorithm walks upward in the PDG to find the closest relevant condition such as an IfStatement, LogicalExpression, or ConditionalExpression.
  • Information-flow analysis. The sink is the conditional variable or expression. The algorithm backtracks variables, functions, assignments, calls, browser APIs, and constants that influence the condition.
  • Crawl design. The crawl used a Google Pixel 4a for mobile and an Ubuntu 24.04 desktop machine. Both used Chromium 128. Crawling was automated with Puppeteer; the desktop crawl used headless Chromium with VisibleV8 and a stealth plugin.
  • Real-device mobile tracing. Mobile tracing was not only an emulation comparison: the authors ported VisibleV8 to Android to handle Android sandbox logging restrictions and contributed the mobile-specific patch upstream. This matters because the measurement depends on runtime traces from a real Pixel 4a.
  • Dataset. The authors crawled the top 10K Tranco sites, successfully gathering traces from 7,811 sites on both platforms, and identified 109,071 unique JavaScript resources fetched in both contexts.
API execution trace branch and platform-gated Flash plugin JavaScript listing.
Figure 1 and Listing 1: a trace branch where platform checks skip Flash/plugin probing on mobile but execute it on the desktop path.

6. Interpreting the Metrics

Divergence scoreHow different the API execution trace is between mobile and desktop for the same script. It is not a uniqueness score.
Percentage of divergent scriptsThe 20.6% result means about one in five identically sourced scripts executed at least somewhat differently across mobile and desktop.
iFlow countAn iFlow is the backward-traced chain of APIs, variables, functions, and constants that influence a conditional branch.
Fingerprinting API presenceWhen an iFlow contains a known fingerprinting API, the branch had access to device/browser-identifying signals before executing platform-specific code.
EntropyThe paper does not compute entropy bits per signal. Read "high entropy" operationally as "strong identifying or classification power."
Uniqueness and collisionThe paper does not run a Panopticlick-style population uniqueness test and does not directly measure fingerprint collisions.
StabilityThe paper tests stability of divergence distributions over two crawls, not long-term stability of individual user fingerprints.
Jaccard similarityA score near 1 means two crawl modes loaded mostly the same scripts. Headless and headful desktop were close; mobile and desktop were much less similar.
False positives / false negativesFalse negatives can come from incomplete static edges or dynamic JavaScript. False positives can come from grouped conditions or spurious Canvas-related divergence.
Correlation and independenceThe paper does not quantify statistical independence between signals, so iFlow counts should not be treated as additive entropy.
Table 4 showing Jaccard similarity for mobile, headless desktop, and headful desktop script sets.
Table 4: headless and headful desktop script sets were much closer to each other than either was to mobile.

7. Browser Probe Examples

Each example is a self-contained browser JavaScript snippet for inspecting the signal families discussed in the paper. Direct paper code is distinguished from reconstructed, inferred, or adapted examples.

Trace divergence score Reconstructed from pseudocode
Source type
Reconstructed from pseudocode
Purpose
Demonstrates the paper's mobile/desktop API-trace alignment idea using offsets, API names, gap penalty, misalignment penalty, and normalized divergence score.
Paper basis
Section 3 defines execution traces, gap penalty, misalignment penalty, lookahead window, and normalized divergence score.
Caveats
Compact browser-compatible reconstruction, not the authors' full implementation.
(async () => {
  const mobileTrace = [
    { offset: 0, api: "Start" },
    { offset: 10, api: "Cond" },
    { offset: 30, api: "M1" },
    { offset: 40, api: "M2" },
    { offset: 20, api: "C1" },
    { offset: 50, api: "Merge" },
    { offset: 60, api: "End" }
  ];

  const desktopTrace = [
    { offset: 0, api: "Start" },
    { offset: 10, api: "Cond" },
    { offset: 20, api: "C1" },
    { offset: 35, api: "D1" },
    { offset: 45, api: "D2" },
    { offset: 50, api: "Merge" },
    { offset: 60, api: "End" }
  ];

  function divergenceScore(Fm, Fd, { gap = 1, penalty = 0.5, lookahead = 5 } = {}) {
    const n = Fm.length, m = Fd.length;
    const same = (a, b) => a && b && a.offset === b.offset && a.api === b.api;
    const D = Array.from({ length: n + 1 }, () => Array(m + 1).fill(Infinity));

    D[0][0] = 0;
    for (let i = 1; i <= n; i++) D[i][0] = i * gap;
    for (let j = 1; j <= m; j++) D[0][j] = j * gap;

    for (let i = 1; i <= n; i++) {
  for (let j = 1; j <= m; j++) {
    D[i][j] = Math.min(D[i - 1][j] + gap, D[i][j - 1] + gap);

    if (same(Fm[i - 1], Fd[j - 1])) {
      D[i][j] = Math.min(D[i][j], D[i - 1][j - 1]);
    } else {
      const lo = Math.max(1, j - lookahead);
      const hi = Math.min(m, j + lookahead);
      for (let jp = lo; jp <= hi; jp++) {
        if (same(Fm[i - 1], Fd[jp - 1])) {
          D[i][j] = Math.min(D[i][j], D[i - 1][jp - 1] + penalty);
        }
      }
    }
  }
    }

    return {
  rawCost: D[n][m],
  normalized: D[n][m] / Math.max(n, m),
  parameters: { gap, penalty, lookahead }
    };
  }

  const result = {
    sourceType: "reconstructed from paper algorithm",
    mobileTrace,
    desktopTrace,
    divergence: divergenceScore(mobileTrace, desktopTrace)
  };

  console.log(result);
  return result;
})()
Platform-gated Flash/plugin probing Adapted from Listing 1
Source type
Adapted from Listing 1 for browser execution
Purpose
Reproduces the Listing 1 logic pattern: classify mobile using navigator.platform and navigator.maxTouchPoints; skip plugin/Flash probing on mobile; probe plugin surfaces on desktop.
Paper basis
Listing 1 and the surrounding methodology discussion use navigator.platform, navigator.maxTouchPoints, navigator.mimeTypes, ActiveXObject, and navigator.plugins.
Caveats
Flash and ActiveX are mostly legacy surfaces. This snippet safely detects availability without assuming support.
(async () => {
  const errors = [];
  const platform = navigator.platform || "";
  const maxTouchPoints = navigator.maxTouchPoints || 0;

  function isMobileLike(p, t) {
    return !!p && (
  p === "iPhone" ||
  p === "iPad" ||
  (typeof p.substr === "function" && p.substr(0, 7) === "Linux a" && t > 0)
    );
  }

  const mobileLike = isMobileLike(platform, maxTouchPoints);
  const flash = {
    skippedBecauseMobileLike: mobileLike,
    activeXAvailable: false,
    mimeTypeEnabled: null,
    pluginPresent: null
  };

  if (!mobileLike) {
    try {
  flash.activeXAvailable = "ActiveXObject" in window;
    } catch (e) {
  errors.push(`ActiveX check failed: ${e.message}`);
    }

    try {
  const mt = navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"];
  flash.mimeTypeEnabled = !!(mt && mt.enabledPlugin);
    } catch (e) {
  errors.push(`mimeTypes check failed: ${e.message}`);
    }

    try {
  flash.pluginPresent = !!(
    navigator.plugins &&
    (navigator.plugins["Shockwave Flash"] || navigator.plugins["Shockwave Flash 2.0"])
  );
    } catch (e) {
  errors.push(`plugins check failed: ${e.message}`);
    }
  }

  const result = {
    sourceType: "modernized from Listing 1",
    platform,
    maxTouchPoints,
    mobileLike,
    flash,
    errors
  };

  console.log(result);
  return result;
})()
Touch and coarse-pointer capability detection Adapted from Listings 2 and 9
Source type
Adapted from Listings 2 and 9
Purpose
Demonstrates touch-device detection using maxTouchPoints, ontouchstart, and CSS media queries for coarse pointers.
Paper basis
Listing 2 and Listing 9 show event and coarse-pointer checks used to infer touch/mobile capability.
Caveats
Touch capability is not equivalent to mobile; desktops can have touch screens, and privacy defenses may spoof or reduce these values.
(async () => {
  const result = {
    sourceType: "direct/conceptual from touch-detection listings",
    maxTouchPoints: navigator.maxTouchPoints ?? null,
    msMaxTouchPoints: navigator.msMaxTouchPoints ?? null,
    ontouchstartInWindow: "ontouchstart" in window,
    anyPointerCoarse: null,
    pointerCoarse: null,
    observedTouchStartDuringProbe: false,
    inferredTouchCapable: false,
    errors: []
  };

  try {
    result.anyPointerCoarse = matchMedia("(any-pointer: coarse)").matches;
    result.pointerCoarse = matchMedia("(pointer: coarse)").matches;
  } catch (e) {
    result.errors.push(`matchMedia failed: ${e.message}`);
  }

  const handler = () => { result.observedTouchStartDuringProbe = true; };
  try {
    window.addEventListener("touchstart", handler, { once: true, passive: true });
    await new Promise(resolve => setTimeout(resolve, 500));
    window.removeEventListener("touchstart", handler);
  } catch (e) {
    result.errors.push(`touch listener failed: ${e.message}`);
  }

  result.inferredTouchCapable = !!(
    result.maxTouchPoints ||
    result.msMaxTouchPoints ||
    result.ontouchstartInWindow ||
    result.anyPointerCoarse
  );

  console.log(result);
  return result;
})()
Media codec capability heuristic Adapted from Listing 3
Source type
Adapted from Listing 3
Purpose
Uses HTMLVideoElement.canPlayType() to compare codec support, mirroring the paper's example where codec availability can imply platform differences.
Paper basis
Listing 3 uses WebM VP9 and MP4 HVC1 support to infer Android-like media capability.
Caveats
Codec support changes with browser version, OS, installed components, and hardware acceleration.
(async () => {
  const result = {
    sourceType: "modernized from Listing 3",
    canPlayTypeAvailable: false,
    codecs: {},
    paperAndroidHeuristic: null,
    errors: []
  };

  try {
    const video = document.createElement("video");
    result.canPlayTypeAvailable = typeof video.canPlayType === "function";
    result.codecs.vp9Webm = video.canPlayType('video/webm; codecs="vp9"');
    result.codecs.hvc1Mp4 = video.canPlayType('video/mp4; codecs="hvc1"');
    result.paperAndroidHeuristic =
  result.codecs.vp9Webm === "probably" &&
  result.codecs.hvc1Mp4 !== "probably";
  } catch (e) {
    result.errors.push(e.message);
  }

  console.log(result);
  return result;
})()
Canvas/WebGL/browser profiling and bot signal collection Adapted from Listing 5
Source type
Adapted from Listing 5
Purpose
Collects browser profiling signals shown in the bot-detection case study: canvas/WebGL support, WebGL vendor/renderer, screen color depth, navigator metadata, and navigator.webdriver.
Paper basis
Listing 5 profiles WebGL/canvas and browser properties; the paper says the WebGL/canvas sequence was desktop-exclusive in that case study.
Caveats
This does not contact any server and does not reproduce the vendor script's full profiling.
(async () => {
  const result = {
    sourceType: "modernized from Listing 5",
    canvas2D: false,
    webgl: {
  supported: false,
  experimentalSupported: false,
  vendor: null,
  renderer: null,
  unmaskedVendor: null,
  unmaskedRenderer: null,
  extensionCount: null
    },
    browserInfo: {
  appName: navigator.appName,
  appVersion: navigator.appVersion,
  product: navigator.product,
  webdriver: navigator.webdriver,
  userAgent: navigator.userAgent
    },
    screenInfo: {
  colorDepth: screen.colorDepth,
  pixelDepth: screen.pixelDepth,
  width: screen.width,
  height: screen.height,
  devicePixelRatio: window.devicePixelRatio
    },
    errors: []
  };

  try {
    const canvas = document.createElement("canvas");
    result.canvas2D = !!canvas.getContext("2d");

    const gl =
  canvas.getContext("webgl") ||
  canvas.getContext("experimental-webgl");

    result.webgl.supported = !!canvas.getContext("webgl");
    result.webgl.experimentalSupported = !!canvas.getContext("experimental-webgl");

    if (gl) {
  result.webgl.vendor = gl.getParameter(gl.VENDOR);
  result.webgl.renderer = gl.getParameter(gl.RENDERER);
  result.webgl.extensionCount = (gl.getSupportedExtensions() || []).length;

  const dbg = gl.getExtension("WEBGL_debug_renderer_info");
  if (dbg) {
    result.webgl.unmaskedVendor = gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL);
    result.webgl.unmaskedRenderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL);
  }
    }
  } catch (e) {
    result.errors.push(e.message);
  }

  console.log(result);
  return result;
})()
Android Chrome Client Hints high-entropy fetch Adapted from Listing 6
Source type
Adapted from Listing 6
Purpose
Demonstrates conditional high-entropy Client Hints collection only when a user-agent check indicates Android Chrome.
Paper basis
Listing 6 checks Android Chrome and calls navigator.userAgentData.getHighEntropyValues(["model", "platformVersion", "fullVersionList"]).
Caveats
Availability and returned values depend on browser support, policy, origin, permissions, and privacy settings.
(async () => {
  const result = {
    sourceType: "modernized from Listing 6",
    userAgent: navigator.userAgent,
    hasUserAgentData: !!navigator.userAgentData,
    isAndroidChromeByUA: /Chrome/i.test(navigator.userAgent) && /Android/i.test(navigator.userAgent),
    requestedHints: ["model", "platformVersion", "fullVersionList"],
    highEntropyValues: null,
    skippedReason: null,
    errors: []
  };

  try {
    if (!result.hasUserAgentData) {
  result.skippedReason = "navigator.userAgentData is unavailable";
    } else if (!result.isAndroidChromeByUA) {
  result.skippedReason = "UA check did not match Android Chrome";
    } else if (typeof navigator.userAgentData.getHighEntropyValues !== "function") {
  result.skippedReason = "getHighEntropyValues is unavailable";
    } else {
  result.highEntropyValues =
    await navigator.userAgentData.getHighEntropyValues(result.requestedHints);
    }
  } catch (e) {
    result.errors.push(e.message);
  }

  console.log(result);
  return result;
})()
Encrypted Media Extension capability surface Adapted from Listing 8
Source type
Adapted from Listing 8
Purpose
Enumerates whether EME-related APIs exist and names the DRM key-system identifiers used in the paper's media-format example.
Paper basis
Listing 8 checks navigator.requestMediaKeySystemAccess, MSMediaKeys, and WebKitMediaKeys, with Widevine, PlayReady, and FairPlay labels.
Caveats
This only checks API availability. It does not request DRM access or test real key-system support.
(async () => {
  const result = {
    sourceType: "modernized from Listing 8",
    apiPresence: {
  requestMediaKeySystemAccess: !!navigator.requestMediaKeySystemAccess,
  MSMediaKeys: !!window.MSMediaKeys,
  WebKitMediaKeys: !!window.WebKitMediaKeys
    },
    keySystemsNamedInPaper: {
  "com.widevine.alpha": "Widevine",
  "com.microsoft.playready": "PlayReady",
  "com.apple.fps": "FairPlay"
    },
    anyEmeApiPresent: false
  };

  result.anyEmeApiPresent = Object.values(result.apiPresence).some(Boolean);

  console.log(result);
  return result;
})()
Short-lived touch behavioral probe Adapted from Listings 4 and 7
Source type
Adapted from Listings 4 and 7
Purpose
Demonstrates mobile behavioral tracking primitives by registering touchstart and touchmove listeners, recording only local counts and a small sample.
Paper basis
Listing 4 registers touchmove on touch devices; Listing 7 wraps an element with touchstart and touchmove handlers.
Caveats
This does not send data anywhere. Running it will observe touch activity on the current page for two seconds.
(async () => {
  const result = {
    sourceType: "modernized from Listings 4 and 7",
    durationMs: 2000,
    touchstartCount: 0,
    touchmoveCount: 0,
    samples: [],
    errors: []
  };

  const target = document.documentElement || window;

  function sampleTouch(e, type) {
    const t = e.touches && e.touches[0];
    if (result.samples.length < 5) {
  result.samples.push({
    type,
    time: Math.round(performance.now()),
    clientX: t ? t.clientX : null,
    clientY: t ? t.clientY : null,
    touchCount: e.touches ? e.touches.length : 0
  });
    }
  }

  const onStart = e => {
    result.touchstartCount++;
    sampleTouch(e, "touchstart");
  };

  const onMove = e => {
    result.touchmoveCount++;
    sampleTouch(e, "touchmove");
  };

  try {
    target.addEventListener("touchstart", onStart, { passive: true });
    target.addEventListener("touchmove", onMove, { passive: true });
    await new Promise(resolve => setTimeout(resolve, result.durationMs));
    target.removeEventListener("touchstart", onStart);
    target.removeEventListener("touchmove", onMove);
  } catch (e) {
    result.errors.push(e.message);
  }

  console.log(result);
  return result;
})()
Lesser-known platform-revealing surface probe Inferred from Table 3
Source type
Inferred from the conceptual description and Table 3
Purpose
Collects representative signals from the paper's lesser-known categories: DOM manipulation, computed style, mutation target, storage access, performance timing, viewport observation support, and media capability.
Paper basis
Table 3 lists DOM manipulation, event handling, custom interfaces, timing, viewport observation, performance monitoring, storage, and media queries.
Caveats
This is not the paper's exact code; it is a conservative browser-executable probe for the described signal families.
(async () => {
  const result = {
    sourceType: "inferred/modernized from Table 3",
    dom: {},
    style: {},
    mutation: {},
    storage: {},
    performance: {},
    viewport: {},
    media: {},
    errors: []
  };

  try {
    const el = document.createElement("div");
    el.textContent = "probe";
    el.style.cssText = "position:absolute;left:-9999px;width:10px;height:10px;";
    document.body.appendChild(el);

    result.dom.createElement = true;
    result.dom.querySelectorBody = !!document.querySelector("body");
    result.style.computedWidth = getComputedStyle(el).width;

    if ("MutationObserver" in window) {
  const seenTargets = [];
  const mo = new MutationObserver(records => {
    for (const r of records) seenTargets.push(r.target.nodeName);
  });
  mo.observe(document.body, { childList: true });
  const child = document.createElement("span");
  document.body.appendChild(child);
  document.body.removeChild(child);
  await new Promise(resolve => setTimeout(resolve, 0));
  mo.disconnect();
  result.mutation.targets = seenTargets;
    }

    el.remove();
  } catch (e) {
    result.errors.push(`DOM/style/mutation probe failed: ${e.message}`);
  }

  try {
    const key = "__platform_probe__";
    localStorage.setItem(key, "1");
    result.storage.localStorageRoundTrip = localStorage.getItem(key) === "1";
    localStorage.removeItem(key);
  } catch (e) {
    result.storage.localStorageRoundTrip = false;
    result.errors.push(`localStorage probe failed: ${e.message}`);
  }

  try {
    result.performance.now = performance.now();
    const nav = performance.getEntriesByType &&
  performance.getEntriesByType("navigation")[0];
    result.performance.navigationStartTime = nav ? nav.startTime : null;
    result.performance.activationStart = nav ? nav.activationStart : null;
  } catch (e) {
    result.errors.push(`performance probe failed: ${e.message}`);
  }

  result.viewport.resizeObserverAvailable = "ResizeObserver" in window;
  result.viewport.innerWidth = window.innerWidth;
  result.viewport.innerHeight = window.innerHeight;

  try {
    const video = document.createElement("video");
    result.media.h264 = video.canPlayType('video/mp4; codecs="avc1.42E01E"');
    result.media.vp9 = video.canPlayType('video/webm; codecs="vp9"');
  } catch (e) {
    result.errors.push(`media probe failed: ${e.message}`);
  }

  console.log(result);
  return result;
})()
Static data-flow dependency example Adapted from Listing 10
Source type
Adapted from Listing 10
Purpose
Shows the simple assignment dependency that the paper says JStap failed to model in one example.
Paper basis
Listing 10 shows b = b + a + 2 and notes that JStap missed a data-flow edge between b on lines 2 and 3.
Caveats
This snippet does not run JStap or build a PDG; it only demonstrates the JavaScript dependency relation.
(async () => {
  let a = 1;
  let b = 0;

  const before = { a, b };
  const expressionInputs = { previousB: b, a, constant: 2 };

  b = b + a + 2;

  const result = {
    sourceType: "direct/minimal from Listing 10",
    before,
    expressionInputs,
    after: { a, b },
    dependencyExplanation: "The new value of b depends on previous b, a, and constant 2."
  };

  console.log(result);
  return result;
})()

8. Practical Security Research Takeaways

  • Browser fingerprinting research. Differential, cross-platform measurement matters. A detector that only searches for known APIs may miss the conditional structure around when those APIs execute.
  • Bot detection research. Desktop-exclusive flows contained more bot-detection logic, including WebDriver, performance timing, canvas/WebGL behavior, and environment profiling.
  • Browser automation. Headless desktop automation can approximate desktop headful script loading and control flow better than it approximates mobile. Mobile-specific behavior needs a real or high-fidelity mobile environment.
  • Privacy defenses. Defenses should test whether reducing or spoofing platform signals changes execution paths, not merely whether individual values are reduced.
  • Anti-fingerprinting evaluation. A strong evaluation should compare normal browser vs privacy mode; mobile vs desktop; headless vs headful; spoofed vs real platform signals; and pre/post branch behavior.
  • Identity consistency testing. UA spoofing without coherent touch, media codecs, plugins, screen, and Client Hints can push scripts into inconsistent branches.
  • Attribution boundary. Treat iFlow source tracing as a strong explanation for explicit client-side branches, while still testing unexplained divergence caused by asynchronous callbacks, server-side variation, or network-dependent behavior.

9. Limitations and Gaps

  • Chromium/V8 scope. The system is based on Chromium and VisibleV8; it does not directly cover Firefox/Gecko or Safari/WebKit behavior.
  • Single mobile device model. The mobile environment is a Google Pixel 4a, which does not capture iOS Safari, Android WebView diversity, tablets, or vendor-customized browsers.
  • Desktop crawl used headless automation. The authors validate headless against headful, but headless still may miss real-user behavior or trigger automation-specific paths.
  • Static iFlow can miss dependencies. JStap may miss data-flow edges and struggles with eval, higher-order functions, runtime code generation, and dynamic JavaScript.
  • VisibleV8 logging scope is not complete for every operation. It logs WebIDL-defined APIs but not JavaScript built-ins such as Math.round() or user-defined functions not attached to globals.
  • No implicit-flow tracking. The iFlow analysis captures explicit influence, but not implicit flows.
  • Grouped conditions can over-attribute. When several conditions appear together, the algorithm may flag multiple sources even if only one was decisive.
  • No direct user-level uniqueness measurement. The paper measures divergent execution and API categories, not how uniquely resulting fingerprints identify users/devices across a population.
  • Tracking intent is not always proven. Platform-specific divergence can be benign. The paper shows privacy-relevant asymmetry, not malicious intent for every script.

10. Retesting Plan

Browsers and platforms

Test current stable and beta Chromium-family browsers, Firefox, Safari/WebKit, iOS Safari, Android Chrome, Android WebView, privacy-focused browsers, and anti-fingerprinting modes.

Signals to collect

Re-test navigator, UA, Client Hints, screen, touch/pointer queries, plugins, WebGL/canvas/audio, performance timing, layout/style, DOM mutation, storage, cookies, networking, media codecs, EME, analytics globals, and webdriver.

Sample design

Use synchronized repeated crawls over a large site list. Control network vantage point, profile state, consent banners, cache state, timing, and first-party/third-party script context.

Stability tests

Repeat across restarts, fresh profiles, stateful profiles, days/weeks, OS updates, browser updates, and different interaction modes.

Entropy and uniqueness checks

Add a consenting panel or lab population to compute per-signal entropy, collisions, linkability, and stability.

Automation vs real-user comparisons

Compare headless, headful, WebDriver, Playwright/Puppeteer, manual browsing, and realistic interaction replay.

Privacy-mode comparisons

Test normal mode, private mode, strict privacy settings, randomized APIs, reduced Client Hints, and spoofed platform profiles.

Key evaluation question

Do defenses merely change exposed values, or do they also change which branches execute?

11. Assessment

This is a valuable paper for browser fingerprinting and anti-bot researchers because it studies branch-conditioned behavior, not just API usage. Its main insight is operationally important: the same script may fingerprint, track, or profile differently depending on platform, and the branch trigger can often be traced to identifiable browser/device signals.

The most durable contribution is the hybrid method: combine V8-level dynamic traces with AST/PDG-based static analysis, identify the first divergent API, trace the nearest controlling condition, backtrack the information sources, then classify the exclusive post-divergence behavior.

The findings should be treated cautiously where they depend on Chromium 128, one Android device model, headless desktop crawling, JStap precision, and the web snapshot from the crawl period. The paper does not prove user-level uniqueness or malicious tracking intent. Still, it provides strong evidence that platform-specific JavaScript divergence is widespread, privacy-relevant, and measurable with high-fidelity instrumentation.

Appendix
Updated 2026-06-20

Glossary

Linked terms for branch-conditioned JavaScript measurement: browser signal APIs, Chromium/V8 instrumentation, iFlow and PDG analysis, crawl tooling, and validation statistics.
DOM and Browser APIs
navigator.platform
Context: Listing 1 and the signal table use this property as one branch input for classifying mobile-like versus desktop-like execution before plugin probing.
Meaning: A legacy Navigator string that identifies the browser platform or operating system. It is useful for observing what a script saw, but it is not a reliable modern feature-detection strategy.
navigator.maxTouchPoints
Context: The paper's Listing 1 and touch-detection examples use this property to infer touch capability and gate mobile-specific branches.
Meaning: A Navigator property exposing the maximum number of simultaneous touch contacts supported by the current device.
navigator.userAgent
Context: iFlows and case studies use the user-agent string for Android Chrome checks, mobile detection, and platform-specific branching.
Meaning: A legacy browser identification string containing browser, OS, device, and compatibility tokens. It is easy to parse incorrectly and is affected by user-agent reduction work.
navigator.userAgentData.getHighEntropyValues()
Context: Listing 6 conditionally requests high-entropy Client Hints such as `model`, `platformVersion`, and `fullVersionList` after an Android Chrome check.
Meaning: A User-Agent Client Hints method that lets scripts request additional browser/device metadata, subject to browser support, origin policy, and privacy controls.
Window.performance and Performance.now()
Context: `Window.performance` and `Performance.now` are among the paper's top iFlow contributors and appear in bot-detection and timing heuristics.
Meaning: The Performance APIs expose high-resolution timing and navigation/rendering measurements. In this report they matter as branch inputs, not as standalone proof of identity.
PerformanceNavigationTiming.activationStart and PerformanceEntry.startTime
Context: Table 3 lists navigation and rendering timing properties among lesser-known platform-revealing sources.
Meaning: Performance timing entries expose lifecycle timestamps that can differ across browser state, page restoration, device speed, and navigation path.
Window.getComputedStyle()
Context: The paper reports `Window.getComputedStyle` as a major iFlow contributor, especially for mobile layout/rendering adaptation.
Meaning: A method returning the resolved CSS values for an element. Scripts can use it to observe rendered layout/style differences across platforms.
navigator.plugins, navigator.mimeTypes, and PluginArray.length
Context: Listing 1 skips Flash/plugin checks on mobile but probes plugin-related surfaces on desktop; `Navigator.plugins` and `PluginArray.length` are heavily desktop-skewed in Table 2.
Meaning: Legacy plugin and MIME-type surfaces that reveal installed or supported plugin capabilities. Modern browsers reduce their practical value, but their presence or absence can still affect branch behavior.
Navigator.webdriver
Context: The bot-detection case study includes `navigator.webdriver` among automation/headless signals.
Meaning: A WebDriver-exposed Navigator flag that can indicate the browser is controlled by automation.
Canvas API
Context: The desktop-only bot-detection case study profiles canvas and WebGL behavior, and the limitations note potential spurious Canvas-related divergence.
Meaning: The Canvas API allows scriptable bitmap drawing. Differences in rendering, fonts, GPU paths, and browser implementation can become fingerprinting inputs.
EventTarget.addEventListener()
Context: The paper's touch and UI-tracking examples register event listeners for touch, click, movement, scroll, and interface monitoring.
Meaning: The event-registration method used by DOM objects to subscribe to user-input and page events. In this report it is a behavioral telemetry primitive.
TouchEvent, touchstart, and touchmove
Context: Mobile-exclusive behavioral tracking is tied to touch-based event listeners and touch coordinates in Listings 4, 7, and 9.
Meaning: Touch events expose gesture and contact information for touch-capable devices. They can support legitimate interaction, but also fine-grained behavioral profiling.
window.matchMedia() and CSS pointer
Context: Listing 9 uses coarse-pointer media queries together with touch properties to infer touch/mobile capability.
Meaning: `matchMedia()` evaluates CSS media queries in JavaScript; the `pointer` media feature classifies the primary pointing device's accuracy.
ResizeObserver
Context: Table 3 lists `Window.ResizeObserver` under viewport observation as a lesser-known platform-revealing API category.
Meaning: An API for observing changes to an element's size. It can reveal responsive layout behavior and viewport-dependent adaptation.
MutationRecord.target and MutationObserver
Context: `MutationRecord.target` appears among the top iFlow APIs, and the report discusses UI tracking and cyclic DOM manipulation.
Meaning: Mutation observers report DOM changes; `MutationRecord.target` identifies the node affected by a mutation.
Storage APIs: localStorage, cookies, and IndexedDB
Context: Desktop-exclusive paths in the report skew toward session-state tracking and storage-based persistence.
Meaning: Browser storage APIs can persist identifiers or state across page loads and visits, subject to origin, browser policy, and privacy mode behavior.
HTMLMediaElement.canPlayType()
Context: Listing 3 uses codec support checks to infer Android-like media capability.
Meaning: A media element method that reports whether the browser is likely to play a given MIME type and codec string.
navigator.requestMediaKeySystemAccess()
Context: Listing 8 enumerates EME-related key-system support such as Widevine, PlayReady, and FairPlay.
Meaning: An Encrypted Media Extensions method used to request access to a media key system. In this report, the API surface is used as a platform capability signal.
Screen, viewport, and devicePixelRatio
Context: The report's signal table and case studies discuss screen, viewport, rendering, and pixel-ratio signals as possible branch inputs.
Meaning: Screen and viewport properties expose display dimensions, color depth, pixel density, and layout size. They are useful for rendering but can also classify device families.
Window.location
Context: `Window.location` is one of the top API contributors in Table 2's iFlow summary.
Meaning: The Location object exposes the current document URL and navigation controls. It can feed branch logic tied to domain, path, query state, or redirect context.
Navigator.connection and the Network Information API
Context: Network monitoring is one of the post-divergence tracking categories, especially on desktop-exclusive paths.
Meaning: The Network Information API can expose connection characteristics such as effective type or downlink where implemented. Availability varies by browser.
Custom analytics globals: Window.gaData, Window.gaplugins, and Window.isMobile
Context: Table 3 groups custom analytics interfaces and platform labels as lesser-known sources that can influence conditional branches.
Meaning: These are service- or site-defined globals, not standard Web APIs. They matter because they can store platform or telemetry state that later branches consume.
Browser, Chrome, and V8 Internals
Chromium
Context: The measurement uses Chromium 128 on both the Pixel 4a and desktop environments, so the findings are explicitly scoped to Chromium/V8 rather than Firefox/Gecko or Safari/WebKit.
Meaning: Chromium is the open-source browser project underlying Chrome and many other browsers. Its implementation choices shape the API traces VisibleV8 observes.
V8
Context: VisibleV8 instruments V8-level JavaScript execution traces, making V8 central to the dynamic portion of the paper's method.
Meaning: V8 is Chromium's JavaScript and WebAssembly engine. In this report it is the runtime layer where API/property activity is logged.
WebIDL-defined APIs
Context: The limitations say VisibleV8 logs WebIDL-defined APIs but not JavaScript built-ins such as `Math.round()` or unrelated user-defined functions.
Meaning: Web IDL is the interface definition language used by web standards to specify browser-exposed APIs and their JavaScript bindings.
Blink
Context: The report discusses Chromium browser behavior and WebIDL/API exposure; Blink is the Chromium rendering engine that implements many web-platform APIs.
Meaning: Blink is Chromium's rendering engine. It is relevant as the implementation layer for DOM, rendering, layout, and many Web API bindings.
Headless Chromium and headful browsing
Context: Section 9 compares mobile, headless desktop, and headful desktop crawl modes and finds headless desktop much closer to headful desktop than to mobile.
Meaning: Headless mode runs Chromium without a visible browser UI; headful mode runs a normal visible browser. Similarity between them does not imply similarity to mobile execution.
WebDriver
Context: The report treats automation detection as a post-divergence behavior category and includes `navigator.webdriver` in bot-detection examples.
Meaning: WebDriver is a browser automation standard. Its control path and exposed state can be used by scripts to infer automation.
User-agent reduction and Client Hints
Context: The report warns that UA spoofing without coherent touch, media, plugins, screen, and Client Hints values can push scripts into inconsistent branches.
Meaning: User-agent reduction limits passive UA string detail, while Client Hints provide a more structured request/response path for selected client metadata.
Browser fingerprinting
Context: The paper distinguishes branch-conditioned API use from direct user-level uniqueness testing, but many pre-branch sources and post-branch behaviors are fingerprinting-relevant.
Meaning: Browser fingerprinting combines observable browser/device attributes to classify, recognize, or link browsers without relying solely on cookies.
Statistics and Measurement Concepts
Divergence score
Context: The headline 20.6% prevalence result is based on non-zero mobile/desktop execution divergence scores for identically sourced scripts.
Meaning: In this paper, the divergence score is a normalized API-trace dissimilarity measure. It is not entropy, uniqueness, or a direct tracking rate.
Dynamic programming alignment
Context: The trace comparison algorithm aligns mobile and desktop API sequences with gap and misalignment penalties.
Meaning: Dynamic programming is used to compute a minimum-cost sequence alignment efficiently by reusing subproblem results.
Information flow and iFlow
Context: The report's core method backtracks from branch conditions to APIs, variables, function calls, constants, and string literals, producing `iFlow` chains.
Meaning: Information-flow analysis asks what sources can influence a sink. Here the sink is a conditional expression or variable controlling platform-specific execution.
Program Dependency Graph (PDG)
Context: JStap-generated PDGs are used to map static dependencies, identify conditional nodes, and trace data sources behind divergence.
Meaning: A PDG represents data and control dependencies in a program. Missing edges can cause false negatives in iFlow tracing.
Jaccard similarity
Context: Table 4 uses Jaccard similarity to compare script sets loaded by mobile, headless desktop, and headful desktop crawls.
Meaning: Jaccard similarity is intersection size divided by union size. A higher value means greater set overlap, not identical execution behavior.
Two-sample t-test and p = 0.37
Context: Section 9 reports no statistically significant temporal difference between November 2024 and July 2025 headless-mobile divergence distributions with `p = 0.37`.
Meaning: A two-sample t-test evaluates whether two sample means differ under stated assumptions. The reported p-value should be read as crawl-level distribution evidence, not per-user fingerprint stability.
Entropy
Context: The report uses "high entropy" operationally for strong identifying or classification signals but does not compute entropy bits for each API.
Meaning: Information entropy measures uncertainty or information content. Fingerprinting studies often use it to estimate how identifying a signal can be across a population.
Uniqueness, collisions, and linkability
Context: The limitations stress that the paper does not perform a Panopticlick-style population uniqueness or collision-rate study.
Meaning: Uniqueness asks whether one fingerprint stands out in a population; collisions are shared fingerprints; linkability asks whether observations can be tied across time or contexts.
False positives and false negatives
Context: Static iFlow gaps, grouped-condition over-attribution, and spurious Canvas divergence create measurement error risks.
Meaning: False positives are cases flagged as relevant when they are not; false negatives are relevant cases missed by the measurement system.
Correlation and statistical independence
Context: The Astro report warns that iFlow counts should not be treated as additive entropy because the paper does not quantify independence between signals.
Meaning: Correlation measures association between variables; statistical independence means one variable's value does not change the probability distribution of another.
Research Tools and Datasets
VisibleV8
Context: VisibleV8 supplies the dynamic API/property traces that make the paper's cross-platform execution comparison possible.
Meaning: VisibleV8 is an instrumented V8/Chromium variant that logs JavaScript API calls and selected host-object property activity.
VisibleV8 for Android
Context: The paper ports VisibleV8 to Android so the mobile environment is a real Pixel 4a rather than only emulation.
Meaning: The Android port changes logging behavior to work within Android sandbox constraints while preserving the measurement goal.
Needs review: the paper cites https://github.com/wspr-ncsu/visiblev8/pull/35, but the pull-request page did not return crawlable content during this pass.
JStap
Context: The paper uses a modified JStap pipeline to build ASTs and PDGs, then notes that JStap can miss data-flow edges.
Meaning: JStap is a static JavaScript analysis tool cited by the paper for PDG/data-flow construction.
Needs review: no stable public project URL was found during this pass; this DOI links the source paper that cites Fass, Backes, and Stock, "Jstap: a static pre-filter for malicious javascript detection," ACSAC 2019.
JSPrism
Context: The paper's artifacts refer to JSPrism as the authors' open-source work, while this repository's code snippets are reconstructed or modernized review helpers.
Meaning: JSPrism is the paper-specific framework name for the hybrid divergence analysis pipeline.
Needs review: the raw extraction lists https://github.com/ahsan238/JSPrism, but the repository page did not return crawlable content during this pass.
Puppeteer
Context: The crawl automation uses Puppeteer on both mobile and desktop settings, with desktop Chromium running headless.
Meaning: Puppeteer is a JavaScript automation library for controlling Chrome/Chromium-family browsers.
Tranco
Context: The crawl targets the top 10,000 Tranco-ranked websites and derives the 109,071 identically sourced script corpus from successful paired crawls.
Meaning: Tranco is a research-oriented top-sites ranking designed to be more manipulation-resistant than simple popularity lists.
mitmproxy
Context: The authors use mitmproxy to validate network-load consistency and successful page loading, while relying on VisibleV8 logs for JavaScript execution analysis.
Meaning: mitmproxy is an intercepting proxy used to inspect HTTP(S) traffic during measurement.
OpenWPM
Context: The related-work section contrasts prior OpenWPM-based measurements with this paper's V8-level tracing approach.
Meaning: OpenWPM is a web privacy measurement framework commonly used for crawling and tracking/fingerprinting studies.
FingerprintJS
Context: The post-divergence behavior classifier draws on known fingerprinting APIs and industry-grade fingerprinting solutions such as FingerprintJS.
Meaning: FingerprintJS is an open-source browser fingerprinting library and a useful reference point for practical signal collection.
Webpack
Context: The information-flow section notes that bundling, minification, and obfuscation can obscure variable semantics before JStap/iFlow tracing.
Meaning: Webpack is a JavaScript bundler; bundled/minified output can make static data-flow reconstruction harder.