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");
}