datadome browser-feature-detection-comparison



var featurePaths = [
  "AppBannerPromptResult",
  "webkitRTCPeerConnection",
  "webkitAudioContext",
  "webkitRequestAnimationFrame",
  "chrome.runtime",
  "chrome.webstore",
  "console.context",
  "InputMethodContext",
  "SVGAnimationElement",
  "SVGPathSegList",
  "PasswordCredential",
  "ViewTransition",
  "VisualViewport.prototype.segments",
  "DeprecationReportBody",
  "MathMLElement",
  "opr",
  "CSS2Properties.prototype.colorScheme",
  "WebKitCSSMatrix",
  "SVGTextPositioningElement",
  "XMLHttpRequestEventTarget",
  "TextDecoderStream",
  "onloadend",
  "WritableStream",
  "TransformStream",
  "TextTrackCue",
  "WeakRef",
  "VisualViewport",
  "StyleSheet",
  "RTCDtlsTransport",
  "Atomics",
  "StaticRange",
  "UIEvent",
  "VideoStreamTrack",
  "OfflineResourceList",
  "SVGGeometryElement",
  "RTCDataChannel",
  "VTTRegion",
  "AbortController",
  "Controllers",
  "onanimationcancel",
  "SVGDocument",
  "IIRFilterNode",
  "RTCStatsReport",
  "MediaStreamTrack",
  "CSS2Properties.prototype.MozOsxFontSmoothing",
  "CropTarget",
  "BatteryManager",
  "LaunchQueue",
  "CSSFontPaletteValuesRule",
  "PushSubscriptionOptions",
  "DOMSettableTokenList",
  "RTCTrackEvent",
  "MozSmsMessage",
  "ServiceWorkerContainer",
  "CanvasCaptureMediaStream",
  "DeviceStorage",
  "XPathNSResolver",
  "SmartCardEvent",
  "WeakSet",
  "MozMobileMessageManager",
  "External.prototype.getHostEnvironmentValue",
  "WindowUtils",
  "XPathNamespace",
  "SVGFEDropShadowElement",
  "SharedWorker",
  "WorkerMessageEvent",
  "CSS2Properties.prototype.MozOSXFontSmoothing",
  "AudioSinkInfo",
  "Notification.prototype.image",
  "ContentVisibilityAutoStateChangeEvent",
  "PerformanceResourceTiming.prototype.renderBlockingStatus",
  "console.createTask",
  "PerformanceServerTiming",
  "CanvasFilter",
  "structuredClone",
  "onslotchange",
  "EyeDropper",
  "URLPattern",
  "VideoFrame",
  "WritableStreamDefaultController",
  "SharedArrayBuffer",
  "CSSCounterStyleRule",
  "CustomStateSet",
  "ReadableStreamDefaultController",
  "XMLDocument.prototype.hasStorageAccess",
  "CryptoKey",
  "SubmitEvent",
  "MediaMetadata",
  "VideoPlaybackQuality",
  "ReadableStreamDefaultReader",
  "UserActivation",
  "FragmentDirective",
  "WebKitMediaKeyError",
  "RTCRtpTransceiver.prototype.stop",
  "Scheduling",
  "EventCounts",
  "VideoTrackList",
  "SourceBuffer",
  "RTCError",
  "FontFaceSet",
  "CSSCharsetRule",
  "MediaDeviceInfo",
  "RTCPeerConnectionIceErrorEvent",
  "RTCSctpTransport",
  "MediaSessionCoordinator",
  "XULPopupElement",
  "MediaSourceHandle",
  "RTCEncodedAudioFrame",
  "__REACT_DEVTOOLS_GLOBAL_HOOK__",
  "ShadowRealm",
  "HTMLSlotElement",
  "DetachedViewControlEvent",
  "GeolocationPosition",
  "SiteBoundCredential",
  "MediaSource",
  "WebTransport",
  "GPUSupportedLimits",
  "ToggleEvent"
];

function detectFeaturePath(path) {
  var parts = path.split(".");
  var current = window;

  for (var index = 0; index < parts.length; index++) {
    var property = parts[index];

    if (current === null || current === undefined || !(property in current)) {
      return {
        supported: false,
        missingAt: parts.slice(0, index + 1).join("."),
        valueType: "-"
      };
    }

    try {
      current = current[property];
    } catch (error) {
      return {
        supported: index === parts.length - 1,
        missingAt: index === parts.length - 1 ? "-" : parts.slice(0, index + 1).join("."),
        valueType: "access-error:" + error.name
      };
    }
  }

  return {
    supported: true,
    missingAt: "-",
    valueType: typeof current
  };
}

var rows = [];
var result = {};
var supported = [];
var unsupported = [];

for (var index = 0; index < featurePaths.length; index++) {
  var path = featurePaths[index];
  var detection = detectFeaturePath(path);

  result[path] = detection.supported;

  rows.push({
    index: index,
    feature: path,
    supported: detection.supported,
    valueType: detection.valueType,
    missingAt: detection.missingAt
  });

  if (detection.supported) {
    supported.push(path);
  } else {
    unsupported.push(path);
  }
}

var summary = {
  total: featurePaths.length,
  supported: supported.length,
  unsupported: unsupported.length,
  supportedPercent: (supported.length / featurePaths.length * 100).toFixed(2) + "%"
};
var signature = featurePaths.map(function (path) {
  return result[path] ? "1" : "0";
}).join("");

function compareSignatures(currentSignature, referenceSignature) {
  var differences = [];
  var maxLength = Math.max(currentSignature.length, referenceSignature.length);

  for (var index = 0; index < maxLength; index++) {
    if (currentSignature[index] !== referenceSignature[index]) {
      differences.push({
        index: index,
        position: index + 1,
        feature: featurePaths[index] || "unknown",
        current: currentSignature[index] === undefined
          ? "missing"
          : currentSignature[index],
        reference: referenceSignature[index] === undefined
          ? "missing"
          : referenceSignature[index]
      });
    }
  }

  return {
    same: differences.length === 0,
    firstDifference: differences.length > 0 ? differences[0] : null,
    differences: differences
  };
}

// Paste another browser's signature here. Leave empty to skip comparison.
var referenceSignature = "0101001010110010011110111111111100110101011101111101010000100001100111111011111101111111111101110110011100110010101111";
var comparison = referenceSignature
  ? compareSignatures(signature, referenceSignature)
  : null;

console.table(rows);
console.log("summary", summary);
console.log("signature", signature);
console.log("supported", supported);
console.log("unsupported", unsupported);
console.log("result", result);
console.log("result JSON\n" + JSON.stringify(result, null, 2));

if (comparison) {
  console.log("referenceSignature", referenceSignature);
  console.log("same", comparison.same);
  console.log("firstDifference", comparison.firstDifference);
  console.table(comparison.differences);
} else {
  console.log("comparison skipped: set referenceSignature to another 01 signature");
}





posted @ 2026-06-09 16:49  AngDH  阅读(6)  评论(0)    收藏  举报