Android Browsers(default settings) |
brave 1.68 |
chrome 127.0 |
cromite 127.0 |
duckduckgo 5.210 |
edge 127.0 |
firefox 129.0 |
focus 129.0 |
mull 127.0 |
opera 83.5 |
samsung 25.0 |
tor 115.2 |
vivaldi 6.8 |
yandex 24.7 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
State Partitioning testsWhich browsers isolate websites to prevent them from sharing data to track you?
A common vulnerability of web browsers is that they allow tracking companies to 'tag' your browser with some data ('state') that identifies you. When third-party trackers are embedded in websites, they can see this identifying data as you browse to different websites. Fortunately, it is possible for this category of leaks to be fixed by partitioning all data stored in the browser such that no data can be shared between websites. |
|||||||||||||
Alt-Svc
Alt-Svc allows the server to indicate to the web browser that a resource should be loaded on a different server. Because this is a persistent setting, it could be used to track users across websites if it is not correctly partitioned. |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: h2, h2, h2, h2, h2 unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h3, h3, h3, h3, h3 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: h2, h2, h2, h2, h2 unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: h2, h2, h2, h2 unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same first party: h3, h3, h3, h3, h3 result, different first party: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
blob
A 'blob URL' is a local reference to some raw data. Trackers can use a blob URL to share data between websites. |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch result, different first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch result, different first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch result, different first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch result, different first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch result, different first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource. result, different first party: Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource. unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource. result, different first party: Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource. unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource. result, different first party: Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource. unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch result, different first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch result, different first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource. result, different first party: Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource., Error: NetworkError when attempting to fetch resource. unsupported: false, false, false, false passed: undefined test failed: true, true, true, true |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch result, different first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { try { let blobURL = URL.createObjectURL(new Blob([secret])); fetch(`${baseURI}blob?mode=write&key=${secret}&blobUrl=${encodeURIComponent(blobURL)}`); } catch (e) { throw new Error("Unsupported"); } } read: async (secret) => { let response = await fetch(`${baseURI}blob?mode=read&key=${secret}`); let result = await response.json(); let blobUrl = decodeURIComponent(result.blobUrl); let blobResponse = await fetch(blobUrl); return blobResponse.text(); } result, same first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch result, different first party: Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch, Error: Failed to fetch unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
BroadcastChannel
A BroadcastChannel is designed to send messages between tabs. In some browsers it can be used for cross-site communication and tracking. |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. unsupported: false, false, false, false passed: undefined test failed: true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: (secret) => { try { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data === "request") { bc.postMessage(secret); } }; } catch (e) { throw new Error("Unsupported"); } } read: () => new Promise((resolve, reject) => { let bc = new BroadcastChannel("secrets"); bc.onmessage = (event) => { if (event.data !== "request") { resolve(event.data); } }; bc.postMessage("request"); setTimeout(() => reject({message: "no BroadcastChannel message"}), 3000); }) result, same first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message result, different first party: Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message, Error: no BroadcastChannel message unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
CacheStorage
The Cache API is a content storage mechanism originally introduced to support ServiceWorkers. If the same Cache object is accessible to multiple websites, it can be abused to track users. |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: 143d61f8-2894-4529-ad80-0a53e9ebc6cc, 143d61f8-2894-4529-ad80-0a53e9ebc6cc, 143d61f8-2894-4529-ad80-0a53e9ebc6cc, 143d61f8-2894-4529-ad80-0a53e9ebc6cc, 143d61f8-2894-4529-ad80-0a53e9ebc6cc result, different first party: Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url') unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: ff5789e9-e545-4690-9fea-1af9b462597e, ff5789e9-e545-4690-9fea-1af9b462597e, ff5789e9-e545-4690-9fea-1af9b462597e, ff5789e9-e545-4690-9fea-1af9b462597e, ff5789e9-e545-4690-9fea-1af9b462597e result, different first party: Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url') unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63, 2f149f9d-7d24-4463-baa9-df54b4e81d63, 2f149f9d-7d24-4463-baa9-df54b4e81d63, 2f149f9d-7d24-4463-baa9-df54b4e81d63, 2f149f9d-7d24-4463-baa9-df54b4e81d63 result, different first party: Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent. unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p result, different first party: 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0 result, different first party: Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url') unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: 39122539-ac2b-4685-b7fc-0e032c9e090b, 39122539-ac2b-4685-b7fc-0e032c9e090b, 39122539-ac2b-4685-b7fc-0e032c9e090b, 39122539-ac2b-4685-b7fc-0e032c9e090b, 39122539-ac2b-4685-b7fc-0e032c9e090b result, different first party: Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: cb2b3139-17be-441a-beaa-850c1130ce80, 381bfe46-5daa-42c3-9e58-39d98058f186, ddd70737-9afe-474e-ae84-787830e88cbc, d6af2086-88f6-4f4f-9669-2d31e549a804, 95431be4-0dbc-4181-a196-d3b6afacb47d result, different first party: Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: ec60fada-f7df-4f1e-b11a-25a5811cf11f, ec60fada-f7df-4f1e-b11a-25a5811cf11f, ec60fada-f7df-4f1e-b11a-25a5811cf11f, ec60fada-f7df-4f1e-b11a-25a5811cf11f, ec60fada-f7df-4f1e-b11a-25a5811cf11f result, different first party: Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: c97b5d06-2396-4bb1-9f7d-6fde65072b04, c97b5d06-2396-4bb1-9f7d-6fde65072b04, c97b5d06-2396-4bb1-9f7d-6fde65072b04, c97b5d06-2396-4bb1-9f7d-6fde65072b04, c97b5d06-2396-4bb1-9f7d-6fde65072b04 result, different first party: Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url') unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: a31f089a-366d-46aa-8a3d-39c59eae3ef3_3p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_3p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_3p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_3p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_3p result, different first party: Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url') unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. result, different first party: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: 1af58a1e-55c5-4125-ba6b-5729d21fd23c, 1af58a1e-55c5-4125-ba6b-5729d21fd23c, 1af58a1e-55c5-4125-ba6b-5729d21fd23c, 1af58a1e-55c5-4125-ba6b-5729d21fd23c, 1af58a1e-55c5-4125-ba6b-5729d21fd23c result, different first party: Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url') unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same first party: 4f69eb13-b603-4269-81bb-78ce896b6e33_3p, 4f69eb13-b603-4269-81bb-78ce896b6e33_3p, 4f69eb13-b603-4269-81bb-78ce896b6e33_3p, 4f69eb13-b603-4269-81bb-78ce896b6e33_3p, 4f69eb13-b603-4269-81bb-78ce896b6e33_3p result, different first party: Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url'), Error: Cannot read properties of undefined (reading 'url') unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
cookie (HTTP)
The cookie, first introduced by Netscape in 1994, is a small amount of data stored by your browser on a website's behalf. It has legitimate uses, but it is also the classic cross-site tracking mechanism, and today still the most popular method of tracking users across websites. Browsers can stop cookies from being used for cross-site tracking by either blocking or partitioning them. |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_http, d77fced8-9428-496f-9946-549bc356d246_http, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_http, 1256fd40-841d-47a2-8902-ce5636a32cb3_http, ce2b00b3-8519-499e-967c-ea73aad6dbb1_http result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: 91872272-1110-44b8-bb8a-fefcdca4198f_http, be106815-df48-45c9-9d4a-86b9823a76db_http, 3d351c8a-a896-428b-bb2d-cb2f2838d223_http, aa902857-ae8c-4123-bd90-2f0901ab8e24_http, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_http result, different first party: 91872272-1110-44b8-bb8a-fefcdca4198f_http, be106815-df48-45c9-9d4a-86b9823a76db_http, 3d351c8a-a896-428b-bb2d-cb2f2838d223_http, aa902857-ae8c-4123-bd90-2f0901ab8e24_http, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63_http, e52cd2ae-6e45-4906-900c-b02f787f4589_http, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_http, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b_http, 32b124ca-4477-4984-b641-b772ba9d739c_http result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: b0873046-aed6-464f-bc48-1c45525ef56d_http, f76c7d52-c07b-4369-84d4-6d511639e60c_http, 32f07353-227f-4e1d-948d-0e4bad5866b1_http, fb89b2ee-5914-4ee5-ae26-30bc3301d983_http, 6567a88a-f349-4734-8828-9cc0df7600bb_http result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d_http, 4df32057-71ef-4c97-b4a9-375da39140da_http, 5a39645b-74e0-456f-a064-66a4075a8239_http, 00946081-6b17-4b36-9aa6-61d144addef7_http, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_http result, different first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d_http, 4df32057-71ef-4c97-b4a9-375da39140da_http, 5a39645b-74e0-456f-a064-66a4075a8239_http, 00946081-6b17-4b36-9aa6-61d144addef7_http, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: a6911260-affb-4f85-b66e-6372edef8271_http, f3f642e9-a578-4fd7-b323-71de0e1e5fda_http, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_http, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_http, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_http result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: cb2b3139-17be-441a-beaa-850c1130ce80_http, 381bfe46-5daa-42c3-9e58-39d98058f186_http, ddd70737-9afe-474e-ae84-787830e88cbc_http, d6af2086-88f6-4f4f-9669-2d31e549a804_http, 95431be4-0dbc-4181-a196-d3b6afacb47d_http result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: faca3efe-63fa-40b1-960d-14241446e02b_http, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_http, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_http, 73a700b0-d223-4f5a-9336-863c67ef6a20_http, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_http result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: 8a59cde4-6473-44da-b170-f66c57b8df4a_http, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_http, 5d49d947-6006-4865-9c31-04b966b4ac61_http, 87e46975-6855-4644-97bf-f9c66bae1455_http, db0c6390-897f-4eb6-b734-977466b215b6_http result, different first party: 8a59cde4-6473-44da-b170-f66c57b8df4a_http, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_http, 5d49d947-6006-4865-9c31-04b966b4ac61_http, 87e46975-6855-4644-97bf-f9c66bae1455_http, db0c6390-897f-4eb6-b734-977466b215b6_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: 08871018-9567-44a6-b124-5cb6fb4797cf_http, ed296612-deee-4fff-b0e8-d7ee83e3b345_http, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_http, 4ee8618c-dd14-47c0-ad13-50e8f625e228_http, 929477f2-6d6b-4b18-a642-f2ca892f3876_http result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: 77f9d876-5d2d-4776-824f-839b4afa98da_http, 3959c542-32c6-4033-b316-37a1a8e480e0_http, bec75a88-52bd-463a-b926-f1694cdddcaf_http, 2239e757-c407-4798-907e-852d4ab1d41f_http result, different first party: , , , unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_http, e8f74dec-686f-4084-a15c-80172d70e290_http, c7af78eb-b2be-4edb-a01f-c5e80885c91b_http, bfa2edb1-7890-44d5-90e0-94ac0fef762a_http, 1e2332aa-e33b-49d1-b45e-4202d0db4096_http result, different first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_http, e8f74dec-686f-4084-a15c-80172d70e290_http, c7af78eb-b2be-4edb-a01f-c5e80885c91b_http, bfa2edb1-7890-44d5-90e0-94ac0fef762a_http, 1e2332aa-e33b-49d1-b45e-4202d0db4096_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same first party: df04981a-509a-43d2-bd50-07e15e2191a0_http, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_http, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_http, 975fde78-d933-4101-8f70-1fb2227ac766_http, 03b8d7d5-b189-4156-8310-62787b519fe2_http result, different first party: df04981a-509a-43d2-bd50-07e15e2191a0_http, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_http, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_http, 975fde78-d933-4101-8f70-1fb2227ac766_http, 03b8d7d5-b189-4156-8310-62787b519fe2_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
cookie (JS)
The cookie, first introduced by Netscape in 1994, is a small amount of data stored by your browser on a website's behalf. It has legitimate uses, but it is also the classic cross-site tracking mechanism, and today still the most popular method of tracking users across websites. Browsers can stop cookies from being used for cross-site tracking by either blocking or partitioning them. |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_js, d77fced8-9428-496f-9946-549bc356d246_js, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_js, 1256fd40-841d-47a2-8902-ce5636a32cb3_js, ce2b00b3-8519-499e-967c-ea73aad6dbb1_js result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: 91872272-1110-44b8-bb8a-fefcdca4198f_js, be106815-df48-45c9-9d4a-86b9823a76db_js, 3d351c8a-a896-428b-bb2d-cb2f2838d223_js, aa902857-ae8c-4123-bd90-2f0901ab8e24_js, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_js result, different first party: 91872272-1110-44b8-bb8a-fefcdca4198f_js, be106815-df48-45c9-9d4a-86b9823a76db_js, 3d351c8a-a896-428b-bb2d-cb2f2838d223_js, aa902857-ae8c-4123-bd90-2f0901ab8e24_js, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63_js, e52cd2ae-6e45-4906-900c-b02f787f4589_js, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_js, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b_js, 32b124ca-4477-4984-b641-b772ba9d739c_js result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: b0873046-aed6-464f-bc48-1c45525ef56d_js, f76c7d52-c07b-4369-84d4-6d511639e60c_js, 32f07353-227f-4e1d-948d-0e4bad5866b1_js, fb89b2ee-5914-4ee5-ae26-30bc3301d983_js, 6567a88a-f349-4734-8828-9cc0df7600bb_js result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d_js, 4df32057-71ef-4c97-b4a9-375da39140da_js, 5a39645b-74e0-456f-a064-66a4075a8239_js, 00946081-6b17-4b36-9aa6-61d144addef7_js, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_js result, different first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d_js, 4df32057-71ef-4c97-b4a9-375da39140da_js, 5a39645b-74e0-456f-a064-66a4075a8239_js, 00946081-6b17-4b36-9aa6-61d144addef7_js, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: a6911260-affb-4f85-b66e-6372edef8271_js, f3f642e9-a578-4fd7-b323-71de0e1e5fda_js, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_js, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_js, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_js result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: cb2b3139-17be-441a-beaa-850c1130ce80_js, 381bfe46-5daa-42c3-9e58-39d98058f186_js, ddd70737-9afe-474e-ae84-787830e88cbc_js, d6af2086-88f6-4f4f-9669-2d31e549a804_js, 95431be4-0dbc-4181-a196-d3b6afacb47d_js result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: faca3efe-63fa-40b1-960d-14241446e02b_js, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_js, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_js, 73a700b0-d223-4f5a-9336-863c67ef6a20_js, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_js result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: 8a59cde4-6473-44da-b170-f66c57b8df4a_js, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_js, 5d49d947-6006-4865-9c31-04b966b4ac61_js, 87e46975-6855-4644-97bf-f9c66bae1455_js, db0c6390-897f-4eb6-b734-977466b215b6_js result, different first party: 8a59cde4-6473-44da-b170-f66c57b8df4a_js, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_js, 5d49d947-6006-4865-9c31-04b966b4ac61_js, 87e46975-6855-4644-97bf-f9c66bae1455_js, db0c6390-897f-4eb6-b734-977466b215b6_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: 08871018-9567-44a6-b124-5cb6fb4797cf_js, ed296612-deee-4fff-b0e8-d7ee83e3b345_js, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_js, 4ee8618c-dd14-47c0-ad13-50e8f625e228_js, 929477f2-6d6b-4b18-a642-f2ca892f3876_js result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: 77f9d876-5d2d-4776-824f-839b4afa98da_js, 3959c542-32c6-4033-b316-37a1a8e480e0_js, bec75a88-52bd-463a-b926-f1694cdddcaf_js, 2239e757-c407-4798-907e-852d4ab1d41f_js result, different first party: , , , unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_js, e8f74dec-686f-4084-a15c-80172d70e290_js, c7af78eb-b2be-4edb-a01f-c5e80885c91b_js, bfa2edb1-7890-44d5-90e0-94ac0fef762a_js, 1e2332aa-e33b-49d1-b45e-4202d0db4096_js result, different first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_js, e8f74dec-686f-4084-a15c-80172d70e290_js, c7af78eb-b2be-4edb-a01f-c5e80885c91b_js, bfa2edb1-7890-44d5-90e0-94ac0fef762a_js, 1e2332aa-e33b-49d1-b45e-4202d0db4096_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same first party: df04981a-509a-43d2-bd50-07e15e2191a0_js, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_js, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_js, 975fde78-d933-4101-8f70-1fb2227ac766_js, 03b8d7d5-b189-4156-8310-62787b519fe2_js result, different first party: df04981a-509a-43d2-bd50-07e15e2191a0_js, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_js, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_js, 975fde78-d933-4101-8f70-1fb2227ac766_js, 03b8d7d5-b189-4156-8310-62787b519fe2_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
CookieStore
The Cookie Store API is an alternative asynchronous API for managing cookies, supported by some browsers. |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1, d77fced8-9428-496f-9946-549bc356d246, d806ff56-0f9b-4bbb-bb05-9fa67a08c877, 1256fd40-841d-47a2-8902-ce5636a32cb3, ce2b00b3-8519-499e-967c-ea73aad6dbb1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: 91872272-1110-44b8-bb8a-fefcdca4198f, be106815-df48-45c9-9d4a-86b9823a76db, 3d351c8a-a896-428b-bb2d-cb2f2838d223, aa902857-ae8c-4123-bd90-2f0901ab8e24, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d result, different first party: 91872272-1110-44b8-bb8a-fefcdca4198f, be106815-df48-45c9-9d4a-86b9823a76db, 3d351c8a-a896-428b-bb2d-cb2f2838d223, aa902857-ae8c-4123-bd90-2f0901ab8e24, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63, e52cd2ae-6e45-4906-900c-b02f787f4589, 7f3c6670-9f55-4ad6-b476-3acc68733c6a, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b, 32b124ca-4477-4984-b641-b772ba9d739c result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d, 4df32057-71ef-4c97-b4a9-375da39140da, 5a39645b-74e0-456f-a064-66a4075a8239, 00946081-6b17-4b36-9aa6-61d144addef7, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04 result, different first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d, 4df32057-71ef-4c97-b4a9-375da39140da, 5a39645b-74e0-456f-a064-66a4075a8239, 00946081-6b17-4b36-9aa6-61d144addef7, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: 8a59cde4-6473-44da-b170-f66c57b8df4a, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20, 5d49d947-6006-4865-9c31-04b966b4ac61, 87e46975-6855-4644-97bf-f9c66bae1455, db0c6390-897f-4eb6-b734-977466b215b6 result, different first party: 8a59cde4-6473-44da-b170-f66c57b8df4a, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20, 5d49d947-6006-4865-9c31-04b966b4ac61, 87e46975-6855-4644-97bf-f9c66bae1455, db0c6390-897f-4eb6-b734-977466b215b6 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: 08871018-9567-44a6-b124-5cb6fb4797cf, ed296612-deee-4fff-b0e8-d7ee83e3b345, f45c8b38-f782-4290-a7cc-7c031ed1bd5e, 4ee8618c-dd14-47c0-ad13-50e8f625e228, 929477f2-6d6b-4b18-a642-f2ca892f3876 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62, e8f74dec-686f-4084-a15c-80172d70e290, c7af78eb-b2be-4edb-a01f-c5e80885c91b, bfa2edb1-7890-44d5-90e0-94ac0fef762a, 1e2332aa-e33b-49d1-b45e-4202d0db4096 result, different first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62, e8f74dec-686f-4084-a15c-80172d70e290, c7af78eb-b2be-4edb-a01f-c5e80885c91b, bfa2edb1-7890-44d5-90e0-94ac0fef762a, 1e2332aa-e33b-49d1-b45e-4202d0db4096 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same first party: df04981a-509a-43d2-bd50-07e15e2191a0, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, 4a8ab582-40cd-40e7-b9b8-260ae2bee808, 975fde78-d933-4101-8f70-1fb2227ac766, 03b8d7d5-b189-4156-8310-62787b519fe2 result, different first party: df04981a-509a-43d2-bd50-07e15e2191a0, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, 4a8ab582-40cd-40e7-b9b8-260ae2bee808, 975fde78-d933-4101-8f70-1fb2227ac766, 03b8d7d5-b189-4156-8310-62787b519fe2 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
CSS cache
CSS stylesheets are cached, and if that cache is shared between websites, it can be used to track users across sites. |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_7697186818104083, fake_5656058101067518, fake_9330750975218289, fake_3448066787917248, fake_29643235128187384 result, different first party: fake_4733232657228854, fake_7274050501161957, fake_5891860192224931, fake_03137344346481541, fake_8757118976276959 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_8223918172984608, fake_6961051883757012, fake_4817494484277367, fake_00924553187186361, fake_16936849504556317 result, different first party: fake_43052126297765536, fake_5495221633539411, fake_9774353367251647, fake_875120003317033, fake_9476065706696337 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_2776296188569085, fake_08829232835932754, fake_4248701527702292, fake_6484659134520363, fake_10084918578388113 result, different first party: fake_8925674651239459, fake_22854359163717808, fake_42920492460275517, fake_8931224765068526, fake_3612896050764274 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_5071911123984754, fake_38659675360378065, fake_6724194957405134, fake_22430499842888607, fake_9313747845955542 result, different first party: fake_5071911123984754, fake_38659675360378065, fake_6724194957405134, fake_22430499842888607, fake_9313747845955542 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_7036487074281428, fake_6692645708513834, fake_3547776035728525, fake_978046266668519, fake_2241636696651954 result, different first party: fake_5999913087770563, fake_8197414120828332, fake_4486643540238917, fake_9280455872959283, fake_1388324854368128 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_4255293295499436, fake_04298219847625662, fake_0917725814634458, fake_21764634134182304, fake_6681637171614316 result, different first party: fake_8384589308264461, fake_15612704835387836, fake_1650256466743112, fake_13168468268845812, fake_5867652489341018 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_7795397213654498, fake_2406674160795128, fake_3826048809932068, fake_3063626539193527, fake_20715064341734402 result, different first party: fake_08983077311542997, fake_4384453814281706, fake_2597117085358285, fake_15404796050994385, fake_3110121308325269 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_045797775739927715, fake_6929473009401472, fake_9469435786752591, fake_08382493549748848, fake_29569421678973873 result, different first party: fake_07948236372916817, fake_3070721203414257, fake_3225249734849567, fake_8056131570930316, fake_495576192378113 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_46030426669554325, fake_9624682544121579, fake_6227321295165855, fake_8192979542662038, fake_4475971702760262 result, different first party: fake_9044060761046047, fake_7387016923021141, fake_9548172573964566, fake_8676371758514052, fake_9279896261204816 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_1337683501010316, fake_05399821173601871, fake_9665510112138791, fake_09133862220506028, fake_970605790744347 result, different first party: fake_42100929860538794, fake_4248390532334867, fake_5705966672122873, fake_8523086278385283, fake_9111417494298073 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_6126108733090334, fake_9449416519134897, fake_07912256841264553, fake_9431661239716711 result, different first party: fake_4561110813028306, fake_8421917520204607, fake_3924585986024123, fake_46255065923849137 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_2709554897366162, fake_8050687339804645, fake_5555349560798422, fake_054554076581780686, fake_09398914604748954 result, different first party: fake_954146687382434, fake_034531473259038936, fake_42172154566591713, fake_8755231239251995, fake_7192126077311363 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same first party: fake_6787493625221996, fake_8455568531894664, fake_5652889306862139, fake_5965755559337151, fake_4091933046979255 result, different first party: fake_5016116281201, fake_2997545878238097, fake_7229650511643282, fake_9605523005047021, fake_9991444326241246 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
favicon cache
A favicon is an icon that represents a website, typically shown in browser tab and bookmarks menu. If the favicon cache is not partitioned, it can be used to track users across websites. |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different first party: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different first party: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1 result, different first party: 1, 1, 1, 1 unsupported: false, false, false, false passed: false, false, false, false test failed: false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
fetch cache
When a resource is received via the Fetch API, it is frequently cached. That cache can potentially be abused for cross-site tracking. |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1 result, different first party: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
font cache
Web fonts are sometimes stored in their own cache, which is vulnerable to being abused for cross-site tracking. |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1 result, different first party: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
getDirectory
navigator.storage.getDirectory exposes a location for storing files to web content. In some cases, these files may be shared across tabs. |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1, d77fced8-9428-496f-9946-549bc356d246, d806ff56-0f9b-4bbb-bb05-9fa67a08c877, 1256fd40-841d-47a2-8902-ce5636a32cb3, ce2b00b3-8519-499e-967c-ea73aad6dbb1 result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: 91872272-1110-44b8-bb8a-fefcdca4198f, be106815-df48-45c9-9d4a-86b9823a76db, 3d351c8a-a896-428b-bb2d-cb2f2838d223, aa902857-ae8c-4123-bd90-2f0901ab8e24, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63, e52cd2ae-6e45-4906-900c-b02f787f4589, 7f3c6670-9f55-4ad6-b476-3acc68733c6a, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b, 32b124ca-4477-4984-b641-b772ba9d739c result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb result, different first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d, 4df32057-71ef-4c97-b4a9-375da39140da, 5a39645b-74e0-456f-a064-66a4075a8239, 00946081-6b17-4b36-9aa6-61d144addef7, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04 result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: a6911260-affb-4f85-b66e-6372edef8271, f3f642e9-a578-4fd7-b323-71de0e1e5fda, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1 result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: faca3efe-63fa-40b1-960d-14241446e02b, 2a2e037d-1d56-4d32-8402-d4b28afa8eac, 0eb26e1b-7201-4d84-aea1-8943179ccfc1, 73a700b0-d223-4f5a-9336-863c67ef6a20, 2a6798d9-a24d-470e-8d91-53d5e7f0d445 result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: 8a59cde4-6473-44da-b170-f66c57b8df4a, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20, 5d49d947-6006-4865-9c31-04b966b4ac61, 87e46975-6855-4644-97bf-f9c66bae1455, db0c6390-897f-4eb6-b734-977466b215b6 result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: 08871018-9567-44a6-b124-5cb6fb4797cf, ed296612-deee-4fff-b0e8-d7ee83e3b345, f45c8b38-f782-4290-a7cc-7c031ed1bd5e, 4ee8618c-dd14-47c0-ad13-50e8f625e228, 929477f2-6d6b-4b18-a642-f2ca892f3876 result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62, e8f74dec-686f-4084-a15c-80172d70e290, c7af78eb-b2be-4edb-a01f-c5e80885c91b, bfa2edb1-7890-44d5-90e0-94ac0fef762a, 1e2332aa-e33b-49d1-b45e-4202d0db4096 result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt", { create: true }); const stream = await fileHandle.createWritable(); await stream.write(secret); await stream.close(); } catch (e) { throw new Error("Unsupported"); } } read: async () => { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle("secret.txt"); const file = await fileHandle.getFile(); return file.text(); } catch (e) { throw new Error("Unsupported"); } } result, same first party: df04981a-509a-43d2-bd50-07e15e2191a0, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, 4a8ab582-40cd-40e7-b9b8-260ae2bee808, 975fde78-d933-4101-8f70-1fb2227ac766, 03b8d7d5-b189-4156-8310-62787b519fe2 result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
H1 connection
HTTP/1.x are the classic web connection protocols. If these connections are re-used across websites, they can be used to track users. |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1, d77fced8-9428-496f-9946-549bc356d246, d806ff56-0f9b-4bbb-bb05-9fa67a08c877, 1256fd40-841d-47a2-8902-ce5636a32cb3, ce2b00b3-8519-499e-967c-ea73aad6dbb1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 91872272-1110-44b8-bb8a-fefcdca4198f, be106815-df48-45c9-9d4a-86b9823a76db, 3d351c8a-a896-428b-bb2d-cb2f2838d223, aa902857-ae8c-4123-bd90-2f0901ab8e24, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63, e52cd2ae-6e45-4906-900c-b02f787f4589, 7f3c6670-9f55-4ad6-b476-3acc68733c6a, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b, 32b124ca-4477-4984-b641-b772ba9d739c result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb result, different first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d, 4df32057-71ef-4c97-b4a9-375da39140da, 5a39645b-74e0-456f-a064-66a4075a8239, 00946081-6b17-4b36-9aa6-61d144addef7, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: a6911260-affb-4f85-b66e-6372edef8271, f3f642e9-a578-4fd7-b323-71de0e1e5fda, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: cb2b3139-17be-441a-beaa-850c1130ce80, 381bfe46-5daa-42c3-9e58-39d98058f186, ddd70737-9afe-474e-ae84-787830e88cbc, d6af2086-88f6-4f4f-9669-2d31e549a804, 95431be4-0dbc-4181-a196-d3b6afacb47d result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: faca3efe-63fa-40b1-960d-14241446e02b, 2a2e037d-1d56-4d32-8402-d4b28afa8eac, 0eb26e1b-7201-4d84-aea1-8943179ccfc1, 73a700b0-d223-4f5a-9336-863c67ef6a20, 2a6798d9-a24d-470e-8d91-53d5e7f0d445 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 8a59cde4-6473-44da-b170-f66c57b8df4a, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20, 5d49d947-6006-4865-9c31-04b966b4ac61, 87e46975-6855-4644-97bf-f9c66bae1455, db0c6390-897f-4eb6-b734-977466b215b6 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 08871018-9567-44a6-b124-5cb6fb4797cf, ed296612-deee-4fff-b0e8-d7ee83e3b345, f45c8b38-f782-4290-a7cc-7c031ed1bd5e, 4ee8618c-dd14-47c0-ad13-50e8f625e228, 929477f2-6d6b-4b18-a642-f2ca892f3876 result, different first party: 08871018-9567-44a6-b124-5cb6fb4797cf, ed296612-deee-4fff-b0e8-d7ee83e3b345, f45c8b38-f782-4290-a7cc-7c031ed1bd5e, 4ee8618c-dd14-47c0-ad13-50e8f625e228, 929477f2-6d6b-4b18-a642-f2ca892f3876 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 77f9d876-5d2d-4776-824f-839b4afa98da, 3959c542-32c6-4033-b316-37a1a8e480e0, bec75a88-52bd-463a-b926-f1694cdddcaf, 2239e757-c407-4798-907e-852d4ab1d41f result, different first party: , , , unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62, e8f74dec-686f-4084-a15c-80172d70e290, c7af78eb-b2be-4edb-a01f-c5e80885c91b, bfa2edb1-7890-44d5-90e0-94ac0fef762a, 1e2332aa-e33b-49d1-b45e-4202d0db4096 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h1.privacytests2.org:8901/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h1.privacytests2.org:8901/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: df04981a-509a-43d2-bd50-07e15e2191a0, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, 4a8ab582-40cd-40e7-b9b8-260ae2bee808, 975fde78-d933-4101-8f70-1fb2227ac766, 03b8d7d5-b189-4156-8310-62787b519fe2 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
H2 connection
HTTP/2 is a web connection protocol introduced in 2015. Some browsers re-use HTTP/2 connections across websites and can thus be used to track users. |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1, d77fced8-9428-496f-9946-549bc356d246, d806ff56-0f9b-4bbb-bb05-9fa67a08c877, 1256fd40-841d-47a2-8902-ce5636a32cb3, ce2b00b3-8519-499e-967c-ea73aad6dbb1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 91872272-1110-44b8-bb8a-fefcdca4198f, be106815-df48-45c9-9d4a-86b9823a76db, 3d351c8a-a896-428b-bb2d-cb2f2838d223, aa902857-ae8c-4123-bd90-2f0901ab8e24, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63, e52cd2ae-6e45-4906-900c-b02f787f4589, 7f3c6670-9f55-4ad6-b476-3acc68733c6a, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b, 32b124ca-4477-4984-b641-b772ba9d739c result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb result, different first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d, 4df32057-71ef-4c97-b4a9-375da39140da, 5a39645b-74e0-456f-a064-66a4075a8239, 00946081-6b17-4b36-9aa6-61d144addef7, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: a6911260-affb-4f85-b66e-6372edef8271, f3f642e9-a578-4fd7-b323-71de0e1e5fda, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: cb2b3139-17be-441a-beaa-850c1130ce80, 381bfe46-5daa-42c3-9e58-39d98058f186, ddd70737-9afe-474e-ae84-787830e88cbc, d6af2086-88f6-4f4f-9669-2d31e549a804, 95431be4-0dbc-4181-a196-d3b6afacb47d result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: faca3efe-63fa-40b1-960d-14241446e02b, 2a2e037d-1d56-4d32-8402-d4b28afa8eac, 0eb26e1b-7201-4d84-aea1-8943179ccfc1, 73a700b0-d223-4f5a-9336-863c67ef6a20, 2a6798d9-a24d-470e-8d91-53d5e7f0d445 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 8a59cde4-6473-44da-b170-f66c57b8df4a, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20, 5d49d947-6006-4865-9c31-04b966b4ac61, 87e46975-6855-4644-97bf-f9c66bae1455, db0c6390-897f-4eb6-b734-977466b215b6 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 08871018-9567-44a6-b124-5cb6fb4797cf, ed296612-deee-4fff-b0e8-d7ee83e3b345, f45c8b38-f782-4290-a7cc-7c031ed1bd5e, 4ee8618c-dd14-47c0-ad13-50e8f625e228, 929477f2-6d6b-4b18-a642-f2ca892f3876 result, different first party: 08871018-9567-44a6-b124-5cb6fb4797cf, ed296612-deee-4fff-b0e8-d7ee83e3b345, f45c8b38-f782-4290-a7cc-7c031ed1bd5e, 4ee8618c-dd14-47c0-ad13-50e8f625e228, 929477f2-6d6b-4b18-a642-f2ca892f3876 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 77f9d876-5d2d-4776-824f-839b4afa98da, 3959c542-32c6-4033-b316-37a1a8e480e0, bec75a88-52bd-463a-b926-f1694cdddcaf, 2239e757-c407-4798-907e-852d4ab1d41f result, different first party: , , , unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62, e8f74dec-686f-4084-a15c-80172d70e290, c7af78eb-b2be-4edb-a01f-c5e80885c91b, bfa2edb1-7890-44d5-90e0-94ac0fef762a, 1e2332aa-e33b-49d1-b45e-4202d0db4096 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { await fetch(`https://h2.privacytests2.org:8902/?mode=write&secret=${secret}`, {cache: "no-store"}); } read: async () => { let response = await fetch(`https://h2.privacytests2.org:8902/?mode=read`, {cache: "no-store"}); return await response.text(); } result, same first party: df04981a-509a-43d2-bd50-07e15e2191a0, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, 4a8ab582-40cd-40e7-b9b8-260ae2bee808, 975fde78-d933-4101-8f70-1fb2227ac766, 03b8d7d5-b189-4156-8310-62787b519fe2 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
H3 connection
HTTP/3 is a new standard HTTP connection protocol, still in draft but widely supported by browsers. If it is not partitioned, it can be used to track users across websites. |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: b117156bc9e539ddf6b363d5463371e0, f914bf0a8563df7c53c851c36ecd28d1, 78d9d739cc8160cecdf4d35e851eaf92, 9cd692ad2c3a4d558fda01a18a14b404, 4a08dd44947a36d600865a46706a81c3 result, different first party: , e90b7e8c9ecc03d9c6bc7b14f8b75f33, fe6c36c05d5443450d1a9b23dce908e5, 3e9b500e22de2059e7e591187b2bb3f6, fa6d60a13ca9ba57f19d70a33f7ac1a3 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: 90f68a1fa45f20fa7aacc205307ff27f, f9662b5b4ca9511ec7c9505a9f4f974b, 7e64972a2825bb53eb6e7588454e5091, 3694050f67496b6732369f40645d1378, abc1a48cb48e4cdf7b8787f14fdc8d4c result, different first party: , 63361c1fd007059bba113852d9aee14e, c106d57f9387a72b6a10754c76e1bc3f, 4bcb9d8f3f133053e0ccb8c709957999, 3f68f46f67199544ff405e59f8fb7ac6 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: 15e49724650efd8ca9662d2b34771987, 259f010aaf390a8399ff791f5d34c523, ec3d4c1e3a987549057a5cd06ff86b2c, cb63e7ca1e7ae220d4f6ab190e583d22, 140276df879e1bfe96c83f0e1e5d8210 result, different first party: 15e49724650efd8ca9662d2b34771987, 259f010aaf390a8399ff791f5d34c523, ec3d4c1e3a987549057a5cd06ff86b2c, cb63e7ca1e7ae220d4f6ab190e583d22, 140276df879e1bfe96c83f0e1e5d8210 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: 8eb0cd741458860f56db6b8b98484b2e, 37f4e622027da8c3d870e387fda36b61, 4f52c3aa636ab3c5fbe1f8b82dedf067, ffbf979856ae399537956f1684372827, 12ed94ec9ebeadd406a26a85722ff517 result, different first party: , c56f3633724632e0411e2b816d7e5b40, 74aa9fa86f996df6352dac514fa8c007, 94ffda7d20474781a6cf2128733fc828, 3d50a6af2b1875f598f8100bb75e90e8 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: 53dadf92c41e5ebb8744cf375f3b47cc, 6d06b92cf6a36f34564bfa5ef33ce631, f13805afa355031b13fb3d38790618f9, d0e9ca7e2917ea13be44baeeaa95206f, 18572d8e45276083a638a1e93fc09298 result, different first party: , 7734d89ea3b7e90945c744e1545d1956, 975e407d091af36c2b0b0fc318d01eb3, 68c3b07b3ffc6cdde1b1b047db8f191f, 26ac95f1362097872b29cbcb0f4e0905 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: 3efcf52ede3b436968b5705877b2c156, 84adf41107799dec112752f6d3b5cee0, 97294f703ce45b4d82ffa8cb5d79b19e, d3beb64062d5a9658e628b93494e3966, a358c2ad088b6a06d31fda4f2e87cb0b result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: 70c32ba66705ae55cbc8c013ef6bf5c6, d5570893395da8418403efa482d16316, 882addd844da9df88b4a4deb5fb22b7e, c0485b48f02717b1da12342cb8010c8f, 8cc09ef9db2d9da7b6dc5de5c296d05d result, different first party: , 5f27b68c2baa3a9745a4b8bb12899264, e3206ab3a002d9568893a4417b74c429, 3c4186bcc065d841121807677cf1b3d5, 1bd01fcc81707a6dd060b0c291a91043 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: 3e3fe1ca4fe85cad6e6f75bab4502dfb, 109ed80ee32bfc4b760dd39be7ed311a, 736b38ba482f7c0849e9387f10eaa869, bee95024342e9214c764b5ad926877cf, ed9154ab0838afaf847131d5517c98b2 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: , , , result, different first party: , , , unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: df7960ec34758e58971d5fb2b4fa331c, dc2adfb40982b3152c7a16b14d8585da, f905d6ce0e065d4fde0786d80cd362ff, 569ca14693ad1ad6998021a74143cce4, 475606bdcb332ec1504cac4e3ed23b80 result, different first party: , 81efc1d2f6e696af7e43c121ccce2037, fd1106d4a4acc544db693583d6571df9, da52ca64dd3f385ac00df2619c27ef78, 1d8bf9ef633f4f3c054330305959d066 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Ensure that we can switch over to h3 via alt-svc: for (let i = 0; i<3; ++i) { await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); await sleepMs(500); } // Are we now connecting over h3? let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`, {cache: "no-store"}); let text = await response.text(); // Empty response text indicates we are not connecting over h3: if (text.trim() === "") { throw new Error("Unsupported"); } } read: async () => { let response = await fetch(`https://h3.privacytests2.org:4434/connection_id`); return await response.text(); } result, same first party: e64f0abaa94dd0b098a6b822d4fbc39b, c51247cd97141660a42d48e7494e83f3, 819b467812b84aea5570f1e4b68240cd, 84b901ba8c7bc3c23d9cf29f848a223e, 638777782740372ec5fcb0b534f54e09 result, different first party: , 1d5e7e334f68889a1a8222f9ea890c69, f13840216413daa31ce6283209b8cf78, 47c78bc57bde51851fca5034fa5cc24e, 67eb487f3dd7c0e865304870d4cd2d7f unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
HSTS cache
The HTTP Strict-Transport-Security response header allows a website to signal that it should only be accessed via HTTPS. The browser remembers this directive in a database, but if this database is not partitioned, then it can be used to track users across websites." |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Used http, Used http, Used http, Used http, Used http unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Used http, Used http, Used http, Used http, Used http unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Used http, Used http, Used http, Used http, Used http unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: null read: null result, same first party: , , , , result, different first party: HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected unsupported: , , , , passed: true, true, true, true, true test failed: false, false, false, false, false |
write: null read: null result, same first party: , , , , result, different first party: HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected unsupported: , , , , passed: true, true, true, true, true test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: null read: null result, same first party: , , , result, different first party: HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected unsupported: , , , passed: true, true, true, true test failed: false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
HSTS cache (fetch)
The HTTP Strict-Transport-Security response header allows a website to signal that it should only be accessed via HTTPS. The browser remembers this directive in a database, but if this database is not partitioned, then it can be used to track users across websites." |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Used http, Used http, Used http, Used http, Used http unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Used http, Used http, Used http, Used http, Used http unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Used http, Used http, Used http, Used http, Used http unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: null read: null result, same first party: , , , , result, different first party: HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected unsupported: , , , , passed: true, true, true, true, true test failed: false, false, false, false, false |
write: null read: null result, same first party: , , , , result, different first party: HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected unsupported: , , , , passed: true, true, true, true, true test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: null read: null result, same first party: , , , result, different first party: HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected, HTTPS used by default; no HSTS cache issue expected unsupported: , , , passed: true, true, true, true test failed: false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: set HSTS flag read: read HSTS flag result, same first party: not tested, not tested, not tested, not tested, not tested result, different first party: Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https, Upgraded to https unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
iframe cache
An iframe is an element in a web page than allows websites to embed a second web page. Caching of this web page could be abused for cross-site tracking. |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1 result, different first party: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
image cache
Caching of images in web browsers is a standard behavior. But if that cache leaks between websites, it can be abused for cross-site tracking. |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1 result, different first party: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
indexedDB
The IndexedDB API exposes a transactional database to web pages. That database can be used to track users across websites, unless it is partitioned. |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1, d77fced8-9428-496f-9946-549bc356d246, d806ff56-0f9b-4bbb-bb05-9fa67a08c877, 1256fd40-841d-47a2-8902-ce5636a32cb3, ce2b00b3-8519-499e-967c-ea73aad6dbb1 result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: 91872272-1110-44b8-bb8a-fefcdca4198f, be106815-df48-45c9-9d4a-86b9823a76db, 3d351c8a-a896-428b-bb2d-cb2f2838d223, aa902857-ae8c-4123-bd90-2f0901ab8e24, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63, e52cd2ae-6e45-4906-900c-b02f787f4589, 7f3c6670-9f55-4ad6-b476-3acc68733c6a, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b, 32b124ca-4477-4984-b641-b772ba9d739c result, different first party: Error: The user denied permission to access the database., Error: The user denied permission to access the database., Error: The user denied permission to access the database., Error: The user denied permission to access the database., Error: The user denied permission to access the database. unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb result, different first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d, 4df32057-71ef-4c97-b4a9-375da39140da, 5a39645b-74e0-456f-a064-66a4075a8239, 00946081-6b17-4b36-9aa6-61d144addef7, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04 result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: a6911260-affb-4f85-b66e-6372edef8271, f3f642e9-a578-4fd7-b323-71de0e1e5fda, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1 result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: cb2b3139-17be-441a-beaa-850c1130ce80, 381bfe46-5daa-42c3-9e58-39d98058f186, ddd70737-9afe-474e-ae84-787830e88cbc, d6af2086-88f6-4f4f-9669-2d31e549a804, 95431be4-0dbc-4181-a196-d3b6afacb47d result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: faca3efe-63fa-40b1-960d-14241446e02b, 2a2e037d-1d56-4d32-8402-d4b28afa8eac, 0eb26e1b-7201-4d84-aea1-8943179ccfc1, 73a700b0-d223-4f5a-9336-863c67ef6a20, 2a6798d9-a24d-470e-8d91-53d5e7f0d445 result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: 8a59cde4-6473-44da-b170-f66c57b8df4a, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20, 5d49d947-6006-4865-9c31-04b966b4ac61, 87e46975-6855-4644-97bf-f9c66bae1455, db0c6390-897f-4eb6-b734-977466b215b6 result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: 08871018-9567-44a6-b124-5cb6fb4797cf, ed296612-deee-4fff-b0e8-d7ee83e3b345, f45c8b38-f782-4290-a7cc-7c031ed1bd5e, 4ee8618c-dd14-47c0-ad13-50e8f625e228, 929477f2-6d6b-4b18-a642-f2ca892f3876 result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: 77f9d876-5d2d-4776-824f-839b4afa98da, 3959c542-32c6-4033-b316-37a1a8e480e0, bec75a88-52bd-463a-b926-f1694cdddcaf, 2239e757-c407-4798-907e-852d4ab1d41f result, different first party: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62, e8f74dec-686f-4084-a15c-80172d70e290, c7af78eb-b2be-4edb-a01f-c5e80885c91b, bfa2edb1-7890-44d5-90e0-94ac0fef762a, 1e2332aa-e33b-49d1-b45e-4202d0db4096 result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same first party: df04981a-509a-43d2-bd50-07e15e2191a0, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, 4a8ab582-40cd-40e7-b9b8-260ae2bee808, 975fde78-d933-4101-8f70-1fb2227ac766, 03b8d7d5-b189-4156-8310-62787b519fe2 result, different first party: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
localStorage
The localStorage API gives websites access to a key-value database that will remain available across visits. If the localStorage API is not partitioned or blocked, it can also be used to track users across websites. |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1, d77fced8-9428-496f-9946-549bc356d246, d806ff56-0f9b-4bbb-bb05-9fa67a08c877, 1256fd40-841d-47a2-8902-ce5636a32cb3, ce2b00b3-8519-499e-967c-ea73aad6dbb1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: 91872272-1110-44b8-bb8a-fefcdca4198f, be106815-df48-45c9-9d4a-86b9823a76db, 3d351c8a-a896-428b-bb2d-cb2f2838d223, aa902857-ae8c-4123-bd90-2f0901ab8e24, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63, e52cd2ae-6e45-4906-900c-b02f787f4589, 7f3c6670-9f55-4ad6-b476-3acc68733c6a, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b, 32b124ca-4477-4984-b641-b772ba9d739c result, different first party: Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document. unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb result, different first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d, 4df32057-71ef-4c97-b4a9-375da39140da, 5a39645b-74e0-456f-a064-66a4075a8239, 00946081-6b17-4b36-9aa6-61d144addef7, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: a6911260-affb-4f85-b66e-6372edef8271, f3f642e9-a578-4fd7-b323-71de0e1e5fda, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: cb2b3139-17be-441a-beaa-850c1130ce80, 381bfe46-5daa-42c3-9e58-39d98058f186, ddd70737-9afe-474e-ae84-787830e88cbc, d6af2086-88f6-4f4f-9669-2d31e549a804, 95431be4-0dbc-4181-a196-d3b6afacb47d result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: faca3efe-63fa-40b1-960d-14241446e02b, 2a2e037d-1d56-4d32-8402-d4b28afa8eac, 0eb26e1b-7201-4d84-aea1-8943179ccfc1, 73a700b0-d223-4f5a-9336-863c67ef6a20, 2a6798d9-a24d-470e-8d91-53d5e7f0d445 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: 8a59cde4-6473-44da-b170-f66c57b8df4a, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20, 5d49d947-6006-4865-9c31-04b966b4ac61, 87e46975-6855-4644-97bf-f9c66bae1455, db0c6390-897f-4eb6-b734-977466b215b6 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: 08871018-9567-44a6-b124-5cb6fb4797cf, ed296612-deee-4fff-b0e8-d7ee83e3b345, f45c8b38-f782-4290-a7cc-7c031ed1bd5e, 4ee8618c-dd14-47c0-ad13-50e8f625e228, 929477f2-6d6b-4b18-a642-f2ca892f3876 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: 77f9d876-5d2d-4776-824f-839b4afa98da, 3959c542-32c6-4033-b316-37a1a8e480e0, bec75a88-52bd-463a-b926-f1694cdddcaf, 2239e757-c407-4798-907e-852d4ab1d41f result, different first party: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62, e8f74dec-686f-4084-a15c-80172d70e290, c7af78eb-b2be-4edb-a01f-c5e80885c91b, bfa2edb1-7890-44d5-90e0-94ac0fef762a, 1e2332aa-e33b-49d1-b45e-4202d0db4096 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same first party: df04981a-509a-43d2-bd50-07e15e2191a0, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, 4a8ab582-40cd-40e7-b9b8-260ae2bee808, 975fde78-d933-4101-8f70-1fb2227ac766, 03b8d7d5-b189-4156-8310-62787b519fe2 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
locks
navigator.locks (only supported in some browsers) allows scripts on multiple tabs to coordinate. If this API is not partitioned, it can be used for cross-site tracking. |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') result, different first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') result, different first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') result, different first party: Error: The request was denied., Error: The request was denied., Error: The request was denied., Error: The request was denied., Error: The request was denied. unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') result, different first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') result, different first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined result, different first party: Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined result, different first party: Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined result, different first party: Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') result, different first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') result, different first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined, Error: queryResult.held[0] is undefined result, different first party: Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context, Error: LockManager.query: query() is not allowed in this context unsupported: false, false, false, false passed: undefined test failed: true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') result, different first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (navigator.locks) { navigator.locks.request(key, lock => new Promise((f,r) => {})); let queryResult = await navigator.locks.query(); return queryResult.held[0].clientId; } else { throw new Error("Unsupported"); } } read: async () => { if (navigator.locks) { let queryResult = await navigator.locks.query(); return queryResult.held[0].name; } } result, same first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') result, different first party: Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name'), Error: Cannot read properties of undefined (reading 'name') unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
prefetch cache
A <link rel='prefetch'...> suggests to browsers they should fetch a resource ahead of time and cache it. But if browsers don't partition this cache, it can be used to track users across websites. |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different first party: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different first party: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
script cache
Caching of scripts in web browsers is a standard behavior. But if that cache leaks between websites, it can be abused for cross-site tracking. |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1 result, different first party: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
ServiceWorker
The ServiceWorker API allows websites to run code in the background and store content in the browser for offline use. If a ServiceWorker can be accessed from multiple websites, it can be abused to track users across sites. |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: Error: Failed to register a ServiceWorker for scope ('https://test-pages.privacytests2.org/') with script ('https://test-pages.privacytests2.org/serviceWorker.js'): The user denied permission to use Service Worker., Error: Failed to register a ServiceWorker for scope ('https://test-pages.privacytests2.org/') with script ('https://test-pages.privacytests2.org/serviceWorker.js'): The user denied permission to use Service Worker., Error: Failed to register a ServiceWorker for scope ('https://test-pages.privacytests2.org/') with script ('https://test-pages.privacytests2.org/serviceWorker.js'): The user denied permission to use Service Worker., Error: Failed to register a ServiceWorker for scope ('https://test-pages.privacytests2.org/') with script ('https://test-pages.privacytests2.org/serviceWorker.js'): The user denied permission to use Service Worker., Error: Failed to register a ServiceWorker for scope ('https://test-pages.privacytests2.org/') with script ('https://test-pages.privacytests2.org/serviceWorker.js'): The user denied permission to use Service Worker. unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined result, different first party: Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined result, different first party: Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined, Error: navigator.serviceWorker is undefined unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
write: async (key) => { if (!navigator.serviceWorker) { throw new Error("Unsupported"); } let registration = await navigator.serviceWorker.register( 'serviceWorker.js'); console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); await fetch(`serviceworker-write?secret=${key}`); } read: async () => { console.log("trying to register the serviceworker now..."); const registration = await Promise.race([ navigator.serviceWorker.register('serviceWorker.js'), sleepMs(500) ]); if (registration === undefined) { // We timed out or otherwise failed. throw new Error("ServiceWorker registration failed"); } console.log(registration); await navigator.serviceWorker.ready; console.log("service worker ready"); await sleepMs(100); let response = await fetch("serviceworker-read"); return await response.text(); } result, same first party: , , , , result, different first party: , , , , unsupported: false, false, false, false, false passed: undefined test failed: true, true, true, true, true |
SharedWorker
The SharedWorker API allows scripts from multiple tabs to share a background thread of computation. If SharedWorker is not partitioned, then it can be abused to shared data between websites in your browser. |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined result, different first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined result, different first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined result, different first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined result, different first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined result, different first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different first party: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined result, different first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined result, different first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: no SharedWorker message received, Error: no SharedWorker message received, Error: no SharedWorker message received, Error: no SharedWorker message received result, different first party: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. unsupported: false, false, false, false passed: undefined test failed: true, true, true, true |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined result, different first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); // console.log("worker", worker); const messagePromise = new Promise((resolve) => { worker.port.onmessage = (e) => resolve(e.data); }); worker.port.postMessage(secret); await messagePromise; } catch (e) { throw new Error("Unsupported"); } } read: async () => { let worker = new SharedWorker("supercookies_sharedworker.js"); worker.port.start(); const messagePromise = new Promise((resolve, reject) => { worker.port.onmessage = (e) => resolve(e.data); setTimeout(() => reject(new Error("no SharedWorker message received")), 200); }); worker.port.postMessage("request"); const message = await messagePromise; if (message === "none") { throw new Error("Unsupported"); } return message; } result, same first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined result, different first party: Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined, Error: SharedWorker is not defined unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
TLS Session ID
The TLS protocol is used by HTTPS to make connections secure. If the browser were to re-use a TLS session, then the session ID could be used to track users across websites. |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: 4ba7a1d5d2b70594a1369314e0d520a0979b56feb9f65992c882a721f14f64b6, 8e7598db825d20cf4668ff82879e64934c5eb6e8054ee9914e7a23586d302e09, bc409f1c3cee6aed8b12e7dcb8e0fc96d5d95405d061ccbe187a31fa3f88fee2, b885ad49ce83f1b14af85823d21476ea80687d303cc474abf7a3938756dc5e71, d5652e02677346c84357e9689d7a315bc0a1290115cd15fef027d3058de634f2 result, different first party: 151e3e341d567672069311445e4d5b54999054ff4734662fbf9bfd5fc66402e8, c6c4425a3a05ed23b090d3895d071d37befa71de8436d820676eee09514524de, 0f8b8048897bfdeeca7eb6ea4406df16341fd4a5f3cda1cd364b7c223b498192, 782171c96409f199c45e2c9a01e053c35abee60d91333f7305c6d740b0cd3e5d, 8e6a55bc2160e8b2e5e0b0b90db91e527fa18fb4dcf041a545384b0d23ecbed7 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: 2e2d19631f0f938fb26b80408c4a2e23d06933621f4445c44d7383f87f351440, 138743eeb3a500d65a73b4708c0ca08a19de789ee00dbf63c5a130b02b2b3221, a92556df31b4588692e4fc88f305493ab0d343e1c4d596e56b31203fa13866fe, f641b2171c097ac36f9d09fcc555ce122a651fea417b4f995cc4e0e3d02f1b05, 42a1d852662c0753e0cb62152641ae651e47ea03a2c194b8921becd999e8809f result, different first party: d5e75065f3f4855a9fca6a204cfc4097b8a6e1412fc0cbb090063673c5cccd07, 012b2ae2a184c032ea5f4e2b1e42830b3e7d984ceccac5dbb2c5c33285d54ef3, 7e023275fee872e343cca6818bdeee13de3651fd22ba841b285264dfdead27ec, 96e601ae020e3552f1e8f2a36e1e109085e82192190f6c90448ce85133d3532a, 3c70b5224537939e07602194b5008f9494478344a85f5e526314ba4097b95422 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: dd52153dfb39b7cf0e771b35868258996bff565375d22933c928232b484e76df, 5b77b5e6d32304b5aaedf4fbe21d702c8680a19d8560c3403386c35dd089be3c, 8ec1abc0cb194d93274ffcfbf4e3117f9856133e596f9cc0f0d6ca8b400420f0, 1a0ac884e3f249a70800690b5810ce5d8a24a935dc4bc0d34449b21550158f05, 0fc95603d2dbf923cc0029d56646e69ab039fbb6fd6c21aa14d5e26b8c7204f0 result, different first party: e9197dafd885a911d1038e3240f9cd6a4cb6042a3701a28a022a44a9d748368c, 6583fb5dee94071b188da3043604e9215fa4f77472539d5f53fd34bbdedc5452, 8e62901575508731e02686ac85cf06dd942594607b4a68eade226f278c0c73b2, 5640637b58c2ce286a23fe697750abe74b2038c5978bf0da2edf2defecabf5fb, e14ec064749372af13202f58184aa4e1da8f76c7fc52804627d29260d458c2f7 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: e00a3043c18cf86f7a8e33ff548931cc3d74895185c1bbe7476b00842918d202, 404926f4471863c13d658556cb212350561a2ab3e2154fc1e7f155cfc44a5e2a, ad0dd7704bcf167f0644d6a540dcc75959f895cac413138b850abc02e6a7249a, 0f06ceeedc60fbf6b6382701e73c58f747214cdb3be33076f3a46c9fba05453d, 37dc2a20d9839b42c5adbdb09a71183d446baa8705aebf4b6475683d585a19d4 result, different first party: 4abee895ee0b4da7bd00427298bbd76198b4c4651c5bf728254f70b3201b158b, 11095eb5fa6793b7d2cf86072cc26253b6cf4a1675195c76e06d96a1946ef6f8, 31b85fa9370aa5c96f09a0f635335ea83af191da5411271e057f89aa6782df41, ab2bb7b155e42c2e53b4603f70f7797b3b1b55718e0c7a258d17490b143be0e3, 53f068cec2acb616bacf7b390907f442f5ec08adbfd59c1730bf7e719609689f unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: b4e514910497f860b6d917f809d2a8a404082bf6b402527d3f87cd64db84e0b8, 71db972e6ca12f9d520eea64fe600a7ac8e48e45afcb8242f760e8ea9999cd83, 3519f9236431cf3ca5b07a468d35eb30efc1c26cde8cbdf7b910ee0fb48446d3, 0de0e344316be2cb03d9872c20438aae7781b22ca751d1e7e60c3dbdaf7093b7, 685e291b12c2fbb51d50e79da973460119ed772bfb67a1755a9f28185016c21f result, different first party: a49daa1ce948259c5f86c998d7338e97ff6880e07f6b1f04469d1620a67c395c, bd5613b592e0ae3686bb8fc0e25043aee762e12a3c68066a0424b570201a1e39, 063a41fed355f640c2a3f04486c4f879af86eb2a501248674594b4c5f8e53064, 9a4b8d0851e005e0ac549ef36d53a96c417844731518dfc0184c703126abeb22, ffd9a89fe3b78865a97765f33b044a730c0a1885c8caac06241448fffb889750 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: e9f70e0f7d7d381ac2b6965c86b6e823c05c40a34e53b6e422997e77f4193f8c, 2a47ad7c7ca3088ca46ae00351fdb8817108288e9e5a6d8eeec5aebdc222e539, 1c72cc7305f66e5efd73a025d1920e85cae47226f5ca5ac89a48460e16dbe931, 69cd1560e77fbc13a74cc8c9680cf901e6cd70c4a6e92432e698839954add01c, c2acf0deb8c89346f747b59b5af4aaa3181c71da5abb4ba2fa378232252a6f46 result, different first party: af95db93020da65f13e95cf78dc98d93dfd0e789c46cc062a116bc3586bdcb22, ee7b1e43d9707360cb8baec9e6f563f959cb971270e071dc77af873acaf9f7f2, d352c3cdbe6901f76ff3064d86a13c750d8544d063fce8dd901eb6b2f8a5b179, 5b074806370cb3ebad248f9bf7991ee8873440aeb0da15c2b547094bd5fe7e74, 300e60f69ee16210bd8a900bedbd9508eaa92e5f864207c71c97f8713a52654d unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: d404b62e1b06abc91a53313b445713bd70e4475c360aca3be4b236947cf0785b, 6304457e6b3244097cbf1a17b695d71d86c3eda04216ca76d4aad7cce680af39, e438ea07293422e537861ff044b65856a4b3a0af5a1f6e87078bda47bb33ace7, 922eb7bf378b915db6f2c05f1cd507eac53c7c37e0f9ae667aa5c43bb3322730, 2c0cec519db001edf689249d72dd85f5bcbaa3a3e5d20d3e457f16973464c650 result, different first party: f875da2a56d5333a7102a7ce58b2a0203311380fb5d2ce534fe7ba01f9cb6053, 7acb1ab77736effbefb3cde1fb7da9406901b9fed712662615e0529f6235f5c5, 0612ca2f2fb087715f5d945dc842d1971c01d3d3e6c35cf49ed0d2bde645b27d, 4217a9b20f204bf68eead00a15d66c88505c073cfdb0b2ca27cd613a16830784, 14814cd4e3152d63ac72ac27d4dff287d0ce4af090f105536feaa5933f1cb212 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: 6d884e9f4385e8155749f1be196d20222f66b9e409ca04e89fe06e635fce6f6d, 3bff18c3143485c81eb4e03bb5853ac5f3de42f331e8040ea28440f3b05d296e, 6110cb2f9659c3c7063110914bc2c9ccc7f4e86082469bcfd8bd654d587dfcca, fa26ff62fbedd317e35f157da58ec58a4dc8c4691de703cfaabe188d8689d508, 56ba80a446a8d312a2c87efd5a910c9a334ed14f220779483949f5589149948e result, different first party: 7d1f22e0400932d60b7598a91386d1d8ddc2f144fa08bdf2ce4a8068ac4f77a8, 87776fe28109211a28fc9f5a626e3cabb6f72c08958d4b8a0462cfbe502beb02, 03bf81fa945b959ee258f2ddfb2021024fae0c0f67125b4adf60616ca4f91974, 03c104fd2891843af4c6784759dc2c6629c87dd23386ebcb7b90eea9d0ec4267, 93c41adfd15653e6fa592ad8a47963f641371a6b6e3504fc8483199ec8ae4c35 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: 09bcdca27877ac69a382fd81eeb34ba3b350f7ca0f8f7536a8bb6cfebba7f562, 290fcc5d0db52568526170e9ec9d9081b8980d6d7a1c0af4fd2dbff8780d8536, d56af4330aa116cfa2127e972a5133a25a330a975644e29d8468863b52319f80, fd9cdc7d54cdd38ad638565ebd68f676c97b0fff11e3c7cbe2f77755e5977ba7, 4d2b31ac9afdac2d76f5216d2187530f5c9ae6761cb6cf3a74aa27eb5b42ff4f result, different first party: 8a3c18e421e3678f72bc11f45b2f3e250d92b0206ba18c19b86ee8617b3dac5a, f236a8c2c09269e144b95b849b0f68570fa516f8c6cc1cea495b4fedeaf58415, 66f27f0e2abb5646f0fff2641c58fe81aae258f9a6b03b486051968a20535c86, 0b118ae7d57e51367e28dc51f2e4f0b134d9289a836d4a362afe4fe83f11831c, 0e74a7a55595c6c8594b51399fef99bd0c469b280ec202dee2d1dd1a4d25b6a9 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: e902b788264d6c29f550b968cc80484de8e49cb27d1c93893d8ef80102e5f915, 31ff4f1f668cebfd932ff676a23748f6029962ccbade3d55fe63845edc5a658f, ed1dfa5c9249b6f9ed9cafe25fce88790cad49ab0d17ff25828d3484dfca609c, fcc0c1fd8ecd5bb5c8b565fa229b32c078d95f9f588a4b7e7dbf4a572ceba356, e19565baa4ec09b9a88f50ad7d421203840f2e52cb3220fb74406806c8bcaf01 result, different first party: 449a7fb9f879c321358bb665b01497b0c0881c5ad18740daef04a8e5ee0eedf5, 58299bdd5fa21f9b8ee38f9a129c83fbcf6c8e28b3d0c2b3adca49f6f4d59ad4, 6a96df3ffbbeffd16c07dac3916ff90dab2eae71d54b5a18c33140bd29d103f0, 8a2c7058f4ca39d7876f70b7624eb930541f5da96a50d5bb4ae64fe709eb728b, d4e9ddfc93d7a1e35ef9aac4198c027115b916017af297dcdb5041fd9dd07ff5 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: 0bd1f79ba1c8124dcf44ecccfb353b0297d76d0607bb6abcf2ce0fc4c1ae507e, 1c20e4457ebe1d41e6d6366120430aca356ec1e2b6a257758d3a2ad551b5559b, 80b679f56138a2b31d625de456e922be4278d68f08d71a1deab372cf8c613dae, 2276b8882f8ebc8392c0ce0bd86cbb5d9b9daca4a833c598d495886bab7106d6 result, different first party: 603f4102e8e9b57d8c818e3c1e9349cc0310f6e43c1f57074d18bfd6fc43f37e, 77889b863cda9629f6c8e75540cf886ba17d8940d7cb43a6904393ed8e529ca9, b4ffdf275b16c299377652e56d96c2a11656dcbe009a3f562447fe73760bf4b2, a42bc5cfc196d2abbc9f3f969adfe93b58b3c694029b56bc3db19d0b36661968 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: 3d5f18230fba18d90009f4cc1e51d982a09b7e88f2873d29af289f82684f49a9, b24b19c306798ed5d000555f121890d36f8936a4cd652be4d8032e214e51a9d8, 756320d42ddfe0f65c40a194e716ebf9ecb8b79b79af505f463b8cc9ba6b902d, 6333c1f4637478859fdf270b66e51d21552986c1def3a74a6738612f4eabab06, 70ddbbecfa7c3eec7731e0e1f4fb64ab4f18419e520a2011de379e3b25cf5b62 result, different first party: 6ea01f0f0e2d1fd3606bb2d1b5ab89ffab94fe35ea1a6af3c6fc2a514b3da4c7, 87d4b82782794651fcfe9feb849afd25af61c24376d388071ab432d82a8ea98c, 30144bbd1b1d9472db98c62521d53b409753e914e99926afcdd024afb0989913, f442910c55a0b0baf98b18dda231e8e7c67e550198a1ddb1b9f9e2f2f6477de9, dd055020c01ca5948b629104265dfc854da74e24fba513e932a833f2305d1897 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } read: async () => { let results = await fetch("https://tls.privacytests2.org:8900/"); return (await results.json()).sessionId; } result, same first party: cc9ea7dfa47167479f92c4e5b4837cf4f7e089d456a2ec4ba4df1f38406ed513, ea11d26af9ae5c16ad95600221011fe1e072046d9c08c951f5cb249f061641e6, f437197dc015412d85aa38be49672dd8965b8a5cf59f399a0cc121f47ecf32a0, a73a5745c5a4344488a464e02d7637a8c6e3a5ba0fabdf08ac4b8423ebbebc53, ac4e8bdb711a3228436d21a2cf3f4339641e9427290ade12412c9efe7d8085c6 result, different first party: 51eb0b0ffdc8024dfabce23e588ea52b05abd39f2505fbefbccf9e82203263f0, 59805c117ccc650664110643ff80ca895442378c32fcb34ce14c58ce3c58993b, 687cbd39e5438d656d673acc2351f963c31708331205b568a66bc46f8b49b73e, 41111009b978d495af546ebec3221d07ba2dab62e8f67928dc033df3772de304, 01128133609d9ddf47f362371e9adf461877af5fc4a2fd3a466bca7483bfe8b4 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
XMLHttpRequest cache
Similar to the newer Fetch API, any resource received may be cached by the browser. The cache is potentially vulnerable to cross-site tracking attack. |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1 result, different first party: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same first party: 1, 1, 1, 1, 1 result, different first party: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
Navigation testsWhich browsers prevent websites from sharing tracking data when you click on a link?
When you click a hyperlink to navigate your browser from one site to another, certain browser APIs allow the first site to communicate to the second site. These privacy vulnerabilities can be fixed by introducing new limits on how much data is transfered between sites.', |
|||||||||||||
document.referrer
The Referer [sic] request header is a mechanism used by browsers to let a website know where the user is visiting from. This header is inherently tracking users across websites. In recent times, browsers have switched to a policy of trimming a referrer to convey less tracking information, but Referer continues to convey cross-site tracking data by default. |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false passed: false, false, false, false test failed: false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { /* do nothing */ } read: () => document.referrer result, same first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ result, different first party: https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/, https://test-pages.privacytests2.org/ unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
sessionStorage
The sessionStorage API is similar to the localStorage API, but it does not persist across tabs or across browser sessions. Nonetheless, it can be used to track users if they navigate from one website to another. This tracking can be thwarted by partitioning sessionStorage between websites. |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1, d77fced8-9428-496f-9946-549bc356d246, d806ff56-0f9b-4bbb-bb05-9fa67a08c877, 1256fd40-841d-47a2-8902-ce5636a32cb3, ce2b00b3-8519-499e-967c-ea73aad6dbb1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: 91872272-1110-44b8-bb8a-fefcdca4198f, be106815-df48-45c9-9d4a-86b9823a76db, 3d351c8a-a896-428b-bb2d-cb2f2838d223, aa902857-ae8c-4123-bd90-2f0901ab8e24, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: 2f149f9d-7d24-4463-baa9-df54b4e81d63, e52cd2ae-6e45-4906-900c-b02f787f4589, 7f3c6670-9f55-4ad6-b476-3acc68733c6a, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b, 32b124ca-4477-4984-b641-b772ba9d739c result, different first party: Error: Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document. unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb result, different first party: b0873046-aed6-464f-bc48-1c45525ef56d, f76c7d52-c07b-4369-84d4-6d511639e60c, 32f07353-227f-4e1d-948d-0e4bad5866b1, fb89b2ee-5914-4ee5-ae26-30bc3301d983, 6567a88a-f349-4734-8828-9cc0df7600bb unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: 60671eda-690d-4a9e-9474-b59d33c8ed2d, 4df32057-71ef-4c97-b4a9-375da39140da, 5a39645b-74e0-456f-a064-66a4075a8239, 00946081-6b17-4b36-9aa6-61d144addef7, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: a6911260-affb-4f85-b66e-6372edef8271, f3f642e9-a578-4fd7-b323-71de0e1e5fda, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: cb2b3139-17be-441a-beaa-850c1130ce80, 381bfe46-5daa-42c3-9e58-39d98058f186, ddd70737-9afe-474e-ae84-787830e88cbc, d6af2086-88f6-4f4f-9669-2d31e549a804, 95431be4-0dbc-4181-a196-d3b6afacb47d result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: faca3efe-63fa-40b1-960d-14241446e02b, 2a2e037d-1d56-4d32-8402-d4b28afa8eac, 0eb26e1b-7201-4d84-aea1-8943179ccfc1, 73a700b0-d223-4f5a-9336-863c67ef6a20, 2a6798d9-a24d-470e-8d91-53d5e7f0d445 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: 8a59cde4-6473-44da-b170-f66c57b8df4a, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20, 5d49d947-6006-4865-9c31-04b966b4ac61, 87e46975-6855-4644-97bf-f9c66bae1455, db0c6390-897f-4eb6-b734-977466b215b6 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: 08871018-9567-44a6-b124-5cb6fb4797cf, ed296612-deee-4fff-b0e8-d7ee83e3b345, f45c8b38-f782-4290-a7cc-7c031ed1bd5e, 4ee8618c-dd14-47c0-ad13-50e8f625e228, 929477f2-6d6b-4b18-a642-f2ca892f3876 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: 77f9d876-5d2d-4776-824f-839b4afa98da, 3959c542-32c6-4033-b316-37a1a8e480e0, bec75a88-52bd-463a-b926-f1694cdddcaf, 2239e757-c407-4798-907e-852d4ab1d41f result, different first party: , , , unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: 91556de9-f4d0-4720-a0eb-89b93d8bbc62, e8f74dec-686f-4084-a15c-80172d70e290, c7af78eb-b2be-4edb-a01f-c5e80885c91b, bfa2edb1-7890-44d5-90e0-94ac0fef762a, 1e2332aa-e33b-49d1-b45e-4202d0db4096 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => sessionStorage.setItem("secret", secret) read: () => sessionStorage.getItem("secret") result, same first party: df04981a-509a-43d2-bd50-07e15e2191a0, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, 4a8ab582-40cd-40e7-b9b8-260ae2bee808, 975fde78-d933-4101-8f70-1fb2227ac766, 03b8d7d5-b189-4156-8310-62787b519fe2 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
window.name
The window.name API allows websites to store data that will persist after the user has navigated the tab to a different website. This mechanism could be partitioned so that data is not allowed to persist between websites. |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_8c65c2d7-9776-4410-ae6f-8e0a2abe70d1, name_d77fced8-9428-496f-9946-549bc356d246, name_d806ff56-0f9b-4bbb-bb05-9fa67a08c877, name_1256fd40-841d-47a2-8902-ce5636a32cb3, name_ce2b00b3-8519-499e-967c-ea73aad6dbb1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_91872272-1110-44b8-bb8a-fefcdca4198f, name_be106815-df48-45c9-9d4a-86b9823a76db, name_3d351c8a-a896-428b-bb2d-cb2f2838d223, name_aa902857-ae8c-4123-bd90-2f0901ab8e24, name_93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d result, different first party: name_91872272-1110-44b8-bb8a-fefcdca4198f, name_be106815-df48-45c9-9d4a-86b9823a76db, name_3d351c8a-a896-428b-bb2d-cb2f2838d223, name_aa902857-ae8c-4123-bd90-2f0901ab8e24, name_93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_2f149f9d-7d24-4463-baa9-df54b4e81d63, name_e52cd2ae-6e45-4906-900c-b02f787f4589, name_7f3c6670-9f55-4ad6-b476-3acc68733c6a, name_002b7cd9-f04b-4f64-baa3-7482ebcb8d8b, name_32b124ca-4477-4984-b641-b772ba9d739c result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_b0873046-aed6-464f-bc48-1c45525ef56d, name_f76c7d52-c07b-4369-84d4-6d511639e60c, name_32f07353-227f-4e1d-948d-0e4bad5866b1, name_fb89b2ee-5914-4ee5-ae26-30bc3301d983, name_6567a88a-f349-4734-8828-9cc0df7600bb result, different first party: name_b0873046-aed6-464f-bc48-1c45525ef56d, name_f76c7d52-c07b-4369-84d4-6d511639e60c, name_32f07353-227f-4e1d-948d-0e4bad5866b1, name_fb89b2ee-5914-4ee5-ae26-30bc3301d983, name_6567a88a-f349-4734-8828-9cc0df7600bb unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_60671eda-690d-4a9e-9474-b59d33c8ed2d, name_4df32057-71ef-4c97-b4a9-375da39140da, name_5a39645b-74e0-456f-a064-66a4075a8239, name_00946081-6b17-4b36-9aa6-61d144addef7, name_2ad71704-a05c-4a9d-9cf9-57f8579cbf04 result, different first party: name_60671eda-690d-4a9e-9474-b59d33c8ed2d, name_4df32057-71ef-4c97-b4a9-375da39140da, name_5a39645b-74e0-456f-a064-66a4075a8239, name_00946081-6b17-4b36-9aa6-61d144addef7, name_2ad71704-a05c-4a9d-9cf9-57f8579cbf04 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_a6911260-affb-4f85-b66e-6372edef8271, name_f3f642e9-a578-4fd7-b323-71de0e1e5fda, name_28d15258-7b1e-43c2-b863-a66c4e6d1a9d, name_f502a6e1-0f6d-451e-9a0a-9ae88e34ae46, name_40b7778f-bf11-4c7a-a4d3-3315e060c7b1 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_cb2b3139-17be-441a-beaa-850c1130ce80, name_381bfe46-5daa-42c3-9e58-39d98058f186, name_ddd70737-9afe-474e-ae84-787830e88cbc, name_d6af2086-88f6-4f4f-9669-2d31e549a804, name_95431be4-0dbc-4181-a196-d3b6afacb47d result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_faca3efe-63fa-40b1-960d-14241446e02b, name_2a2e037d-1d56-4d32-8402-d4b28afa8eac, name_0eb26e1b-7201-4d84-aea1-8943179ccfc1, name_73a700b0-d223-4f5a-9336-863c67ef6a20, name_2a6798d9-a24d-470e-8d91-53d5e7f0d445 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_8a59cde4-6473-44da-b170-f66c57b8df4a, name_56ab2bad-36f1-4f5d-9ceb-afea357a6e20, name_5d49d947-6006-4865-9c31-04b966b4ac61, name_87e46975-6855-4644-97bf-f9c66bae1455, name_db0c6390-897f-4eb6-b734-977466b215b6 result, different first party: name_8a59cde4-6473-44da-b170-f66c57b8df4a, name_56ab2bad-36f1-4f5d-9ceb-afea357a6e20, name_5d49d947-6006-4865-9c31-04b966b4ac61, name_87e46975-6855-4644-97bf-f9c66bae1455, name_db0c6390-897f-4eb6-b734-977466b215b6 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_08871018-9567-44a6-b124-5cb6fb4797cf, name_ed296612-deee-4fff-b0e8-d7ee83e3b345, name_f45c8b38-f782-4290-a7cc-7c031ed1bd5e, name_4ee8618c-dd14-47c0-ad13-50e8f625e228, name_929477f2-6d6b-4b18-a642-f2ca892f3876 result, different first party: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_77f9d876-5d2d-4776-824f-839b4afa98da, name_3959c542-32c6-4033-b316-37a1a8e480e0, name_bec75a88-52bd-463a-b926-f1694cdddcaf, name_2239e757-c407-4798-907e-852d4ab1d41f result, different first party: , , , unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_91556de9-f4d0-4720-a0eb-89b93d8bbc62, name_e8f74dec-686f-4084-a15c-80172d70e290, name_c7af78eb-b2be-4edb-a01f-c5e80885c91b, name_bfa2edb1-7890-44d5-90e0-94ac0fef762a, name_1e2332aa-e33b-49d1-b45e-4202d0db4096 result, different first party: name_91556de9-f4d0-4720-a0eb-89b93d8bbc62, name_e8f74dec-686f-4084-a15c-80172d70e290, name_c7af78eb-b2be-4edb-a01f-c5e80885c91b, name_bfa2edb1-7890-44d5-90e0-94ac0fef762a, name_1e2332aa-e33b-49d1-b45e-4202d0db4096 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => window.name = "name_" + secret read: () => window.name result, same first party: name_df04981a-509a-43d2-bd50-07e15e2191a0, name_e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, name_4a8ab582-40cd-40e7-b9b8-260ae2bee808, name_975fde78-d933-4101-8f70-1fb2227ac766, name_03b8d7d5-b189-4156-8310-62787b519fe2 result, different first party: name_df04981a-509a-43d2-bd50-07e15e2191a0, name_e9c7d7a8-cfd7-46b4-9c28-29d250862dd3, name_4a8ab582-40cd-40e7-b9b8-260ae2bee808, name_975fde78-d933-4101-8f70-1fb2227ac766, name_03b8d7d5-b189-4156-8310-62787b519fe2 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
HTTPS testsWhich browsers prevent unencrypted network connections?
HTTPS is the protocol that web browsers use to connect securely to websites. When HTTPS is being used, the connection is encrypted so that third parties on the network cannot read content being sent between the server and your browser. In the past, insecure connections were the default and websites would need to actively request that a browser use HTTPS. Now the status quo is shifting, and browser makers are moving toward a world where HTTPS is the default protocol.` |
|||||||||||||
Insecure website warning
Checks to see if the browser stops loading an insecure website and warns the user before giving them the option to continue. Known as HTTPS-Only Mode in some browsers. |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
passed: true, true, true, true, true result: Insecure website never loaded, Insecure website never loaded, Insecure website never loaded, Insecure website never loaded, Insecure website never loaded |
passed: true, true, true, true, true result: Insecure website never loaded, Insecure website never loaded, Insecure website never loaded, Insecure website never loaded, Insecure website never loaded |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
passed: true, true, true, true result: Insecure website never loaded, Insecure website never loaded, Insecure website never loaded, Insecure website never loaded |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
passed: false, false, false, false, false result: Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded, Insecure website loaded |
Upgradable address
Checks to see if an insecure address entered into the browser's address bar is upgraded to HTTPS whenever possible. |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
upgraded: true, true, true, true passed: true, true, true, true |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
Upgradable hyperlink
Checks to see if the user has clicked on a hyperlink to an insecure address, if the browser upgrades that address to HTTPS whenever possible. |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: true, true, true, true passed: true, true, true, true |
upgraded: true, true, true, true, true passed: true, true, true, true, true |
upgraded: false, false, false, false, false passed: false, false, false, false, false |
Upgradable image
Checks to see if the browser attempts to upgrade an insecure address for an image to HTTPS whenever possible. |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: false, false, false, false, false result: loaded insecurely, loaded insecurely, loaded insecurely, loaded insecurely, loaded insecurely |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true result: upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
Upgradable script
Checks to see if the browser attempts to upgrade an insecure address for an script to HTTPS whenever possible. |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: upgraded, upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
passed: true, true, true, true result: upgraded, upgraded, upgraded, upgraded |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
passed: true, true, true, true, true result: blocked, blocked, blocked, blocked, blocked |
Misc testsWhich browsers provide additional assorted privacy protections?
This category includes tests for the presence of miscellaneous privacy features |
|||||||||||||
ECH enabled
Encrypted Client Hello (ECH) is a new protocol that hides the website you are visiting from third-party network eavesdroppers. |
SNI_status: encrypted passed: true, true, true, true, true |
SNI_status: encrypted passed: true, true, true, true, true |
SNI_status: plaintext passed: false, false, false, false, false |
SNI_status: plaintext passed: false, false, false, false, false |
SNI_status: encrypted passed: true, true, true, true, true |
SNI_status: plaintext passed: false, false, false, true, false |
SNI_status: encrypted passed: true, false, true, false, false |
SNI_status: plaintext passed: false, false, true, true, false |
SNI_status: plaintext passed: false, false, false, false, false |
SNI_status: plaintext passed: false, false, false, false, false |
SNI_status: plaintext passed: false, false, false, false |
SNI_status: encrypted passed: true, true, true, true, true |
SNI_status: encrypted passed: true, true, true, true, true |
GPC enabled first-party
The Global Privacy Control is an HTTP header that can be sent by a browser to instruct a website not to sell the user's personal data to third parties. This test checks to see if the GPC header is sent by default to the top-level website. |
header value: 1 passed: true, true, true, true, true |
header value: undefined passed: false, false, false, false, false |
header value: 1 passed: true, true, true, true, true |
header value: 1 passed: true, true, true, true, true |
header value: undefined passed: false, false, false, false, false |
header value: undefined passed: false, false, false, false, false |
header value: 1 passed: true, true, true, true, true |
header value: undefined passed: false, false, false, false, false |
header value: undefined passed: false, false, false, false, false |
header value: undefined passed: false, false, false, false, false |
header value: undefined passed: false, false, false, false |
header value: undefined passed: false, false, false, false, false |
header value: undefined passed: false, false, false, false, false |
GPC enabled third-party
The Global Privacy Control is an HTTP header that can be sent by a browser to instruct a visited website not to sell the user's personal data to other parties. This test checks to see if the GPC header is sent to third-party elements on the web page. |
sec-gpc: 1 passed: true, true, true, true, true |
passed: false, false, false, false, false |
sec-gpc: 1 passed: true, true, true, true, true |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
sec-gpc: 1 passed: true, true, true, true, true |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
IP address leak
IP addresses can be used to uniquely identify a large percentage of users. A proxy, VPN, or Tor can mask a user's IP address. |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
passed: true, true, true, true |
passed: false, false, false, false, false |
passed: false, false, false, false, false |
Stream isolation
Browsers that use Tor can use a different Tor circuit per top-level website. |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: false, false, false, false readSameFirstParty: 2a0b:f4c2::3, 2a0b:f4c2::25, 2001:67c:6ec:203:192:42:116:210, 2a0b:f4c2::23 readDifferentFirstParty: 2a03:94e0:242c:dead::1, 2001:67c:6ec:203:192:42:116:184, 2a03:e600:100::6, 2001:bc8:1600:472a::1 passed: true, true, true, true testFailed: false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
write: () => { if (!usingTor) { throw new Error("Unsupported"); } } read: async () => { if (usingTor) { return ipAddress; } else { throw new Error("Unsupported"); } } unsupported: true, true, true, true, true readSameFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported readDifferentFirstParty: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported testFailed: false, false, false, false, false |
Tor enabled
The Tor network sends the browser's web requests through a series of relays to hide a user's IP address, thereby helping to mask their identity and location. This test checks to see if the Tor network is being used by default. |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: true, true, true, true passed: true, true, true, true |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
IsTorExit: false, false, false, false, false passed: false, false, false, false, false |
Fingerprinting resistance testsWhich browsers hide what's unique about your device?
Fingerprinting is a technique trackers use to uniquely identify you as you browse the web. A fingerprinting script will measure several characteristics of your browser and, combining this data, will build a fingerprint that may uniquely identify you among web users. Browsers can introduce countermeasures, such as minimizing the distinguishing information disclosed by certain web APIs so your browser is harder to pick out from the crowd (so-called 'fingerprinting resistance').`, |
|||||||||||||
Media query screen height
Height of the user's screen in pixels. |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 663,666,668,668,666 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: undefined desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: undefined desired value: undefined passed: false,false,false,false |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
Media query screen width
Width of the user's screen in pixels. |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 356,358,359,359,358 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 980,980,980,980,980 desired value: undefined passed: true,true,true,true,true |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 980,980,980,980 desired value: undefined passed: true,true,true,true |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: undefined desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
outerHeight
Height of the browser window in pixels, including browser chrome. |
expression: outerHeight desired expression: undefined actual value: 916,916,916,916,916 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 670,670,670,670,670 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 663,666,668,668,666 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 670,670,670,670,670 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 916,916,916,916,916 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 725,725,725,725,725 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 725,725,725,725,725 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 1822,1822,1822,1822,1822 desired value: undefined passed: true,true,true,true,true |
expression: outerHeight desired expression: undefined actual value: 614,614,614,614,614 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 630,630,630,630,630 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 1822,1822,1822,1822 desired value: undefined passed: true,true,true,true |
expression: outerHeight desired expression: undefined actual value: 582,582,582,582,582 desired value: undefined passed: false,false,false,false,false |
expression: outerHeight desired expression: undefined actual value: 618,618,618,618,618 desired value: undefined passed: false,false,false,false,false |
screen.height
Height of the user's screen, in pixels. |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 663,666,668,668,666 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 1822,1822,1822,1822,1822 desired value: undefined passed: true,true,true,true,true |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 1822,1822,1822,1822 desired value: undefined passed: true,true,true,true |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
expression: screen.height desired expression: undefined actual value: 800,800,800,800,800 desired value: undefined passed: false,false,false,false,false |
screen.width
Width of the user's screen, in pixels. |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 356,358,359,359,358 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 980,980,980,980,980 desired value: undefined passed: true,true,true,true,true |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 980,980,980,980 desired value: undefined passed: true,true,true,true |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
expression: screen.width desired expression: undefined actual value: 360,360,360,360,360 desired value: undefined passed: false,false,false,false,false |
screenX
Position, in pixels, of the left edge of the browser window on screen. |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0 desired value: undefined passed: true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenX desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
screenY
Position, in pixels, of the top edge of the browser window on screen. |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenY desired expression: undefined actual value: 83,83,83,83,83 desired value: undefined passed: false,false,false,false,false |
expression: screenY desired expression: undefined actual value: 83,83,83,83,83 desired value: undefined passed: false,false,false,false,false |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenY desired expression: undefined actual value: 0,0,0,0 desired value: undefined passed: true,true,true,true |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
expression: screenY desired expression: undefined actual value: 0,0,0,0,0 desired value: undefined passed: true,true,true,true,true |
Tracking query parameter testsWhich browsers remove URL parameters that can track you?
When you browse from one web page to another, tracking companies will frequently attach a 'tracking query parameter' to the address of the second web page. That query parameter may contain a unique identifier that tracks you individually as you browse the web. And these query parameters are frequently synchronized with cookies, making them a powerful tracking vector. Web browsers can protect you from known tracking query parameters by stripping them from web addresses before your browser sends them. (The set of tracking query parameters tested here was largely borrowed from Brave.)` |
|||||||||||||
__hsfp
HubSpot tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
__hssc
HubSpot tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
__hstc
HubSpot tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
__s
Drip.com email address tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
_hsenc
HubSpot tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
_openstat
Yandex tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
dclid
DoubleClick Click ID (Google) |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
fbclid
Facebook Click Identifier |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
gclid
Google Click Identifier |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
hsCtaTracking
HubSpot tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
mc_eid
Mailchimp Email ID (email recipient's address) |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
mkt_tok
Adobe Marketo tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
ml_subscriber
MailerLite email tracking |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
ml_subscriber_hash
MailerLite email tracking |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
msclkid
Microsoft Click ID |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
oly_anon_id
Omeda marketing 'anonymous' customer id |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
oly_enc_id
Omeda marketing 'known' customer id |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
rb_clickid
Unknown high-entropy tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
s_cid
Adobe Site Catalyst tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
vero_conv
Vero tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
vero_id
Vero tracking parameter |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
wickedid
Wicked Reports e-commerce tracking |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
yclid
Yandex Click ID |
passed: true, true, true, true, true |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
value: 875725364841891 passed: false, false, false, false, false |
Tracker content blocking testsWhich browsers block important known tracking scripts and pixels?
When you visit a web page, it frequently has third-party embedded tracking content, such as scripts and tracking pixels. These embedded components spy on you. Some browsers and browser extensions maintain list of tracking companies and block their content from being loaded. This section checks to see if a browser blocks 20 of the largest trackers listed by https://whotracks.me.` |
|||||||||||||
Adobe
Tests whether the browser blocks the page from loading the tracker at https://munchkin.marketo.net/munchkin.js |
url: https://munchkin.marketo.net/munchkin.js passed: true, true, true, true, true |
url: https://munchkin.marketo.net/munchkin.js passed: false, false, false, false, false |
url: https://munchkin.marketo.net/munchkin.js passed: false, false, false, false, false |
url: https://munchkin.marketo.net/munchkin.js passed: true, true, true, true, true |
url: https://munchkin.marketo.net/munchkin.js passed: false, false, false, false, false |
url: https://munchkin.marketo.net/munchkin.js passed: false, false, false, false, false |
url: https://munchkin.marketo.net/munchkin.js passed: true, true, true, true, true |
url: https://munchkin.marketo.net/munchkin.js passed: true, true, true, true, true |
url: https://munchkin.marketo.net/munchkin.js passed: false, false, false, false, false |
url: https://munchkin.marketo.net/munchkin.js passed: false, false, false, false, false |
url: https://munchkin.marketo.net/munchkin.js passed: false, false, false, false |
url: https://munchkin.marketo.net/munchkin.js passed: false, false, false, false, false |
url: https://munchkin.marketo.net/munchkin.js passed: false, false, false, false, false |
Adobe Audience Manager
Tests whether the browser blocks the page from loading the tracker at https://dpm.demdex.net/ibs |
url: https://dpm.demdex.net/ibs passed: true, true, true, true, true |
url: https://dpm.demdex.net/ibs passed: false, false, false, false, false |
url: https://dpm.demdex.net/ibs passed: false, false, false, false, false |
url: https://dpm.demdex.net/ibs passed: true, true, true, true, true |
url: https://dpm.demdex.net/ibs passed: false, false, false, false, false |
url: https://dpm.demdex.net/ibs passed: false, false, false, false, false |
url: https://dpm.demdex.net/ibs passed: true, true, true, true, true |
url: https://dpm.demdex.net/ibs passed: true, true, true, true, true |
url: https://dpm.demdex.net/ibs passed: false, false, false, false, false |
url: https://dpm.demdex.net/ibs passed: false, false, false, false, false |
url: https://dpm.demdex.net/ibs passed: false, false, false, false |
url: https://dpm.demdex.net/ibs passed: false, false, false, false, false |
url: https://dpm.demdex.net/ibs passed: false, false, false, false, false |
Amazon adsystem
Tests whether the browser blocks the page from loading the tracker at https://s.amazon-adsystem.com/dcm |
url: https://s.amazon-adsystem.com/dcm passed: true, true, true, true, true |
url: https://s.amazon-adsystem.com/dcm passed: false, false, false, false, false |
url: https://s.amazon-adsystem.com/dcm passed: true, true, true, true, true |
url: https://s.amazon-adsystem.com/dcm passed: true, true, true, true, true |
url: https://s.amazon-adsystem.com/dcm passed: false, false, false, false, false |
url: https://s.amazon-adsystem.com/dcm passed: false, false, false, false, false |
url: https://s.amazon-adsystem.com/dcm passed: true, true, true, true, true |
url: https://s.amazon-adsystem.com/dcm passed: true, true, true, true, true |
url: https://s.amazon-adsystem.com/dcm passed: true, true, true, true, true |
url: https://s.amazon-adsystem.com/dcm passed: false, false, false, false, false |
url: https://s.amazon-adsystem.com/dcm passed: false, false, false, false |
url: https://s.amazon-adsystem.com/dcm passed: false, false, false, false, false |
url: https://s.amazon-adsystem.com/dcm passed: false, false, false, false, false |
AppNexus
Tests whether the browser blocks the page from loading the tracker at https://ib.adnxs.com/px?id=178248&t=1 |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: true, true, true, true, true |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: false, false, false, false, false |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: true, true, true, true, true |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: true, true, true, true, true |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: false, false, false, false, false |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: false, false, false, false, false |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: true, true, true, true, true |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: true, true, true, true, true |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: true, true, true, true, true |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: false, false, false, false, false |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: false, false, false, false |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: false, false, false, false, false |
url: https://ib.adnxs.com/px?id=178248&t=1 passed: false, false, false, false, false |
Bing Ads
Tests whether the browser blocks the page from loading the tracker at https://bat.bing.com/bat.js |
url: https://bat.bing.com/bat.js passed: true, true, true, true, true |
url: https://bat.bing.com/bat.js passed: false, false, false, false, false |
url: https://bat.bing.com/bat.js passed: false, false, false, false, false |
url: https://bat.bing.com/bat.js passed: true, true, true, true, true |
url: https://bat.bing.com/bat.js passed: false, false, false, false, false |
url: https://bat.bing.com/bat.js passed: false, false, false, false, false |
url: https://bat.bing.com/bat.js passed: true, true, true, true, true |
url: https://bat.bing.com/bat.js passed: true, true, true, true, true |
url: https://bat.bing.com/bat.js passed: false, false, false, false, false |
url: https://bat.bing.com/bat.js passed: false, false, false, false, false |
url: https://bat.bing.com/bat.js passed: false, false, false, false |
url: https://bat.bing.com/bat.js passed: false, false, false, false, false |
url: https://bat.bing.com/bat.js passed: false, false, false, false, false |
Chartbeat
Tests whether the browser blocks the page from loading the tracker at https://static.chartbeat.com/js/chartbeat.js |
url: https://static.chartbeat.com/js/chartbeat.js passed: true, true, true, true, true |
url: https://static.chartbeat.com/js/chartbeat.js passed: false, false, false, false, false |
url: https://static.chartbeat.com/js/chartbeat.js passed: false, false, false, false, false |
url: https://static.chartbeat.com/js/chartbeat.js passed: true, true, true, true, true |
url: https://static.chartbeat.com/js/chartbeat.js passed: false, false, false, false, false |
url: https://static.chartbeat.com/js/chartbeat.js passed: false, false, false, false, false |
url: https://static.chartbeat.com/js/chartbeat.js passed: true, true, true, true, true |
url: https://static.chartbeat.com/js/chartbeat.js passed: true, true, true, true, true |
url: https://static.chartbeat.com/js/chartbeat.js passed: false, false, false, false, false |
url: https://static.chartbeat.com/js/chartbeat.js passed: false, false, false, false, false |
url: https://static.chartbeat.com/js/chartbeat.js passed: false, false, false, false |
url: https://static.chartbeat.com/js/chartbeat.js passed: false, false, false, false, false |
url: https://static.chartbeat.com/js/chartbeat.js passed: false, false, false, false, false |
Criteo
Tests whether the browser blocks the page from loading the tracker at https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: true, true, true, true, true |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: false, false, false, false, false |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: false, false, false, false, false |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: true, true, true, true, true |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: false, false, false, false, false |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: false, false, false, false, false |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: true, true, true, true, true |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: true, true, true, true, true |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: false, false, false, false, false |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: false, false, false, false, false |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: false, false, false, false |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: false, false, false, false, false |
url: https://dis.criteo.com/dis/rtb/appnexus/cookiematch.aspx passed: false, false, false, false, false |
DoubleClick (Google)
Tests whether the browser blocks the page from loading the tracker at https://securepubads.g.doubleclick.net/static/glade.js |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: true, true, true, true, true |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: false, false, false, false, false |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: true, true, true, true, true |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: true, true, true, true, true |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: false, false, false, false, false |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: false, false, false, false, false |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: true, true, true, true, true |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: true, true, true, true, true |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: true, true, true, true, true |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: false, false, false, false, false |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: false, false, false, false |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: false, false, false, false, false |
url: https://securepubads.g.doubleclick.net/static/glade.js passed: false, false, false, false, false |
Facebook tracking
Tests whether the browser blocks the page from loading the tracker at https://connect.facebook.net/en_US/fbevents.js |
url: https://connect.facebook.net/en_US/fbevents.js passed: true, true, true, true, true |
url: https://connect.facebook.net/en_US/fbevents.js passed: false, false, false, false, false |
url: https://connect.facebook.net/en_US/fbevents.js passed: false, false, false, false, false |
url: https://connect.facebook.net/en_US/fbevents.js passed: true, true, true, true, true |
url: https://connect.facebook.net/en_US/fbevents.js passed: false, false, false, false, false |
url: https://connect.facebook.net/en_US/fbevents.js passed: false, false, false, false, false |
url: https://connect.facebook.net/en_US/fbevents.js passed: true, true, true, true, true |
url: https://connect.facebook.net/en_US/fbevents.js passed: true, true, true, true, true |
url: https://connect.facebook.net/en_US/fbevents.js passed: false, false, false, false, false |
url: https://connect.facebook.net/en_US/fbevents.js passed: false, false, false, false, false |
url: https://connect.facebook.net/en_US/fbevents.js passed: false, false, false, false |
url: https://connect.facebook.net/en_US/fbevents.js passed: false, false, false, false, false |
url: https://connect.facebook.net/en_US/fbevents.js passed: false, false, false, false, false |
Google (third-party ad pixel)
Tests whether the browser blocks the page from loading the tracker at https://www.google.com/pagead/1p-user-list/ |
url: https://www.google.com/pagead/1p-user-list/ passed: true, true, true, true, true |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false, false |
url: https://www.google.com/pagead/1p-user-list/ passed: true, true, true, true, true |
url: https://www.google.com/pagead/1p-user-list/ passed: true, true, true, true, true |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false, false |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false, false |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false, false |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false, false |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false, false |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false, false |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false, false |
url: https://www.google.com/pagead/1p-user-list/ passed: false, false, false, false, false |
Google Analytics
Tests whether the browser blocks the page from loading the tracker at https://google-analytics.com/urchin.js |
url: https://google-analytics.com/urchin.js passed: true, true, true, true, true |
url: https://google-analytics.com/urchin.js passed: false, false, false, false, false |
url: https://google-analytics.com/urchin.js passed: false, false, false, false, false |
url: https://google-analytics.com/urchin.js passed: true, true, true, true, true |
url: https://google-analytics.com/urchin.js passed: false, false, false, false, false |
url: https://google-analytics.com/urchin.js passed: false, false, false, false, false |
url: https://google-analytics.com/urchin.js passed: true, true, true, true, true |
url: https://google-analytics.com/urchin.js passed: true, true, true, true, true |
url: https://google-analytics.com/urchin.js passed: false, false, false, false, false |
url: https://google-analytics.com/urchin.js passed: false, false, false, false, false |
url: https://google-analytics.com/urchin.js passed: false, false, false, false |
url: https://google-analytics.com/urchin.js passed: false, false, false, false, false |
url: https://google-analytics.com/urchin.js passed: false, false, false, false, false |
Google Tag Manager
Tests whether the browser blocks the page from loading the tracker at https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: true, true, true, true, true |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: true, true, true, true, true |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
url: https://www.googletagmanager.com/gtag.js?id=GTM-NX4SMZL passed: false, false, false, false, false |
Index Exchange
Tests whether the browser blocks the page from loading the tracker at https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: true, true, true, true, true |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: false, false, false, false, false |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: true, true, true, true, true |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: true, true, true, true, true |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: false, false, false, false, false |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: false, false, false, false, false |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: true, true, true, true, true |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: true, true, true, true, true |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: true, true, true, true, true |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: false, false, false, false, false |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: false, false, false, false |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: false, false, false, false, false |
url: https://dsum-sec.casalemedia.com/crum?cm_dsp_id=10&external_user_id=629685505537&C=1 passed: false, false, false, false, false |
New Relic
Tests whether the browser blocks the page from loading the tracker at https://js-agent.newrelic.com/nr-1212.min.js |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: true, true, true, true, true |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: false, false, false, false, false |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: false, false, false, false, false |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: true, true, true, true, true |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: false, false, false, false, false |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: false, false, false, false, false |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: true, true, true, true, true |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: true, true, true, true, true |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: false, false, false, false, false |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: false, false, false, false, false |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: false, false, false, false |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: false, false, false, false, false |
url: https://js-agent.newrelic.com/nr-1212.min.js passed: false, false, false, false, false |
Quantcast
Tests whether the browser blocks the page from loading the tracker at https://pixel.quantserve.com/pixel |
url: https://pixel.quantserve.com/pixel passed: true, true, true, true, true |
url: https://pixel.quantserve.com/pixel passed: false, false, false, false, false |
url: https://pixel.quantserve.com/pixel passed: false, false, false, false, false |
url: https://pixel.quantserve.com/pixel passed: true, true, true, true, true |
url: https://pixel.quantserve.com/pixel passed: false, false, false, false, false |
url: https://pixel.quantserve.com/pixel passed: false, false, false, false, false |
url: https://pixel.quantserve.com/pixel passed: true, true, true, true, true |
url: https://pixel.quantserve.com/pixel passed: true, true, true, true, true |
url: https://pixel.quantserve.com/pixel passed: false, false, false, false, false |
url: https://pixel.quantserve.com/pixel passed: false, false, false, false, false |
url: https://pixel.quantserve.com/pixel passed: false, false, false, false |
url: https://pixel.quantserve.com/pixel passed: false, false, false, false, false |
url: https://pixel.quantserve.com/pixel passed: false, false, false, false, false |
Scorecard Research Beacon
Tests whether the browser blocks the page from loading the tracker at https://sb.scorecardresearch.com/internal-c2/default/cs.js |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: true, true, true, true, true |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: false, false, false, false, false |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: false, false, false, false, false |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: true, true, true, true, true |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: false, false, false, false, false |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: false, false, false, false, false |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: true, true, true, true, true |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: true, true, true, true, true |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: false, false, false, false, false |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: false, false, false, false, false |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: false, false, false, false |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: false, false, false, false, false |
url: https://sb.scorecardresearch.com/internal-c2/default/cs.js passed: false, false, false, false, false |
Taboola
Tests whether the browser blocks the page from loading the tracker at https://trc.taboola.com/futureplc-tomsguide/trc/3/json |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: true, true, true, true, true |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: false, false, false, false, false |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: false, false, false, false, false |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: true, true, true, true, true |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: false, false, false, false, false |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: false, false, false, false, false |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: true, true, true, true, true |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: true, true, true, true, true |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: false, false, false, false, false |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: false, false, false, false, false |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: false, false, false, false |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: false, false, false, false, false |
url: https://trc.taboola.com/futureplc-tomsguide/trc/3/json passed: false, false, false, false, false |
Twitter pixel
Tests whether the browser blocks the page from loading the tracker at https://t.co/i/adsct |
url: https://t.co/i/adsct passed: true, true, true, true, true |
url: https://t.co/i/adsct passed: false, false, false, false, false |
url: https://t.co/i/adsct passed: true, true, true, true, true |
url: https://t.co/i/adsct passed: true, true, true, true, true |
url: https://t.co/i/adsct passed: false, false, false, false, false |
url: https://t.co/i/adsct passed: false, false, false, false, false |
url: https://t.co/i/adsct passed: true, true, true, true, true |
url: https://t.co/i/adsct passed: true, true, true, true, true |
url: https://t.co/i/adsct passed: false, false, false, false, false |
url: https://t.co/i/adsct passed: false, false, false, false, false |
url: https://t.co/i/adsct passed: false, false, false, false |
url: https://t.co/i/adsct passed: false, false, false, false, false |
url: https://t.co/i/adsct passed: false, false, false, false, false |
Yandex Ads
Tests whether the browser blocks the page from loading the tracker at https://yandex.ru/ads/system/header-bidding.js |
url: https://yandex.ru/ads/system/header-bidding.js passed: true, true, true, true, true |
url: https://yandex.ru/ads/system/header-bidding.js passed: false, false, false, false, false |
url: https://yandex.ru/ads/system/header-bidding.js passed: true, true, true, true, true |
url: https://yandex.ru/ads/system/header-bidding.js passed: true, true, true, true, true |
url: https://yandex.ru/ads/system/header-bidding.js passed: false, false, false, false, false |
url: https://yandex.ru/ads/system/header-bidding.js passed: false, false, false, false, false |
url: https://yandex.ru/ads/system/header-bidding.js passed: false, false, false, false, false |
url: https://yandex.ru/ads/system/header-bidding.js passed: false, false, false, false, false |
url: https://yandex.ru/ads/system/header-bidding.js passed: true, true, true, true, true |
url: https://yandex.ru/ads/system/header-bidding.js passed: false, false, false, false, false |
url: https://yandex.ru/ads/system/header-bidding.js passed: false, false, false, false |
url: https://yandex.ru/ads/system/header-bidding.js passed: false, false, false, false, false |
url: https://yandex.ru/ads/system/header-bidding.js passed: false, false, false, false, false |
Cross-session first-party tracking testsWhich browsers prevent websites from tracking you across browser sessions?
A common vulnerability of web browsers is that they allow websites ("first parties") to 'tag' your browser with some tracking data. This tag can be used to re-identify you when you return to a website you visited before. This category of leaks can be prevented by browser if they clean or isolate data between browser sessions. (In cases where a user has logged into a website or entered detailed information, it may be justifiable for a browser to retain information across sessions. These tests check when no such justification exists: when you have entered no significant information into a website, will the browser still retain data that allows you to be tracked across sessions?) |
|||||||||||||
Alt-Svc
Alt-Svc allows the server to indicate to the web browser that a resource should be loaded on a different server. Because this is a persistent setting, it could be used to track users across websites if it is not correctly partitioned. |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h2, h2, h2, h2, h2 result, different session: h2, h2, h2, h2, h2 unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h3, h2, h3, h2, h3 unsupported: false, false, false, false, false passed: false, true, false, true, false test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h3, h2, h3, h2, h3 unsupported: false, false, false, false, false passed: false, true, false, true, false test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h2, h2, h2, h2, h2 result, different session: h2, h2, h2, h2, h2 unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h2, h2, h2, h2 result, different session: h2, h2, h2, h2 unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
CacheStorage
The Cache API is a content storage mechanism originally introduced to support ServiceWorkers. If the same Cache object is accessible to multiple websites, it can be abused to track users. |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p, 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p, 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p, 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p, 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p result, different session: 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p, 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p, 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p, 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p, 143d61f8-2894-4529-ad80-0a53e9ebc6cc_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p result, different session: c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p, 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p, 32b124ca-4477-4984-b641-b772ba9d739c_1p result, different session: 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p, 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p, 32b124ca-4477-4984-b641-b772ba9d739c_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 15571fa3-0642-4589-90a9-ec73a7a073d9_1p, 15571fa3-0642-4589-90a9-ec73a7a073d9_1p, 15571fa3-0642-4589-90a9-ec73a7a073d9_1p, 15571fa3-0642-4589-90a9-ec73a7a073d9_1p, 15571fa3-0642-4589-90a9-ec73a7a073d9_1p result, different session: 15571fa3-0642-4589-90a9-ec73a7a073d9_1p, 15571fa3-0642-4589-90a9-ec73a7a073d9_1p, 15571fa3-0642-4589-90a9-ec73a7a073d9_1p, 15571fa3-0642-4589-90a9-ec73a7a073d9_1p, 15571fa3-0642-4589-90a9-ec73a7a073d9_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p result, different session: 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 6b80d03e-105e-4201-b76d-0596f346aaac_1p, 6b80d03e-105e-4201-b76d-0596f346aaac_1p, 6b80d03e-105e-4201-b76d-0596f346aaac_1p, 6b80d03e-105e-4201-b76d-0596f346aaac_1p, 6b80d03e-105e-4201-b76d-0596f346aaac_1p result, different session: 6b80d03e-105e-4201-b76d-0596f346aaac_1p, 6b80d03e-105e-4201-b76d-0596f346aaac_1p, 6b80d03e-105e-4201-b76d-0596f346aaac_1p, 6b80d03e-105e-4201-b76d-0596f346aaac_1p, 6b80d03e-105e-4201-b76d-0596f346aaac_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_1p, 381bfe46-5daa-42c3-9e58-39d98058f186_1p, ddd70737-9afe-474e-ae84-787830e88cbc_1p, d6af2086-88f6-4f4f-9669-2d31e549a804_1p, 95431be4-0dbc-4181-a196-d3b6afacb47d_1p result, different session: Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: ec26e749-9cec-4f7a-98e6-641c090e7817_1p, ec26e749-9cec-4f7a-98e6-641c090e7817_1p, ec26e749-9cec-4f7a-98e6-641c090e7817_1p, ec26e749-9cec-4f7a-98e6-641c090e7817_1p, ec26e749-9cec-4f7a-98e6-641c090e7817_1p result, different session: ec26e749-9cec-4f7a-98e6-641c090e7817_1p, ec26e749-9cec-4f7a-98e6-641c090e7817_1p, ec26e749-9cec-4f7a-98e6-641c090e7817_1p, ec26e749-9cec-4f7a-98e6-641c090e7817_1p, ec26e749-9cec-4f7a-98e6-641c090e7817_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p, c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p, c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p, c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p, c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p result, different session: c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p, c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p, c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p, c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p, c97b5d06-2396-4bb1-9f7d-6fde65072b04_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p result, different session: a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p, a31f089a-366d-46aa-8a3d-39c59eae3ef3_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. result, different session: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p result, different session: 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_1p, df04981a-509a-43d2-bd50-07e15e2191a0_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 03b8d7d5-b189-4156-8310-62787b519fe2_1p result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_1p, df04981a-509a-43d2-bd50-07e15e2191a0_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 03b8d7d5-b189-4156-8310-62787b519fe2_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
cookie (HTTP)
The cookie, first introduced by Netscape in 1994, is a small amount of data stored by your browser on a website's behalf. It has legitimate uses, but it is also the classic cross-site tracking mechanism, and today still the most popular method of tracking users across websites. Browsers can stop cookies from being used for cross-site tracking by either blocking or partitioning them. |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_1p_http, d77fced8-9428-496f-9946-549bc356d246_1p_http, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_1p_http, 1256fd40-841d-47a2-8902-ce5636a32cb3_1p_http, ce2b00b3-8519-499e-967c-ea73aad6dbb1_1p_http result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p_http, be106815-df48-45c9-9d4a-86b9823a76db_1p_http, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p_http, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p_http, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p_http result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p_http, be106815-df48-45c9-9d4a-86b9823a76db_1p_http, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p_http, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p_http, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p_http, e52cd2ae-6e45-4906-900c-b02f787f4589_1p_http, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p_http, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b_1p_http, 32b124ca-4477-4984-b641-b772ba9d739c_1p_http result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: b0873046-aed6-464f-bc48-1c45525ef56d_1p_http, f76c7d52-c07b-4369-84d4-6d511639e60c_1p_http, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p_http, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p_http, 6567a88a-f349-4734-8828-9cc0df7600bb_1p_http result, different session: b0873046-aed6-464f-bc48-1c45525ef56d_1p_http, f76c7d52-c07b-4369-84d4-6d511639e60c_1p_http, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p_http, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p_http, 6567a88a-f349-4734-8828-9cc0df7600bb_1p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p_http, 4df32057-71ef-4c97-b4a9-375da39140da_1p_http, 5a39645b-74e0-456f-a064-66a4075a8239_1p_http, 00946081-6b17-4b36-9aa6-61d144addef7_1p_http, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p_http result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p_http, 4df32057-71ef-4c97-b4a9-375da39140da_1p_http, 5a39645b-74e0-456f-a064-66a4075a8239_1p_http, 00946081-6b17-4b36-9aa6-61d144addef7_1p_http, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: a6911260-affb-4f85-b66e-6372edef8271_1p_http, f3f642e9-a578-4fd7-b323-71de0e1e5fda_1p_http, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_1p_http, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_1p_http, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_1p_http result, different session: a6911260-affb-4f85-b66e-6372edef8271_1p_http, f3f642e9-a578-4fd7-b323-71de0e1e5fda_1p_http, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_1p_http, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_1p_http, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_1p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_1p_http, 381bfe46-5daa-42c3-9e58-39d98058f186_1p_http, ddd70737-9afe-474e-ae84-787830e88cbc_1p_http, d6af2086-88f6-4f4f-9669-2d31e549a804_1p_http, 95431be4-0dbc-4181-a196-d3b6afacb47d_1p_http result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: faca3efe-63fa-40b1-960d-14241446e02b_1p_http, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_1p_http, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_1p_http, 73a700b0-d223-4f5a-9336-863c67ef6a20_1p_http, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_1p_http result, different session: faca3efe-63fa-40b1-960d-14241446e02b_1p_http, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_1p_http, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_1p_http, 73a700b0-d223-4f5a-9336-863c67ef6a20_1p_http, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_1p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p_http, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p_http, 5d49d947-6006-4865-9c31-04b966b4ac61_1p_http, 87e46975-6855-4644-97bf-f9c66bae1455_1p_http, db0c6390-897f-4eb6-b734-977466b215b6_1p_http result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p_http, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p_http, 5d49d947-6006-4865-9c31-04b966b4ac61_1p_http, 87e46975-6855-4644-97bf-f9c66bae1455_1p_http, db0c6390-897f-4eb6-b734-977466b215b6_1p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p_http, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p_http, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p_http, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p_http, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p_http result, different session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p_http, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p_http, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p_http, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p_http, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 77f9d876-5d2d-4776-824f-839b4afa98da_1p_http, 3959c542-32c6-4033-b316-37a1a8e480e0_1p_http, bec75a88-52bd-463a-b926-f1694cdddcaf_1p_http, 2239e757-c407-4798-907e-852d4ab1d41f_1p_http result, different session: , , , unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p_http, e8f74dec-686f-4084-a15c-80172d70e290_1p_http, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p_http, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p_http, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p_http result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p_http, e8f74dec-686f-4084-a15c-80172d70e290_1p_http, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p_http, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p_http, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_1p_http, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p_http, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p_http, 975fde78-d933-4101-8f70-1fb2227ac766_1p_http, 03b8d7d5-b189-4156-8310-62787b519fe2_1p_http result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_1p_http, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p_http, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p_http, 975fde78-d933-4101-8f70-1fb2227ac766_1p_http, 03b8d7d5-b189-4156-8310-62787b519fe2_1p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
cookie (JS)
The cookie, first introduced by Netscape in 1994, is a small amount of data stored by your browser on a website's behalf. It has legitimate uses, but it is also the classic cross-site tracking mechanism, and today still the most popular method of tracking users across websites. Browsers can stop cookies from being used for cross-site tracking by either blocking or partitioning them. |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_1p_js, d77fced8-9428-496f-9946-549bc356d246_1p_js, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_1p_js, 1256fd40-841d-47a2-8902-ce5636a32cb3_1p_js, ce2b00b3-8519-499e-967c-ea73aad6dbb1_1p_js result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p_js, be106815-df48-45c9-9d4a-86b9823a76db_1p_js, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p_js, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p_js, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p_js result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p_js, be106815-df48-45c9-9d4a-86b9823a76db_1p_js, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p_js, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p_js, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p_js, e52cd2ae-6e45-4906-900c-b02f787f4589_1p_js, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p_js, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b_1p_js, 32b124ca-4477-4984-b641-b772ba9d739c_1p_js result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: b0873046-aed6-464f-bc48-1c45525ef56d_1p_js, f76c7d52-c07b-4369-84d4-6d511639e60c_1p_js, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p_js, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p_js, 6567a88a-f349-4734-8828-9cc0df7600bb_1p_js result, different session: b0873046-aed6-464f-bc48-1c45525ef56d_1p_js, f76c7d52-c07b-4369-84d4-6d511639e60c_1p_js, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p_js, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p_js, 6567a88a-f349-4734-8828-9cc0df7600bb_1p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p_js, 4df32057-71ef-4c97-b4a9-375da39140da_1p_js, 5a39645b-74e0-456f-a064-66a4075a8239_1p_js, 00946081-6b17-4b36-9aa6-61d144addef7_1p_js, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p_js result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p_js, 4df32057-71ef-4c97-b4a9-375da39140da_1p_js, 5a39645b-74e0-456f-a064-66a4075a8239_1p_js, 00946081-6b17-4b36-9aa6-61d144addef7_1p_js, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: a6911260-affb-4f85-b66e-6372edef8271_1p_js, f3f642e9-a578-4fd7-b323-71de0e1e5fda_1p_js, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_1p_js, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_1p_js, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_1p_js result, different session: a6911260-affb-4f85-b66e-6372edef8271_1p_js, f3f642e9-a578-4fd7-b323-71de0e1e5fda_1p_js, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_1p_js, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_1p_js, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_1p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_1p_js, 381bfe46-5daa-42c3-9e58-39d98058f186_1p_js, ddd70737-9afe-474e-ae84-787830e88cbc_1p_js, d6af2086-88f6-4f4f-9669-2d31e549a804_1p_js, 95431be4-0dbc-4181-a196-d3b6afacb47d_1p_js result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: faca3efe-63fa-40b1-960d-14241446e02b_1p_js, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_1p_js, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_1p_js, 73a700b0-d223-4f5a-9336-863c67ef6a20_1p_js, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_1p_js result, different session: faca3efe-63fa-40b1-960d-14241446e02b_1p_js, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_1p_js, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_1p_js, 73a700b0-d223-4f5a-9336-863c67ef6a20_1p_js, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_1p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p_js, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p_js, 5d49d947-6006-4865-9c31-04b966b4ac61_1p_js, 87e46975-6855-4644-97bf-f9c66bae1455_1p_js, db0c6390-897f-4eb6-b734-977466b215b6_1p_js result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p_js, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p_js, 5d49d947-6006-4865-9c31-04b966b4ac61_1p_js, 87e46975-6855-4644-97bf-f9c66bae1455_1p_js, db0c6390-897f-4eb6-b734-977466b215b6_1p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p_js, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p_js, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p_js, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p_js, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p_js result, different session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p_js, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p_js, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p_js, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p_js, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 77f9d876-5d2d-4776-824f-839b4afa98da_1p_js, 3959c542-32c6-4033-b316-37a1a8e480e0_1p_js, bec75a88-52bd-463a-b926-f1694cdddcaf_1p_js, 2239e757-c407-4798-907e-852d4ab1d41f_1p_js result, different session: , , , unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p_js, e8f74dec-686f-4084-a15c-80172d70e290_1p_js, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p_js, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p_js, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p_js result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p_js, e8f74dec-686f-4084-a15c-80172d70e290_1p_js, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p_js, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p_js, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_1p_js, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p_js, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p_js, 975fde78-d933-4101-8f70-1fb2227ac766_1p_js, 03b8d7d5-b189-4156-8310-62787b519fe2_1p_js result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_1p_js, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p_js, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p_js, 975fde78-d933-4101-8f70-1fb2227ac766_1p_js, 03b8d7d5-b189-4156-8310-62787b519fe2_1p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
CookieStore
The Cookie Store API is an alternative asynchronous API for managing cookies, supported by some browsers. |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_1p, d77fced8-9428-496f-9946-549bc356d246_1p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_1p, 1256fd40-841d-47a2-8902-ce5636a32cb3_1p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_1p result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p, be106815-df48-45c9-9d4a-86b9823a76db_1p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p, be106815-df48-45c9-9d4a-86b9823a76db_1p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p, e52cd2ae-6e45-4906-900c-b02f787f4589_1p, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b_1p, 32b124ca-4477-4984-b641-b772ba9d739c_1p result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: b0873046-aed6-464f-bc48-1c45525ef56d_1p, f76c7d52-c07b-4369-84d4-6d511639e60c_1p, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p, 6567a88a-f349-4734-8828-9cc0df7600bb_1p result, different session: b0873046-aed6-464f-bc48-1c45525ef56d_1p, f76c7d52-c07b-4369-84d4-6d511639e60c_1p, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p, 6567a88a-f349-4734-8828-9cc0df7600bb_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p, 4df32057-71ef-4c97-b4a9-375da39140da_1p, 5a39645b-74e0-456f-a064-66a4075a8239_1p, 00946081-6b17-4b36-9aa6-61d144addef7_1p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p, 4df32057-71ef-4c97-b4a9-375da39140da_1p, 5a39645b-74e0-456f-a064-66a4075a8239_1p, 00946081-6b17-4b36-9aa6-61d144addef7_1p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p, 5d49d947-6006-4865-9c31-04b966b4ac61_1p, 87e46975-6855-4644-97bf-f9c66bae1455_1p, db0c6390-897f-4eb6-b734-977466b215b6_1p result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p, 5d49d947-6006-4865-9c31-04b966b4ac61_1p, 87e46975-6855-4644-97bf-f9c66bae1455_1p, db0c6390-897f-4eb6-b734-977466b215b6_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p result, different session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p, e8f74dec-686f-4084-a15c-80172d70e290_1p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p, e8f74dec-686f-4084-a15c-80172d70e290_1p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_1p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 975fde78-d933-4101-8f70-1fb2227ac766_1p, 03b8d7d5-b189-4156-8310-62787b519fe2_1p result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_1p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 975fde78-d933-4101-8f70-1fb2227ac766_1p, 03b8d7d5-b189-4156-8310-62787b519fe2_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
CSS cache
CSS stylesheets are cached, and if that cache is shared between websites, it can be used to track users across sites. |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_9120552749952695, fake_9702811187453022, fake_9605101046090623, fake_8305574245937015, fake_49731400277503024 result, different session: fake_9120552749952695, fake_9702811187453022, fake_9605101046090623, fake_8305574245937015, fake_49731400277503024 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_012046916333812607, fake_22892621874966457, fake_3904253839317944, fake_29472601492574735, fake_024676284662448644 result, different session: fake_012046916333812607, fake_22892621874966457, fake_3904253839317944, fake_29472601492574735, fake_024676284662448644 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_21671872625224164, fake_710917817143738, fake_8598320594975966, fake_10680570514782639, fake_6043153025341976 result, different session: fake_21671872625224164, fake_710917817143738, fake_8598320594975966, fake_10680570514782639, fake_6043153025341976 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_53628891148977, fake_8772114727642919, fake_14746746773086805, fake_5467292520664842, fake_13713767656011422 result, different session: fake_53628891148977, fake_8772114727642919, fake_14746746773086805, fake_5467292520664842, fake_13713767656011422 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_7859058264581851, fake_1426917823210878, fake_29586637778348623, fake_7056344232125058, fake_33839533003551336 result, different session: fake_7859058264581851, fake_1426917823210878, fake_29586637778348623, fake_7056344232125058, fake_33839533003551336 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_9421717309377466, fake_7175136476772122, fake_28507310773920147, fake_22171424041102283, fake_5799265828262203 result, different session: fake_9421717309377466, fake_7175136476772122, fake_28507310773920147, fake_22171424041102283, fake_5799265828262203 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_1703045549352038, fake_8144412834321997, fake_3414216269809123, fake_4778283270269461, fake_114778248464243 result, different session: fake_9576811532312544, fake_1349163582785622, fake_5811797878825196, fake_6140423108821433, fake_6399386688367785 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_48254395897071123, fake_3546191120578117, fake_19670238425576003, fake_13357071896757766, fake_359693219492486 result, different session: fake_48254395897071123, fake_3546191120578117, fake_19670238425576003, fake_13357071896757766, fake_359693219492486 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_6007078687912986, fake_6544194951867413, fake_7659278942354228, fake_156878165017305, fake_6742870453979135 result, different session: fake_6007078687912986, fake_6544194951867413, fake_7659278942354228, fake_156878165017305, fake_6742870453979135 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_6936124690751699, fake_15150921203306367, fake_6290935176388797, fake_2031880593644828, fake_9016129486556941 result, different session: fake_6936124690751699, fake_15150921203306367, fake_6290935176388797, fake_2031880593644828, fake_9016129486556941 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_022500084152515143, fake_9531070298067015, fake_3606057596875405, fake_14755095925745154 result, different session: fake_9719759077167673, fake_31860007151668834, fake_017216515576874203, fake_6798832640730876 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_22628626288771736, fake_22225647733652432, fake_36941117062056406, fake_6475542860828518, fake_010136477486583528 result, different session: fake_22628626288771736, fake_22225647733652432, fake_36941117062056406, fake_6475542860828518, fake_010136477486583528 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_48687238391464893, fake_18373254644717996, fake_2532042552183382, fake_856418159622643, fake_4220578350169242 result, different session: fake_48687238391464893, fake_18373254644717996, fake_2532042552183382, fake_856418159622643, fake_4220578350169242 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
favicon cache
A favicon is an icon that represents a website, typically shown in browser tab and bookmarks menu. If the favicon cache is not partitioned, it can be used to track users across websites. |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
fetch cache
When a resource is received via the Fetch API, it is frequently cached. That cache can potentially be abused for cross-site tracking. |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
font cache
Web fonts are sometimes stored in their own cache, which is vulnerable to being abused for cross-site tracking. |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
iframe cache
An iframe is an element in a web page than allows websites to embed a second web page. Caching of this web page could be abused for cross-site tracking. |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 2, 1, 1 unsupported: false, false, false, false, false passed: false, false, true, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
image cache
Caching of images in web browsers is a standard behavior. But if that cache leaks between websites, it can be abused for cross-site tracking. |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
indexedDB
The IndexedDB API exposes a transactional database to web pages. That database can be used to track users across websites, unless it is partitioned. |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_1p, d77fced8-9428-496f-9946-549bc356d246_1p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_1p, 1256fd40-841d-47a2-8902-ce5636a32cb3_1p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_1p result, different session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_1p, d77fced8-9428-496f-9946-549bc356d246_1p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_1p, 1256fd40-841d-47a2-8902-ce5636a32cb3_1p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p, be106815-df48-45c9-9d4a-86b9823a76db_1p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p, be106815-df48-45c9-9d4a-86b9823a76db_1p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p, e52cd2ae-6e45-4906-900c-b02f787f4589_1p, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b_1p, 32b124ca-4477-4984-b641-b772ba9d739c_1p result, different session: 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p, e52cd2ae-6e45-4906-900c-b02f787f4589_1p, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b_1p, 32b124ca-4477-4984-b641-b772ba9d739c_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: b0873046-aed6-464f-bc48-1c45525ef56d_1p, f76c7d52-c07b-4369-84d4-6d511639e60c_1p, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p, 6567a88a-f349-4734-8828-9cc0df7600bb_1p result, different session: b0873046-aed6-464f-bc48-1c45525ef56d_1p, f76c7d52-c07b-4369-84d4-6d511639e60c_1p, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p, 6567a88a-f349-4734-8828-9cc0df7600bb_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p, 4df32057-71ef-4c97-b4a9-375da39140da_1p, 5a39645b-74e0-456f-a064-66a4075a8239_1p, 00946081-6b17-4b36-9aa6-61d144addef7_1p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p, 4df32057-71ef-4c97-b4a9-375da39140da_1p, 5a39645b-74e0-456f-a064-66a4075a8239_1p, 00946081-6b17-4b36-9aa6-61d144addef7_1p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: a6911260-affb-4f85-b66e-6372edef8271_1p, f3f642e9-a578-4fd7-b323-71de0e1e5fda_1p, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_1p, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_1p, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_1p result, different session: a6911260-affb-4f85-b66e-6372edef8271_1p, f3f642e9-a578-4fd7-b323-71de0e1e5fda_1p, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_1p, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_1p, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_1p, 381bfe46-5daa-42c3-9e58-39d98058f186_1p, ddd70737-9afe-474e-ae84-787830e88cbc_1p, d6af2086-88f6-4f4f-9669-2d31e549a804_1p, 95431be4-0dbc-4181-a196-d3b6afacb47d_1p result, different session: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: faca3efe-63fa-40b1-960d-14241446e02b_1p, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_1p, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_1p, 73a700b0-d223-4f5a-9336-863c67ef6a20_1p, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_1p result, different session: faca3efe-63fa-40b1-960d-14241446e02b_1p, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_1p, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_1p, 73a700b0-d223-4f5a-9336-863c67ef6a20_1p, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p, 5d49d947-6006-4865-9c31-04b966b4ac61_1p, 87e46975-6855-4644-97bf-f9c66bae1455_1p, db0c6390-897f-4eb6-b734-977466b215b6_1p result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p, 5d49d947-6006-4865-9c31-04b966b4ac61_1p, 87e46975-6855-4644-97bf-f9c66bae1455_1p, db0c6390-897f-4eb6-b734-977466b215b6_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p result, different session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 77f9d876-5d2d-4776-824f-839b4afa98da_1p, 3959c542-32c6-4033-b316-37a1a8e480e0_1p, bec75a88-52bd-463a-b926-f1694cdddcaf_1p, 2239e757-c407-4798-907e-852d4ab1d41f_1p result, different session: undefined unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p, e8f74dec-686f-4084-a15c-80172d70e290_1p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p, e8f74dec-686f-4084-a15c-80172d70e290_1p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_1p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 975fde78-d933-4101-8f70-1fb2227ac766_1p, 03b8d7d5-b189-4156-8310-62787b519fe2_1p result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_1p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 975fde78-d933-4101-8f70-1fb2227ac766_1p, 03b8d7d5-b189-4156-8310-62787b519fe2_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
localStorage
The localStorage API gives websites access to a key-value database that will remain available across visits. If the localStorage API is not partitioned or blocked, it can also be used to track users across websites. |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_1p, d77fced8-9428-496f-9946-549bc356d246_1p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_1p, 1256fd40-841d-47a2-8902-ce5636a32cb3_1p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_1p result, different session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_1p, d77fced8-9428-496f-9946-549bc356d246_1p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_1p, 1256fd40-841d-47a2-8902-ce5636a32cb3_1p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p, be106815-df48-45c9-9d4a-86b9823a76db_1p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_1p, be106815-df48-45c9-9d4a-86b9823a76db_1p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_1p, aa902857-ae8c-4123-bd90-2f0901ab8e24_1p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p, e52cd2ae-6e45-4906-900c-b02f787f4589_1p, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b_1p, 32b124ca-4477-4984-b641-b772ba9d739c_1p result, different session: 2f149f9d-7d24-4463-baa9-df54b4e81d63_1p, e52cd2ae-6e45-4906-900c-b02f787f4589_1p, 7f3c6670-9f55-4ad6-b476-3acc68733c6a_1p, 002b7cd9-f04b-4f64-baa3-7482ebcb8d8b_1p, 32b124ca-4477-4984-b641-b772ba9d739c_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: b0873046-aed6-464f-bc48-1c45525ef56d_1p, f76c7d52-c07b-4369-84d4-6d511639e60c_1p, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p, 6567a88a-f349-4734-8828-9cc0df7600bb_1p result, different session: b0873046-aed6-464f-bc48-1c45525ef56d_1p, f76c7d52-c07b-4369-84d4-6d511639e60c_1p, 32f07353-227f-4e1d-948d-0e4bad5866b1_1p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_1p, 6567a88a-f349-4734-8828-9cc0df7600bb_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p, 4df32057-71ef-4c97-b4a9-375da39140da_1p, 5a39645b-74e0-456f-a064-66a4075a8239_1p, 00946081-6b17-4b36-9aa6-61d144addef7_1p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_1p, 4df32057-71ef-4c97-b4a9-375da39140da_1p, 5a39645b-74e0-456f-a064-66a4075a8239_1p, 00946081-6b17-4b36-9aa6-61d144addef7_1p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: a6911260-affb-4f85-b66e-6372edef8271_1p, f3f642e9-a578-4fd7-b323-71de0e1e5fda_1p, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_1p, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_1p, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_1p result, different session: a6911260-affb-4f85-b66e-6372edef8271_1p, f3f642e9-a578-4fd7-b323-71de0e1e5fda_1p, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_1p, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_1p, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_1p, 381bfe46-5daa-42c3-9e58-39d98058f186_1p, ddd70737-9afe-474e-ae84-787830e88cbc_1p, d6af2086-88f6-4f4f-9669-2d31e549a804_1p, 95431be4-0dbc-4181-a196-d3b6afacb47d_1p result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: faca3efe-63fa-40b1-960d-14241446e02b_1p, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_1p, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_1p, 73a700b0-d223-4f5a-9336-863c67ef6a20_1p, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_1p result, different session: faca3efe-63fa-40b1-960d-14241446e02b_1p, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_1p, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_1p, 73a700b0-d223-4f5a-9336-863c67ef6a20_1p, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p, 5d49d947-6006-4865-9c31-04b966b4ac61_1p, 87e46975-6855-4644-97bf-f9c66bae1455_1p, db0c6390-897f-4eb6-b734-977466b215b6_1p result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_1p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_1p, 5d49d947-6006-4865-9c31-04b966b4ac61_1p, 87e46975-6855-4644-97bf-f9c66bae1455_1p, db0c6390-897f-4eb6-b734-977466b215b6_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p result, different session: 08871018-9567-44a6-b124-5cb6fb4797cf_1p, ed296612-deee-4fff-b0e8-d7ee83e3b345_1p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_1p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_1p, 929477f2-6d6b-4b18-a642-f2ca892f3876_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 77f9d876-5d2d-4776-824f-839b4afa98da_1p, 3959c542-32c6-4033-b316-37a1a8e480e0_1p, bec75a88-52bd-463a-b926-f1694cdddcaf_1p, 2239e757-c407-4798-907e-852d4ab1d41f_1p result, different session: , , , unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p, e8f74dec-686f-4084-a15c-80172d70e290_1p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_1p, e8f74dec-686f-4084-a15c-80172d70e290_1p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_1p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_1p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_1p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 975fde78-d933-4101-8f70-1fb2227ac766_1p, 03b8d7d5-b189-4156-8310-62787b519fe2_1p result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_1p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_1p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_1p, 975fde78-d933-4101-8f70-1fb2227ac766_1p, 03b8d7d5-b189-4156-8310-62787b519fe2_1p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
prefetch cache
A <link rel='prefetch'...> suggests to browsers they should fetch a resource ahead of time and cache it. But if browsers don't partition this cache, it can be used to track users across websites. |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
script cache
Caching of scripts in web browsers is a standard behavior. But if that cache leaks between websites, it can be abused for cross-site tracking. |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
XMLHttpRequest cache
Similar to the newer Fetch API, any resource received may be cached by the browser. The cache is potentially vulnerable to cross-site tracking attack. |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
Cross-session third-party tracking testsWhich browsers prevent third-party trackers from tracking you across browser sessions?
A common vulnerability of web browsers is that they allow third-party trackers to 'tag' your browser with some tracking data. This tag can be used to re-identify you when you return to a website you visited before. This category of leaks can be prevented by browser if they clean or isolate data between browser sessions. (In cases where a user has logged into a website or entered detailed information, it may be justifiable for a browser to retain information across sessions. These tests check when no such justification exists: when you have entered no significant information into a website, will the browser still retain data that allows you to be tracked across sessions?) |
|||||||||||||
Alt-Svc
Alt-Svc allows the server to indicate to the web browser that a resource should be loaded on a different server. Because this is a persistent setting, it could be used to track users across websites if it is not correctly partitioned. |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h2, h2, h2, h2, h2 result, different session: h2, h2, h2, h2, h2 unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h3, h2, h3, h2, h3 unsupported: false, false, false, false, false passed: false, true, false, true, false test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h3, h2, h3, h2, h3 unsupported: false, false, false, false, false passed: false, true, false, true, false test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h2, h2, h2, h2, h2 result, different session: h2, h2, h2, h2, h2 unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h2, h2, h2, h2 result, different session: h2, h2, h2, h2 unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async () => { // Clear Alt-Svc caching first. let responseText = ""; for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/clear"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after clear:", responseText); // Store "h3" state in Alt-Svc cache for (let i = 0; i < 3; ++i) { await fetch(altSvcOrigin + "/set"); await sleepMs(100); } responseText = await fetchText(altSvcOrigin + "/protocol"); console.log("after set:", responseText); } read: async () => { const protocol = await fetchText(altSvcOrigin + "/protocol"); if ((new URL(location)).searchParams.get("thirdparty") === "same") { if (protocol !== "h3") { throw new Error("Unsupported"); } } return protocol; } result, same session: h3, h3, h3, h3, h3 result, different session: h2, h2, h2, h2, h2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
CacheStorage
The Cache API is a content storage mechanism originally introduced to support ServiceWorkers. If the same Cache object is accessible to multiple websites, it can be abused to track users. |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_3p, d77fced8-9428-496f-9946-549bc356d246_3p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_3p, 1256fd40-841d-47a2-8902-ce5636a32cb3_3p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_3p result, different session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_3p, d77fced8-9428-496f-9946-549bc356d246_3p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_3p, 1256fd40-841d-47a2-8902-ce5636a32cb3_3p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p result, different session: c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p, c745bf91-cf98-4e5f-8375-d1de83cf19d5_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent. result, different session: Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent., Error: Failed to execute 'open' on 'CacheStorage': An attempt was made to break through the security policy of the user agent. unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p result, different session: 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p, 1a5b5a6f-5aeb-49ba-8577-c852ce8b48e5_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p result, different session: 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p, 4aca6bfb-ecb4-47d0-bce6-bb64559cf8a0_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 6b80d03e-105e-4201-b76d-0596f346aaac_3p, 6b80d03e-105e-4201-b76d-0596f346aaac_3p, 6b80d03e-105e-4201-b76d-0596f346aaac_3p, 6b80d03e-105e-4201-b76d-0596f346aaac_3p, 6b80d03e-105e-4201-b76d-0596f346aaac_3p result, different session: 6b80d03e-105e-4201-b76d-0596f346aaac_3p, 6b80d03e-105e-4201-b76d-0596f346aaac_3p, 6b80d03e-105e-4201-b76d-0596f346aaac_3p, 6b80d03e-105e-4201-b76d-0596f346aaac_3p, 6b80d03e-105e-4201-b76d-0596f346aaac_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_3p, 381bfe46-5daa-42c3-9e58-39d98058f186_3p, ddd70737-9afe-474e-ae84-787830e88cbc_3p, d6af2086-88f6-4f4f-9669-2d31e549a804_3p, 95431be4-0dbc-4181-a196-d3b6afacb47d_3p result, different session: Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined, Error: cacheKeys[0] is undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: ec26e749-9cec-4f7a-98e6-641c090e7817_3p, ec26e749-9cec-4f7a-98e6-641c090e7817_3p, ec26e749-9cec-4f7a-98e6-641c090e7817_3p, ec26e749-9cec-4f7a-98e6-641c090e7817_3p, ec26e749-9cec-4f7a-98e6-641c090e7817_3p result, different session: ec26e749-9cec-4f7a-98e6-641c090e7817_3p, ec26e749-9cec-4f7a-98e6-641c090e7817_3p, ec26e749-9cec-4f7a-98e6-641c090e7817_3p, ec26e749-9cec-4f7a-98e6-641c090e7817_3p, ec26e749-9cec-4f7a-98e6-641c090e7817_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 1a184507-9b7a-45eb-a7c2-93b91227080c_3p, 1a184507-9b7a-45eb-a7c2-93b91227080c_3p, 1a184507-9b7a-45eb-a7c2-93b91227080c_3p, 1a184507-9b7a-45eb-a7c2-93b91227080c_3p, 1a184507-9b7a-45eb-a7c2-93b91227080c_3p result, different session: 1a184507-9b7a-45eb-a7c2-93b91227080c_3p, 1a184507-9b7a-45eb-a7c2-93b91227080c_3p, 1a184507-9b7a-45eb-a7c2-93b91227080c_3p, 1a184507-9b7a-45eb-a7c2-93b91227080c_3p, 1a184507-9b7a-45eb-a7c2-93b91227080c_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 62cb741f-c8c7-452b-a081-453be7d8a485_3p, 62cb741f-c8c7-452b-a081-453be7d8a485_3p, 62cb741f-c8c7-452b-a081-453be7d8a485_3p, 62cb741f-c8c7-452b-a081-453be7d8a485_3p, 62cb741f-c8c7-452b-a081-453be7d8a485_3p result, different session: 62cb741f-c8c7-452b-a081-453be7d8a485_3p, 62cb741f-c8c7-452b-a081-453be7d8a485_3p, 62cb741f-c8c7-452b-a081-453be7d8a485_3p, 62cb741f-c8c7-452b-a081-453be7d8a485_3p, 62cb741f-c8c7-452b-a081-453be7d8a485_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. result, different session: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p result, different session: 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p, 1af58a1e-55c5-4125-ba6b-5729d21fd23c_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { try { let cache = await caches.open("supercookies"); cache.addAll([`test.css?key=${key}`]); } catch (e) { throw new Error("Unsupported"); } } read: async () => { let cache = await caches.open("supercookies"); let cacheKeys = await cache.keys(); let url = cacheKeys[0].url; return (new URL(url)).searchParams.get("key"); } result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_3p, df04981a-509a-43d2-bd50-07e15e2191a0_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 03b8d7d5-b189-4156-8310-62787b519fe2_3p result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_3p, df04981a-509a-43d2-bd50-07e15e2191a0_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 03b8d7d5-b189-4156-8310-62787b519fe2_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
cookie (HTTP)
The cookie, first introduced by Netscape in 1994, is a small amount of data stored by your browser on a website's behalf. It has legitimate uses, but it is also the classic cross-site tracking mechanism, and today still the most popular method of tracking users across websites. Browsers can stop cookies from being used for cross-site tracking by either blocking or partitioning them. |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_3p_http, d77fced8-9428-496f-9946-549bc356d246_3p_http, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_3p_http, 1256fd40-841d-47a2-8902-ce5636a32cb3_3p_http, ce2b00b3-8519-499e-967c-ea73aad6dbb1_3p_http result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p_http, be106815-df48-45c9-9d4a-86b9823a76db_3p_http, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p_http, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p_http, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p_http result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p_http, be106815-df48-45c9-9d4a-86b9823a76db_3p_http, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p_http, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p_http, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: , , , , result, different session: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: , , , , result, different session: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p_http, 4df32057-71ef-4c97-b4a9-375da39140da_3p_http, 5a39645b-74e0-456f-a064-66a4075a8239_3p_http, 00946081-6b17-4b36-9aa6-61d144addef7_3p_http, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p_http result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p_http, 4df32057-71ef-4c97-b4a9-375da39140da_3p_http, 5a39645b-74e0-456f-a064-66a4075a8239_3p_http, 00946081-6b17-4b36-9aa6-61d144addef7_3p_http, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: a6911260-affb-4f85-b66e-6372edef8271_3p_http, f3f642e9-a578-4fd7-b323-71de0e1e5fda_3p_http, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_3p_http, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_3p_http, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_3p_http result, different session: a6911260-affb-4f85-b66e-6372edef8271_3p_http, f3f642e9-a578-4fd7-b323-71de0e1e5fda_3p_http, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_3p_http, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_3p_http, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_3p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_3p_http, 381bfe46-5daa-42c3-9e58-39d98058f186_3p_http, ddd70737-9afe-474e-ae84-787830e88cbc_3p_http, d6af2086-88f6-4f4f-9669-2d31e549a804_3p_http, 95431be4-0dbc-4181-a196-d3b6afacb47d_3p_http result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: faca3efe-63fa-40b1-960d-14241446e02b_3p_http, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_3p_http, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_3p_http, 73a700b0-d223-4f5a-9336-863c67ef6a20_3p_http, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_3p_http result, different session: faca3efe-63fa-40b1-960d-14241446e02b_3p_http, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_3p_http, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_3p_http, 73a700b0-d223-4f5a-9336-863c67ef6a20_3p_http, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_3p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p_http, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p_http, 5d49d947-6006-4865-9c31-04b966b4ac61_3p_http, 87e46975-6855-4644-97bf-f9c66bae1455_3p_http, db0c6390-897f-4eb6-b734-977466b215b6_3p_http result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p_http, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p_http, 5d49d947-6006-4865-9c31-04b966b4ac61_3p_http, 87e46975-6855-4644-97bf-f9c66bae1455_3p_http, db0c6390-897f-4eb6-b734-977466b215b6_3p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: , , , , result, different session: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: , , , result, different session: , , , unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p_http, e8f74dec-686f-4084-a15c-80172d70e290_3p_http, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p_http, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p_http, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p_http result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p_http, e8f74dec-686f-4084-a15c-80172d70e290_3p_http, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p_http, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p_http, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { // Request a page that will send an HTTPOnly 'set-cookie' response header with secret value. await fetch(`${baseURI}cookie?secret=${secret}_http`); } read: async () => { // Test if we now send a requests with a 'cookie' header containing the secret. let response = await fetch(`${baseURI}headers`); let cookie = (await response.json())["cookie"]; return cookie ? cookie.match(/secret=([\w-]+)/)[1]: null; } result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_3p_http, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p_http, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p_http, 975fde78-d933-4101-8f70-1fb2227ac766_3p_http, 03b8d7d5-b189-4156-8310-62787b519fe2_3p_http result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_3p_http, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p_http, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p_http, 975fde78-d933-4101-8f70-1fb2227ac766_3p_http, 03b8d7d5-b189-4156-8310-62787b519fe2_3p_http unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
cookie (JS)
The cookie, first introduced by Netscape in 1994, is a small amount of data stored by your browser on a website's behalf. It has legitimate uses, but it is also the classic cross-site tracking mechanism, and today still the most popular method of tracking users across websites. Browsers can stop cookies from being used for cross-site tracking by either blocking or partitioning them. |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_3p_js, d77fced8-9428-496f-9946-549bc356d246_3p_js, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_3p_js, 1256fd40-841d-47a2-8902-ce5636a32cb3_3p_js, ce2b00b3-8519-499e-967c-ea73aad6dbb1_3p_js result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p_js, be106815-df48-45c9-9d4a-86b9823a76db_3p_js, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p_js, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p_js, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p_js result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p_js, be106815-df48-45c9-9d4a-86b9823a76db_3p_js, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p_js, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p_js, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: , , , , result, different session: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: , , , , result, different session: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p_js, 4df32057-71ef-4c97-b4a9-375da39140da_3p_js, 5a39645b-74e0-456f-a064-66a4075a8239_3p_js, 00946081-6b17-4b36-9aa6-61d144addef7_3p_js, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p_js result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p_js, 4df32057-71ef-4c97-b4a9-375da39140da_3p_js, 5a39645b-74e0-456f-a064-66a4075a8239_3p_js, 00946081-6b17-4b36-9aa6-61d144addef7_3p_js, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: a6911260-affb-4f85-b66e-6372edef8271_3p_js, f3f642e9-a578-4fd7-b323-71de0e1e5fda_3p_js, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_3p_js, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_3p_js, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_3p_js result, different session: a6911260-affb-4f85-b66e-6372edef8271_3p_js, f3f642e9-a578-4fd7-b323-71de0e1e5fda_3p_js, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_3p_js, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_3p_js, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_3p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_3p_js, 381bfe46-5daa-42c3-9e58-39d98058f186_3p_js, ddd70737-9afe-474e-ae84-787830e88cbc_3p_js, d6af2086-88f6-4f4f-9669-2d31e549a804_3p_js, 95431be4-0dbc-4181-a196-d3b6afacb47d_3p_js result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: faca3efe-63fa-40b1-960d-14241446e02b_3p_js, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_3p_js, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_3p_js, 73a700b0-d223-4f5a-9336-863c67ef6a20_3p_js, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_3p_js result, different session: faca3efe-63fa-40b1-960d-14241446e02b_3p_js, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_3p_js, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_3p_js, 73a700b0-d223-4f5a-9336-863c67ef6a20_3p_js, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_3p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p_js, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p_js, 5d49d947-6006-4865-9c31-04b966b4ac61_3p_js, 87e46975-6855-4644-97bf-f9c66bae1455_3p_js, db0c6390-897f-4eb6-b734-977466b215b6_3p_js result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p_js, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p_js, 5d49d947-6006-4865-9c31-04b966b4ac61_3p_js, 87e46975-6855-4644-97bf-f9c66bae1455_3p_js, db0c6390-897f-4eb6-b734-977466b215b6_3p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: , , , , result, different session: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: , , , result, different session: , , , unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p_js, e8f74dec-686f-4084-a15c-80172d70e290_3p_js, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p_js, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p_js, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p_js result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p_js, e8f74dec-686f-4084-a15c-80172d70e290_3p_js, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p_js, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p_js, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => { document.cookie = `secret=${secret}_js; max-age=3600; SameSite=None; Secure`; } read: () => document.cookie ? document.cookie.match(/secret=([\w-]+)/)[1] : null result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_3p_js, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p_js, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p_js, 975fde78-d933-4101-8f70-1fb2227ac766_3p_js, 03b8d7d5-b189-4156-8310-62787b519fe2_3p_js result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_3p_js, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p_js, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p_js, 975fde78-d933-4101-8f70-1fb2227ac766_3p_js, 03b8d7d5-b189-4156-8310-62787b519fe2_3p_js unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
CookieStore
The Cookie Store API is an alternative asynchronous API for managing cookies, supported by some browsers. |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_3p, d77fced8-9428-496f-9946-549bc356d246_3p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_3p, 1256fd40-841d-47a2-8902-ce5636a32cb3_3p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_3p result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p, be106815-df48-45c9-9d4a-86b9823a76db_3p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p, be106815-df48-45c9-9d4a-86b9823a76db_3p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: , , , , result, different session: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: , , , , result, different session: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p, 4df32057-71ef-4c97-b4a9-375da39140da_3p, 5a39645b-74e0-456f-a064-66a4075a8239_3p, 00946081-6b17-4b36-9aa6-61d144addef7_3p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p, 4df32057-71ef-4c97-b4a9-375da39140da_3p, 5a39645b-74e0-456f-a064-66a4075a8239_3p, 00946081-6b17-4b36-9aa6-61d144addef7_3p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p, 5d49d947-6006-4865-9c31-04b966b4ac61_3p, 87e46975-6855-4644-97bf-f9c66bae1455_3p, db0c6390-897f-4eb6-b734-977466b215b6_3p result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p, 5d49d947-6006-4865-9c31-04b966b4ac61_3p, 87e46975-6855-4644-97bf-f9c66bae1455_3p, db0c6390-897f-4eb6-b734-977466b215b6_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: , , , , result, different session: , , , , unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported result, different session: Error: Unsupported, Error: Unsupported, Error: Unsupported, Error: Unsupported unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p, e8f74dec-686f-4084-a15c-80172d70e290_3p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p, e8f74dec-686f-4084-a15c-80172d70e290_3p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (data) => { const msPerHour = 60 * 60 * 1000; if (!window.cookieStore) { throw new Error("Unsupported"); } window.cookieStore.set({ name: "partition_test", value: data, expires: Date.now() + msPerHour, sameSite: "none" }); } read: async () => { if (!window.cookieStore) { throw new Error("Unsupported"); } const cookie = await window.cookieStore.get("partition_test"); if (!cookie) { return null; } return cookie.value; } result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_3p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 975fde78-d933-4101-8f70-1fb2227ac766_3p, 03b8d7d5-b189-4156-8310-62787b519fe2_3p result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_3p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 975fde78-d933-4101-8f70-1fb2227ac766_3p, 03b8d7d5-b189-4156-8310-62787b519fe2_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
CSS cache
CSS stylesheets are cached, and if that cache is shared between websites, it can be used to track users across sites. |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_4015961839067972, fake_018625707385958368, fake_13069400410884624, fake_6121695569642833, fake_9987940041489474 result, different session: fake_4015961839067972, fake_018625707385958368, fake_13069400410884624, fake_6121695569642833, fake_9987940041489474 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_8056509640582625, fake_02334788830844814, fake_3683990825691479, fake_42843389729303993, fake_8906451010129981 result, different session: fake_8056509640582625, fake_02334788830844814, fake_3683990825691479, fake_42843389729303993, fake_8906451010129981 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_47989478614095904, fake_09377383066983125, fake_5986551315204294, fake_8915146884738125, fake_7891778943214562 result, different session: fake_47989478614095904, fake_09377383066983125, fake_5986551315204294, fake_8915146884738125, fake_7891778943214562 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_39386609635980085, fake_11260168550726668, fake_4649016107628092, fake_026616223689429175, fake_20852627583687378 result, different session: fake_39386609635980085, fake_11260168550726668, fake_4649016107628092, fake_026616223689429175, fake_20852627583687378 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_3132384404151487, fake_6787884303643399, fake_18441853259329322, fake_9469768796467581, fake_2845344472744398 result, different session: fake_3132384404151487, fake_6787884303643399, fake_18441853259329322, fake_9469768796467581, fake_2845344472744398 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_12962045227270402, fake_42499493744408, fake_4121703954305753, fake_8452381393792636, fake_7487831650173715 result, different session: fake_12962045227270402, fake_42499493744408, fake_4121703954305753, fake_8452381393792636, fake_7487831650173715 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_8588114239120033, fake_3667862941851041, fake_2982730200073347, fake_8640736095591948, fake_19112289596439025 result, different session: fake_08685718779129137, fake_5145080155562547, fake_6588397862310729, fake_24010009788338493, fake_11617817738938485 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_9011995546135225, fake_6801301514926088, fake_7303633183982572, fake_691451294517099, fake_7850834578211483 result, different session: fake_9011995546135225, fake_6801301514926088, fake_7303633183982572, fake_691451294517099, fake_7850834578211483 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_8818980616148848, fake_7187179966776356, fake_8837898239336326, fake_6492393335480138, fake_9141327383860403 result, different session: fake_8818980616148848, fake_7187179966776356, fake_8837898239336326, fake_6492393335480138, fake_9141327383860403 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_8275182768695466, fake_9985751907192331, fake_8668479499818034, fake_77722830637697, fake_6208291301202815 result, different session: fake_8275182768695466, fake_9985751907192331, fake_8668479499818034, fake_77722830637697, fake_6208291301202815 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_36536639257103776, fake_8723615251783545, fake_8935354529474759, fake_32019139282792075 result, different session: fake_11333742984007622, fake_7251643636437739, fake_756193932836406, fake_7340723051782301 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_1219970646394728, fake_9502012395525621, fake_16682246406239942, fake_4192672245952014, fake_002656534160156321 result, different session: fake_1219970646394728, fake_9502012395525621, fake_16682246406239942, fake_4192672245952014, fake_002656534160156321 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return key; } read: async (key) => { const href = testURI("resource", "css", key); const head = document.getElementsByTagName("head")[0]; head.innerHTML += `<link type="text/css" rel="stylesheet" href="${href}">`; const testElement = document.querySelector("#css"); let fontFamily; while (true) { await sleepMs(100); fontFamily = getComputedStyle(testElement).fontFamily; if (fontFamily.startsWith("fake")) { break; } } console.log(fontFamily); return fontFamily; } result, same session: fake_5174871448030702, fake_050088933556277526, fake_9352441476974538, fake_22139572630856663, fake_24411847408838172 result, different session: fake_5174871448030702, fake_050088933556277526, fake_9352441476974538, fake_22139572630856663, fake_24411847408838172 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
favicon cache
A favicon is an icon that represents a website, typically shown in browser tab and bookmarks menu. If the favicon cache is not partitioned, it can be used to track users across websites. |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => key read: async (key) => { // Wait for the favicon to load (defined in supercookies.html) await sleepMs(2000); let response = await fetch( testURI("ctr", "favicon", key), {"cache": "reload"}); let count = (await response.text()).trim(); if (count === "0") { throw new Error("No requests received"); } return count; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
fetch cache
When a resource is received via the Fetch API, it is frequently cached. That cache can potentially be abused for cross-site tracking. |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); return key; } read: async (key) => { let response = await fetch(testURI("resource", "fetch", key), {cache: "force-cache"}); let countResponse = await fetch(testURI("ctr", "fetch", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
font cache
Web fonts are sometimes stored in their own cache, which is vulnerable to being abused for cross-site tracking. |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } body { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); return key; } read: async (key) => { const text = document.createElement("span"); text.id = "text"; text.innerText = "test"; document.body.appendChild(text); const originalWidth = text.getBoundingClientRect().width; let style = document.createElement("style"); style.type='text/css'; let fontURI = testURI("resource", "font", key); style.innerHTML = `@font-face {font-family: "myFont"; src: url("${fontURI}"); } #text { font-family: "myFont" }`; document.getElementsByTagName("head")[0].appendChild(style); let newWidth; do { await sleepMs(100); newWidth = text.getBoundingClientRect().width; } while (newWidth < 0 || newWidth === originalWidth) let response = await fetch( testURI("ctr", "font", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
iframe cache
An iframe is an element in a web page than allows websites to embed a second web page. Caching of this web page could be abused for cross-site tracking. |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.addEventListener("load", () => resolve(key), {once: true}); iframe.src = testURI("resource", "page", key); }) read: async (key) => { let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let iframeLoadPromise = new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, {once: true}); }); let address = testURI("resource", "page", key); iframe.src = address; await iframeLoadPromise; let response = await fetch( testURI("ctr", "page", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
image cache
Caching of images in web browsers is a standard behavior. But if that cache leaks between websites, it can be abused for cross-site tracking. |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let img = document.createElement("img"); document.body.appendChild(img); img.addEventListener("load", () => resolve(key), {once: true}); img.src = testURI("resource", "image", key); }) read: async (key) => { let img = document.createElement("img"); document.body.appendChild(img); let imgLoadPromise = new Promise((resolve, reject) => { img.addEventListener("load", resolve, {once: true}); }); img.src = testURI("resource", "image", key); await imgLoadPromise; let response = await fetch( testURI("ctr", "image", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
indexedDB
The IndexedDB API exposes a transactional database to web pages. That database can be used to track users across websites, unless it is partitioned. |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_3p, d77fced8-9428-496f-9946-549bc356d246_3p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_3p, 1256fd40-841d-47a2-8902-ce5636a32cb3_3p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_3p result, different session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_3p, d77fced8-9428-496f-9946-549bc356d246_3p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_3p, 1256fd40-841d-47a2-8902-ce5636a32cb3_3p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p, be106815-df48-45c9-9d4a-86b9823a76db_3p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p, be106815-df48-45c9-9d4a-86b9823a76db_3p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: Error: The user denied permission to access the database., Error: The user denied permission to access the database., Error: The user denied permission to access the database., Error: The user denied permission to access the database., Error: The user denied permission to access the database. result, different session: Error: The user denied permission to access the database., Error: The user denied permission to access the database., Error: The user denied permission to access the database., Error: The user denied permission to access the database., Error: The user denied permission to access the database. unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: b0873046-aed6-464f-bc48-1c45525ef56d_3p, f76c7d52-c07b-4369-84d4-6d511639e60c_3p, 32f07353-227f-4e1d-948d-0e4bad5866b1_3p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_3p, 6567a88a-f349-4734-8828-9cc0df7600bb_3p result, different session: b0873046-aed6-464f-bc48-1c45525ef56d_3p, f76c7d52-c07b-4369-84d4-6d511639e60c_3p, 32f07353-227f-4e1d-948d-0e4bad5866b1_3p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_3p, 6567a88a-f349-4734-8828-9cc0df7600bb_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p, 4df32057-71ef-4c97-b4a9-375da39140da_3p, 5a39645b-74e0-456f-a064-66a4075a8239_3p, 00946081-6b17-4b36-9aa6-61d144addef7_3p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p, 4df32057-71ef-4c97-b4a9-375da39140da_3p, 5a39645b-74e0-456f-a064-66a4075a8239_3p, 00946081-6b17-4b36-9aa6-61d144addef7_3p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: a6911260-affb-4f85-b66e-6372edef8271_3p, f3f642e9-a578-4fd7-b323-71de0e1e5fda_3p, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_3p, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_3p, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_3p result, different session: a6911260-affb-4f85-b66e-6372edef8271_3p, f3f642e9-a578-4fd7-b323-71de0e1e5fda_3p, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_3p, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_3p, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_3p, 381bfe46-5daa-42c3-9e58-39d98058f186_3p, ddd70737-9afe-474e-ae84-787830e88cbc_3p, d6af2086-88f6-4f4f-9669-2d31e549a804_3p, 95431be4-0dbc-4181-a196-d3b6afacb47d_3p result, different session: undefined unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: faca3efe-63fa-40b1-960d-14241446e02b_3p, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_3p, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_3p, 73a700b0-d223-4f5a-9336-863c67ef6a20_3p, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_3p result, different session: faca3efe-63fa-40b1-960d-14241446e02b_3p, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_3p, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_3p, 73a700b0-d223-4f5a-9336-863c67ef6a20_3p, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p, 5d49d947-6006-4865-9c31-04b966b4ac61_3p, 87e46975-6855-4644-97bf-f9c66bae1455_3p, db0c6390-897f-4eb6-b734-977466b215b6_3p result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p, 5d49d947-6006-4865-9c31-04b966b4ac61_3p, 87e46975-6855-4644-97bf-f9c66bae1455_3p, db0c6390-897f-4eb6-b734-977466b215b6_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 08871018-9567-44a6-b124-5cb6fb4797cf_3p, ed296612-deee-4fff-b0e8-d7ee83e3b345_3p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_3p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_3p, 929477f2-6d6b-4b18-a642-f2ca892f3876_3p result, different session: 08871018-9567-44a6-b124-5cb6fb4797cf_3p, ed296612-deee-4fff-b0e8-d7ee83e3b345_3p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_3p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_3p, 929477f2-6d6b-4b18-a642-f2ca892f3876_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. result, different session: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p, e8f74dec-686f-4084-a15c-80172d70e290_3p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p, e8f74dec-686f-4084-a15c-80172d70e290_3p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (secret) => { try { return await IdbKeyVal.set("secret", secret); } catch (e) { throw new Error("Unsupported"); } } read: () => IdbKeyVal.get("secret") result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_3p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 975fde78-d933-4101-8f70-1fb2227ac766_3p, 03b8d7d5-b189-4156-8310-62787b519fe2_3p result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_3p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 975fde78-d933-4101-8f70-1fb2227ac766_3p, 03b8d7d5-b189-4156-8310-62787b519fe2_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
localStorage
The localStorage API gives websites access to a key-value database that will remain available across visits. If the localStorage API is not partitioned or blocked, it can also be used to track users across websites. |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_3p, d77fced8-9428-496f-9946-549bc356d246_3p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_3p, 1256fd40-841d-47a2-8902-ce5636a32cb3_3p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_3p result, different session: 8c65c2d7-9776-4410-ae6f-8e0a2abe70d1_3p, d77fced8-9428-496f-9946-549bc356d246_3p, d806ff56-0f9b-4bbb-bb05-9fa67a08c877_3p, 1256fd40-841d-47a2-8902-ce5636a32cb3_3p, ce2b00b3-8519-499e-967c-ea73aad6dbb1_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p, be106815-df48-45c9-9d4a-86b9823a76db_3p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p result, different session: 91872272-1110-44b8-bb8a-fefcdca4198f_3p, be106815-df48-45c9-9d4a-86b9823a76db_3p, 3d351c8a-a896-428b-bb2d-cb2f2838d223_3p, aa902857-ae8c-4123-bd90-2f0901ab8e24_3p, 93cc4a3a-101b-4f14-b1d9-8bcf261b4f4d_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document. result, different session: Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document., Error: Failed to read the 'localStorage' property from 'Window': Access is denied for this document. unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: b0873046-aed6-464f-bc48-1c45525ef56d_3p, f76c7d52-c07b-4369-84d4-6d511639e60c_3p, 32f07353-227f-4e1d-948d-0e4bad5866b1_3p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_3p, 6567a88a-f349-4734-8828-9cc0df7600bb_3p result, different session: b0873046-aed6-464f-bc48-1c45525ef56d_3p, f76c7d52-c07b-4369-84d4-6d511639e60c_3p, 32f07353-227f-4e1d-948d-0e4bad5866b1_3p, fb89b2ee-5914-4ee5-ae26-30bc3301d983_3p, 6567a88a-f349-4734-8828-9cc0df7600bb_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p, 4df32057-71ef-4c97-b4a9-375da39140da_3p, 5a39645b-74e0-456f-a064-66a4075a8239_3p, 00946081-6b17-4b36-9aa6-61d144addef7_3p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p result, different session: 60671eda-690d-4a9e-9474-b59d33c8ed2d_3p, 4df32057-71ef-4c97-b4a9-375da39140da_3p, 5a39645b-74e0-456f-a064-66a4075a8239_3p, 00946081-6b17-4b36-9aa6-61d144addef7_3p, 2ad71704-a05c-4a9d-9cf9-57f8579cbf04_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: a6911260-affb-4f85-b66e-6372edef8271_3p, f3f642e9-a578-4fd7-b323-71de0e1e5fda_3p, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_3p, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_3p, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_3p result, different session: a6911260-affb-4f85-b66e-6372edef8271_3p, f3f642e9-a578-4fd7-b323-71de0e1e5fda_3p, 28d15258-7b1e-43c2-b863-a66c4e6d1a9d_3p, f502a6e1-0f6d-451e-9a0a-9ae88e34ae46_3p, 40b7778f-bf11-4c7a-a4d3-3315e060c7b1_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: cb2b3139-17be-441a-beaa-850c1130ce80_3p, 381bfe46-5daa-42c3-9e58-39d98058f186_3p, ddd70737-9afe-474e-ae84-787830e88cbc_3p, d6af2086-88f6-4f4f-9669-2d31e549a804_3p, 95431be4-0dbc-4181-a196-d3b6afacb47d_3p result, different session: , , , , unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: faca3efe-63fa-40b1-960d-14241446e02b_3p, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_3p, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_3p, 73a700b0-d223-4f5a-9336-863c67ef6a20_3p, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_3p result, different session: faca3efe-63fa-40b1-960d-14241446e02b_3p, 2a2e037d-1d56-4d32-8402-d4b28afa8eac_3p, 0eb26e1b-7201-4d84-aea1-8943179ccfc1_3p, 73a700b0-d223-4f5a-9336-863c67ef6a20_3p, 2a6798d9-a24d-470e-8d91-53d5e7f0d445_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p, 5d49d947-6006-4865-9c31-04b966b4ac61_3p, 87e46975-6855-4644-97bf-f9c66bae1455_3p, db0c6390-897f-4eb6-b734-977466b215b6_3p result, different session: 8a59cde4-6473-44da-b170-f66c57b8df4a_3p, 56ab2bad-36f1-4f5d-9ceb-afea357a6e20_3p, 5d49d947-6006-4865-9c31-04b966b4ac61_3p, 87e46975-6855-4644-97bf-f9c66bae1455_3p, db0c6390-897f-4eb6-b734-977466b215b6_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 08871018-9567-44a6-b124-5cb6fb4797cf_3p, ed296612-deee-4fff-b0e8-d7ee83e3b345_3p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_3p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_3p, 929477f2-6d6b-4b18-a642-f2ca892f3876_3p result, different session: 08871018-9567-44a6-b124-5cb6fb4797cf_3p, ed296612-deee-4fff-b0e8-d7ee83e3b345_3p, f45c8b38-f782-4290-a7cc-7c031ed1bd5e_3p, 4ee8618c-dd14-47c0-ad13-50e8f625e228_3p, 929477f2-6d6b-4b18-a642-f2ca892f3876_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. result, different session: Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure., Error: The operation is insecure. unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p, e8f74dec-686f-4084-a15c-80172d70e290_3p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p result, different session: 91556de9-f4d0-4720-a0eb-89b93d8bbc62_3p, e8f74dec-686f-4084-a15c-80172d70e290_3p, c7af78eb-b2be-4edb-a01f-c5e80885c91b_3p, bfa2edb1-7890-44d5-90e0-94ac0fef762a_3p, 1e2332aa-e33b-49d1-b45e-4202d0db4096_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (secret) => localStorage.setItem("secret", secret) read: () => localStorage.getItem("secret") result, same session: df04981a-509a-43d2-bd50-07e15e2191a0_3p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 975fde78-d933-4101-8f70-1fb2227ac766_3p, 03b8d7d5-b189-4156-8310-62787b519fe2_3p result, different session: df04981a-509a-43d2-bd50-07e15e2191a0_3p, e9c7d7a8-cfd7-46b4-9c28-29d250862dd3_3p, 4a8ab582-40cd-40e7-b9b8-260ae2bee808_3p, 975fde78-d933-4101-8f70-1fb2227ac766_3p, 03b8d7d5-b189-4156-8310-62787b519fe2_3p unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
prefetch cache
A <link rel='prefetch'...> suggests to browsers they should fetch a resource ahead of time and cache it. But if browsers don't partition this cache, it can be used to track users across websites. |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true, true passed: undefined test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received result, different session: Error: No requests received, Error: No requests received, Error: No requests received, Error: No requests received unsupported: true, true, true, true passed: undefined test failed: false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); return key; } read: async (key) => { let link = document.createElement("link"); link.rel = "prefetch"; link.href = testURI("resource", "prefetch", key); document.getElementsByTagName("head")[0].appendChild(link); await sleepMs(500); let response = await fetch( testURI("ctr", "prefetch", key), {"cache": "reload"}); let countString = (await response.text()).trim(); if (parseInt(countString) === 0) { throw new Error("No requests received"); } return countString; } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
script cache
Caching of scripts in web browsers is a standard behavior. But if that cache leaks between websites, it can be abused for cross-site tracking. |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: (key) => new Promise((resolve, reject) => { let script = document.createElement("script"); document.body.appendChild(script); script.addEventListener("load", () => resolve(key), {once: true}); script.src = testURI("resource", "script", key); }) read: async (key) => { let script = document.createElement("script"); document.body.appendChild(script); let scriptLoadPromise = new Promise((resolve, reject) => { script.addEventListener("load", resolve, {once: true}); }); script.src = testURI("resource", "script", key); await scriptLoadPromise; let response = await fetch( testURI("ctr", "script", key), {"cache": "reload"}); return (await response.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
XMLHttpRequest cache
Similar to the newer Fetch API, any resource received may be cached by the browser. The cache is potentially vulnerable to cross-site tracking attack. |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 2, 2, 2, 2, 2 unsupported: false, false, false, false, false passed: true, true, true, true, true test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1 result, different session: 2, 2, 2, 2 unsupported: false, false, false, false passed: true, true, true, true test failed: false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |
write: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; return key; } read: async (key) => { const req = new XMLHttpRequest(); const loadPromise = new Promise(resolve => req.addEventListener("load", resolve)); req.open("GET", testURI("resource", "xhr", key)); req.send(); await loadPromise; let countResponse = await fetch(testURI("ctr", "xhr", key), {cache: "reload"}); return (await countResponse.text()).trim(); } result, same session: 1, 1, 1, 1, 1 result, different session: 1, 1, 1, 1, 1 unsupported: false, false, false, false, false passed: false, false, false, false, false test failed: false, false, false, false, false |