Command Palette

Search for a command to run...

Page Inspect

https://privacytests.org/
Internal Links
9
External Links
5
Images
18
Headings
1

Page Content

Title:Which browsers are best for privacy?
Description:PrivacyTests.org subjects major web browsers to a suite of automated tests to find out: which web browsers offer the best privacy protections?
HTML Size:1393 KB
Markdown Size:98 KB
Fetched At:November 18, 2025

Page Structure

h1Desktop Browsers

Markdown Content

What are the best private browsers in 2025?

PrivacyTests.org

News

About

No. 95

Open-source tests of web browser privacy.

Updated 2025-08-12

Desktop browsers

Desktop private modes

iOS browsers

Android browsers

Nightly builds

Nightly private modes

= Passed privacy test

= Failed privacy test

= No such feature

(Click anywhere for more info.)

# Desktop Browsers
(default settings)


brave
1.81


chrome
139.0


duckduckgo
1.150


edge
139.0


firefox
141.0


librewolf
141.0


mullvad
14.5


opera
120.0


safari
18.6


tor
14.5


ungoogled
139.0


vivaldi
7.5

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, Error: Unsupported
result, different first party: h2, h2, h2, h2, h2
unsupported: false, false, false, false, true
passed: 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
result, different first party: h2
unsupported: true
passed: undefined
test failed: 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,
h3,
Error: Unsupported,
h3,
Error: Unsupported
result, different first party: h2, h2, h2, h2, h2
unsupported: true, false, true, false, true
passed: , 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
result, different first party: h2
unsupported: true
passed: undefined
test failed: 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:
e7085635-2c69-4e98-92d3-97e4c73afa2f,
dad47994-1478-4269-bc67-9d5be7279695,
a224b08b-56ca-430a-8291-a1391ce3f527,
ed625f5b-53f1-45e2-b9d8-f1afa4b755d4,
54ad99c6-a8ab-4b8b-957e-aaa49d517db0
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:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116,
9e792e5f-2682-45df-a4b6-9926c1368572,
96cb1992-e972-4aef-8062-ef9c5ed16a01,
be33e986-4227-4dad-98ab-849158191238,
d1bff213-a9f5-41c3-a065-c8b074cff472
result, different first party:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116,
9e792e5f-2682-45df-a4b6-9926c1368572,
96cb1992-e972-4aef-8062-ef9c5ed16a01,
be33e986-4227-4dad-98ab-849158191238,
d1bff213-a9f5-41c3-a065-c8b074cff472
unsupported: false, false, false, false, false
passed: false, false, false, false, false
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: fb5e2f4c-c5b5-411f-a3b3-03e08b0cc599
result, different first party: Error: Load failed
unsupported: false
passed: true
test failed: 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:
026115d8-5ec8-4705-b68d-299ea05d729f,
b33c419d-acf6-4795-95e0-d5d753f2f16d,
6a79070f-7300-4f0a-b3e4-67db8452282d,
fc4e16e7-ac2e-48a9-8623-332158912d29,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b
result, different first party:
026115d8-5ec8-4705-b68d-299ea05d729f,
b33c419d-acf6-4795-95e0-d5d753f2f16d,
6a79070f-7300-4f0a-b3e4-67db8452282d,
fc4e16e7-ac2e-48a9-8623-332158912d29,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b
unsupported: false, false, false, false, false
passed: false, false, false, false, false
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:
a89ceebb-1801-46fc-bbfa-9268cd1e86b8,
3c6d0906-4d80-439c-9124-ff2647fc503f,
29934d34-345f-4b44-91a5-4cfc4705276b,
c261a896-1dbf-455d-8a32-c51b15883279,
4befec68-5b8d-4639-b156-03db7501a173
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: 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:
15e21312-33db-4994-b766-baad8032803f,
7ccbfb90-229d-427c-9f22-79caffc2fec3,
ab247bb9-7408-43c0-81f4-22f7335617f7,
1cc5af75-9209-4c31-a70b-5f98374d6544,
f1e4b993-6e6c-430d-bd4c-f9214ee02e71
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: 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:
e64ec357-7007-4dab-a6fa-6650afbb1b92,
ea216c9a-9cb5-4630-8ddf-2d5bf0ab8b56,
f2c54d89-4429-43be-9044-840a1c275e7f,
91894484-f7cc-4015-ae96-635239333863,
d4713458-e4ff-458e-b8a8-0a3562d0441b
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: 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:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd,
299e3cd4-7953-4f77-801f-8985b822ac24,
aad11fab-6660-48f9-b28d-4b2ee45a44df,
d31fb840-54e6-4419-b2ca-f532e60327ac,
8003e0ac-cbd3-4236-932f-a79792d54b62
result, different first party:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd,
299e3cd4-7953-4f77-801f-8985b822ac24,
aad11fab-6660-48f9-b28d-4b2ee45a44df,
d31fb840-54e6-4419-b2ca-f532e60327ac,
8003e0ac-cbd3-4236-932f-a79792d54b62
unsupported: false, false, false, false, false
passed: false, false, false, false, false
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:
c0150e2b-e0d0-41b9-b45d-d902a1eb8b52,
fe4b6d38-97a5-47e0-8ce9-abd6b175891b,
3ac91718-3eba-45e8-aceb-765d0391821b,
f2d6741d-a215-4cac-a81a-dec44031672d,
576d3332-f9c6-455d-bddd-b3b643b6c552
result, different first party:
Error: Load failed,
Error: Load failed,
Error: Load failed,
Error: Load failed,
Error: Load failed
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: 49fe77ef-a8ac-4213-90fb-9b81cb45fd81
result, different first party: Error: NetworkError when attempting to fetch resource.
unsupported: false
passed: true
test failed: 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:
24441439-f1db-4c84-bc96-50682c4e643e,
6d1c53c8-70cf-47eb-9a21-0ba706352479,
5894b594-2a38-4d3a-be5d-e53e01ad93d1,
e198d1f6-c1a6-4343-9907-302129e685e7,
bf62e3cc-149e-4225-8d7b-3b8b3b338e10
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:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7,
32f534ec-f0c9-4fb9-a393-c743feebc30e,
085080b8-ac7e-4d13-b00e-fceb219d3dac,
e74254c5-9034-45cd-b7ba-b7db726e55ab
result, different first party:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7,
32f534ec-f0c9-4fb9-a393-c743feebc30e,
085080b8-ac7e-4d13-b00e-fceb219d3dac,
e74254c5-9034-45cd-b7ba-b7db726e55ab
unsupported: false, false, false, false, false
passed: false, false, false, false, false
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:
e7085635-2c69-4e98-92d3-97e4c73afa2f,
dad47994-1478-4269-bc67-9d5be7279695,
a224b08b-56ca-430a-8291-a1391ce3f527,
ed625f5b-53f1-45e2-b9d8-f1afa4b755d4,
54ad99c6-a8ab-4b8b-957e-aaa49d517db0
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: true, true, true, true, true
test failed: false, false, false, false, false

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:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116,
9e792e5f-2682-45df-a4b6-9926c1368572,
96cb1992-e972-4aef-8062-ef9c5ed16a01,
be33e986-4227-4dad-98ab-849158191238,
d1bff213-a9f5-41c3-a065-c8b074cff472
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: true, true, true, true, true
test failed: false, false, false, false, false

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: fb5e2f4c-c5b5-411f-a3b3-03e08b0cc599
result, different first party: Error: no BroadcastChannel message
unsupported: false
passed: true
test failed: false

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:
026115d8-5ec8-4705-b68d-299ea05d729f,
b33c419d-acf6-4795-95e0-d5d753f2f16d,
6a79070f-7300-4f0a-b3e4-67db8452282d,
fc4e16e7-ac2e-48a9-8623-332158912d29,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b
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: true, true, true, true, true
test failed: false, false, false, false, false

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:
a89ceebb-1801-46fc-bbfa-9268cd1e86b8,
3c6d0906-4d80-439c-9124-ff2647fc503f,
29934d34-345f-4b44-91a5-4cfc4705276b,
c261a896-1dbf-455d-8a32-c51b15883279,
4befec68-5b8d-4639-b156-03db7501a173
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: true, true, true, true, true
test failed: false, false, false, false, false

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:
15e21312-33db-4994-b766-baad8032803f,
7ccbfb90-229d-427c-9f22-79caffc2fec3,
ab247bb9-7408-43c0-81f4-22f7335617f7,
1cc5af75-9209-4c31-a70b-5f98374d6544,
f1e4b993-6e6c-430d-bd4c-f9214ee02e71
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: true, true, true, true, true
test failed: false, false, false, false, false

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:
e64ec357-7007-4dab-a6fa-6650afbb1b92,
ea216c9a-9cb5-4630-8ddf-2d5bf0ab8b56,
f2c54d89-4429-43be-9044-840a1c275e7f,
91894484-f7cc-4015-ae96-635239333863,
d4713458-e4ff-458e-b8a8-0a3562d0441b
result, different first party:
Error: The operation is insecure.,
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, false
passed: true, true, true, true, true
test failed: false, false, false, false, false

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:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd,
299e3cd4-7953-4f77-801f-8985b822ac24,
aad11fab-6660-48f9-b28d-4b2ee45a44df,
d31fb840-54e6-4419-b2ca-f532e60327ac,
8003e0ac-cbd3-4236-932f-a79792d54b62
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: true, true, true, true, true
test failed: false, false, false, false, false

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:
c0150e2b-e0d0-41b9-b45d-d902a1eb8b52,
fe4b6d38-97a5-47e0-8ce9-abd6b175891b,
3ac91718-3eba-45e8-aceb-765d0391821b,
f2d6741d-a215-4cac-a81a-dec44031672d,
576d3332-f9c6-455d-bddd-b3b643b6c552
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: true, true, true, true, true
test failed: false, false, false, false, false

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: 49fe77ef-a8ac-4213-90fb-9b81cb45fd81
result, different first party: Error: The operation is insecure.
unsupported: false
passed: true
test failed: false

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:
24441439-f1db-4c84-bc96-50682c4e643e,
6d1c53c8-70cf-47eb-9a21-0ba706352479,
5894b594-2a38-4d3a-be5d-e53e01ad93d1,
e198d1f6-c1a6-4343-9907-302129e685e7,
bf62e3cc-149e-4225-8d7b-3b8b3b338e10
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: true, true, true, true, true
test failed: false, false, false, false, false

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:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7,
32f534ec-f0c9-4fb9-a393-c743feebc30e,
085080b8-ac7e-4d13-b00e-fceb219d3dac,
e74254c5-9034-45cd-b7ba-b7db726e55ab
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: 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 first party:
e7085635-2c69-4e98-92d3-97e4c73afa2f,
dad47994-1478-4269-bc67-9d5be7279695,
a224b08b-56ca-430a-8291-a1391ce3f527,
ed625f5b-53f1-45e2-b9d8-f1afa4b755d4,
54ad99c6-a8ab-4b8b-957e-aaa49d517db0
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:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116,
9e792e5f-2682-45df-a4b6-9926c1368572,
96cb1992-e972-4aef-8062-ef9c5ed16a01,
be33e986-4227-4dad-98ab-849158191238,
d1bff213-a9f5-41c3-a065-c8b074cff472
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: fb5e2f4c-c5b5-411f-a3b3-03e08b0cc599
result, different first party: Error: undefined is not an object (evaluating 'cacheKeys\[0\].url')
unsupported: false
passed: true
test failed: 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:
026115d8-5ec8-4705-b68d-299ea05d729f,
b33c419d-acf6-4795-95e0-d5d753f2f16d,
6a79070f-7300-4f0a-b3e4-67db8452282d,
fc4e16e7-ac2e-48a9-8623-332158912d29,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b
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:
a89ceebb-1801-46fc-bbfa-9268cd1e86b8,
3c6d0906-4d80-439c-9124-ff2647fc503f,
29934d34-345f-4b44-91a5-4cfc4705276b,
c261a896-1dbf-455d-8a32-c51b15883279,
4befec68-5b8d-4639-b156-03db7501a173
result, different first party:
Error: can't access property "url",
cacheKeys\[0\] is undefined,
Error: can't access property "url",
cacheKeys\[0\] is undefined,
Error: can't access property "url",
cacheKeys\[0\] is undefined,
Error: can't access property "url",
cacheKeys\[0\] is undefined,
Error: can't access property "url",
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:
15e21312-33db-4994-b766-baad8032803f,
7ccbfb90-229d-427c-9f22-79caffc2fec3,
ab247bb9-7408-43c0-81f4-22f7335617f7,
1cc5af75-9209-4c31-a70b-5f98374d6544,
f1e4b993-6e6c-430d-bd4c-f9214ee02e71
result, different first party:
Error: can't access property "url",
cacheKeys\[0\] is undefined,
Error: can't access property "url",
cacheKeys\[0\] is undefined,
Error: can't access property "url",
cacheKeys\[0\] is undefined,
Error: can't access property "url",
cacheKeys\[0\] is undefined,
Error: can't access property "url",
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:
e64ec357-7007-4dab-a6fa-6650afbb1b92,
ea216c9a-9cb5-4630-8ddf-2d5bf0ab8b56,
f2c54d89-4429-43be-9044-840a1c275e7f,
91894484-f7cc-4015-ae96-635239333863,
d4713458-e4ff-458e-b8a8-0a3562d0441b
result, different first party:
Error: The operation is insecure.,
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, 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:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd,
299e3cd4-7953-4f77-801f-8985b822ac24,
aad11fab-6660-48f9-b28d-4b2ee45a44df,
d31fb840-54e6-4419-b2ca-f532e60327ac,
8003e0ac-cbd3-4236-932f-a79792d54b62
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:
c0150e2b-e0d0-41b9-b45d-d902a1eb8b52,
fe4b6d38-97a5-47e0-8ce9-abd6b175891b,
3ac91718-3eba-45e8-aceb-765d0391821b,
f2d6741d-a215-4cac-a81a-dec44031672d,
576d3332-f9c6-455d-bddd-b3b643b6c552
result, different first party:
Error: undefined is not an object (evaluating 'cacheKeys\[0\].url'),
Error: undefined is not an object (evaluating 'cacheKeys\[0\].url'),
Error: undefined is not an object (evaluating 'cacheKeys\[0\].url'),
Error: undefined is not an object (evaluating 'cacheKeys\[0\].url'),
Error: undefined is not an object (evaluating 'cacheKeys\[0\].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: 49fe77ef-a8ac-4213-90fb-9b81cb45fd81
result, different first party: Error: The operation is insecure.
unsupported: false
passed: true
test failed: 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:
24441439-f1db-4c84-bc96-50682c4e643e,
6d1c53c8-70cf-47eb-9a21-0ba706352479,
5894b594-2a38-4d3a-be5d-e53e01ad93d1,
e198d1f6-c1a6-4343-9907-302129e685e7,
bf62e3cc-149e-4225-8d7b-3b8b3b338e10
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:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7,
32f534ec-f0c9-4fb9-a393-c743feebc30e,
085080b8-ac7e-4d13-b00e-fceb219d3dac,
e74254c5-9034-45cd-b7ba-b7db726e55ab
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:
e7085635-2c69-4e98-92d3-97e4c73afa2f\_http,
dad47994-1478-4269-bc67-9d5be7279695\_http,
a224b08b-56ca-430a-8291-a1391ce3f527\_http,
ed625f5b-53f1-45e2-b9d8-f1afa4b755d4\_http,
54ad99c6-a8ab-4b8b-957e-aaa49d517db0\_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:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116\_http,
9e792e5f-2682-45df-a4b6-9926c1368572\_http,
96cb1992-e972-4aef-8062-ef9c5ed16a01\_http,
be33e986-4227-4dad-98ab-849158191238\_http,
d1bff213-a9f5-41c3-a065-c8b074cff472\_http
result, different first party:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116\_http,
9e792e5f-2682-45df-a4b6-9926c1368572\_http,
96cb1992-e972-4aef-8062-ef9c5ed16a01\_http,
be33e986-4227-4dad-98ab-849158191238\_http,
d1bff213-a9f5-41c3-a065-c8b074cff472\_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: fb5e2f4c-c5b5-411f-a3b3-03e08b0cc599\_http
result, different first party: null
unsupported: false
passed: true
test failed: 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:
026115d8-5ec8-4705-b68d-299ea05d729f\_http,
b33c419d-acf6-4795-95e0-d5d753f2f16d\_http,
6a79070f-7300-4f0a-b3e4-67db8452282d\_http,
fc4e16e7-ac2e-48a9-8623-332158912d29\_http,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b\_http
result, different first party:
026115d8-5ec8-4705-b68d-299ea05d729f\_http,
b33c419d-acf6-4795-95e0-d5d753f2f16d\_http,
6a79070f-7300-4f0a-b3e4-67db8452282d\_http,
fc4e16e7-ac2e-48a9-8623-332158912d29\_http,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b\_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:
a89ceebb-1801-46fc-bbfa-9268cd1e86b8\_http,
3c6d0906-4d80-439c-9124-ff2647fc503f\_http,
29934d34-345f-4b44-91a5-4cfc4705276b\_http,
c261a896-1dbf-455d-8a32-c51b15883279\_http,
4befec68-5b8d-4639-b156-03db7501a173\_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:
15e21312-33db-4994-b766-baad8032803f\_http,
7ccbfb90-229d-427c-9f22-79caffc2fec3\_http,
ab247bb9-7408-43c0-81f4-22f7335617f7\_http,
1cc5af75-9209-4c31-a70b-5f98374d6544\_http,
f1e4b993-6e6c-430d-bd4c-f9214ee02e71\_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:
e64ec357-7007-4dab-a6fa-6650afbb1b92\_http,
ea216c9a-9cb5-4630-8ddf-2d5bf0ab8b56\_http,
f2c54d89-4429-43be-9044-840a1c275e7f\_http,
91894484-f7cc-4015-ae96-635239333863\_http,
d4713458-e4ff-458e-b8a8-0a3562d0441b\_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:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd\_http,
299e3cd4-7953-4f77-801f-8985b822ac24\_http,
aad11fab-6660-48f9-b28d-4b2ee45a44df\_http,
d31fb840-54e6-4419-b2ca-f532e60327ac\_http,
8003e0ac-cbd3-4236-932f-a79792d54b62\_http
result, different first party:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd\_http,
299e3cd4-7953-4f77-801f-8985b822ac24\_http,
aad11fab-6660-48f9-b28d-4b2ee45a44df\_http,
d31fb840-54e6-4419-b2ca-f532e60327ac\_http,
8003e0ac-cbd3-4236-932f-a79792d54b62\_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:
c0150e2b-e0d0-41b9-b45d-d902a1eb8b52\_http,
fe4b6d38-97a5-47e0-8ce9-abd6b175891b\_http,
3ac91718-3eba-45e8-aceb-765d0391821b\_http,
f2d6741d-a215-4cac-a81a-dec44031672d\_http,
576d3332-f9c6-455d-bddd-b3b643b6c552\_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: 49fe77ef-a8ac-4213-90fb-9b81cb45fd81\_http
result, different first party: null
unsupported: false
passed: true
test failed: 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:
24441439-f1db-4c84-bc96-50682c4e643e\_http,
6d1c53c8-70cf-47eb-9a21-0ba706352479\_http,
5894b594-2a38-4d3a-be5d-e53e01ad93d1\_http,
e198d1f6-c1a6-4343-9907-302129e685e7\_http,
bf62e3cc-149e-4225-8d7b-3b8b3b338e10\_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:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b\_http,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7\_http,
32f534ec-f0c9-4fb9-a393-c743feebc30e\_http,
085080b8-ac7e-4d13-b00e-fceb219d3dac\_http,
e74254c5-9034-45cd-b7ba-b7db726e55ab\_http
result, different first party:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b\_http,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7\_http,
32f534ec-f0c9-4fb9-a393-c743feebc30e\_http,
085080b8-ac7e-4d13-b00e-fceb219d3dac\_http,
e74254c5-9034-45cd-b7ba-b7db726e55ab\_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:
e7085635-2c69-4e98-92d3-97e4c73afa2f\_js,
dad47994-1478-4269-bc67-9d5be7279695\_js,
a224b08b-56ca-430a-8291-a1391ce3f527\_js,
ed625f5b-53f1-45e2-b9d8-f1afa4b755d4\_js,
54ad99c6-a8ab-4b8b-957e-aaa49d517db0\_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:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116\_js,
9e792e5f-2682-45df-a4b6-9926c1368572\_js,
96cb1992-e972-4aef-8062-ef9c5ed16a01\_js,
be33e986-4227-4dad-98ab-849158191238\_js,
d1bff213-a9f5-41c3-a065-c8b074cff472\_js
result, different first party:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116\_js,
9e792e5f-2682-45df-a4b6-9926c1368572\_js,
96cb1992-e972-4aef-8062-ef9c5ed16a01\_js,
be33e986-4227-4dad-98ab-849158191238\_js,
d1bff213-a9f5-41c3-a065-c8b074cff472\_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: fb5e2f4c-c5b5-411f-a3b3-03e08b0cc599\_js
result, different first party: null
unsupported: false
passed: true
test failed: 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:
026115d8-5ec8-4705-b68d-299ea05d729f\_js,
b33c419d-acf6-4795-95e0-d5d753f2f16d\_js,
6a79070f-7300-4f0a-b3e4-67db8452282d\_js,
fc4e16e7-ac2e-48a9-8623-332158912d29\_js,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b\_js
result, different first party:
026115d8-5ec8-4705-b68d-299ea05d729f\_js,
b33c419d-acf6-4795-95e0-d5d753f2f16d\_js,
6a79070f-7300-4f0a-b3e4-67db8452282d\_js,
fc4e16e7-ac2e-48a9-8623-332158912d29\_js,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b\_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:
a89ceebb-1801-46fc-bbfa-9268cd1e86b8\_js,
3c6d0906-4d80-439c-9124-ff2647fc503f\_js,
29934d34-345f-4b44-91a5-4cfc4705276b\_js,
c261a896-1dbf-455d-8a32-c51b15883279\_js,
4befec68-5b8d-4639-b156-03db7501a173\_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:
15e21312-33db-4994-b766-baad8032803f\_js,
7ccbfb90-229d-427c-9f22-79caffc2fec3\_js,
ab247bb9-7408-43c0-81f4-22f7335617f7\_js,
1cc5af75-9209-4c31-a70b-5f98374d6544\_js,
f1e4b993-6e6c-430d-bd4c-f9214ee02e71\_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:
e64ec357-7007-4dab-a6fa-6650afbb1b92\_js,
ea216c9a-9cb5-4630-8ddf-2d5bf0ab8b56\_js,
f2c54d89-4429-43be-9044-840a1c275e7f\_js,
91894484-f7cc-4015-ae96-635239333863\_js,
d4713458-e4ff-458e-b8a8-0a3562d0441b\_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:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd\_js,
299e3cd4-7953-4f77-801f-8985b822ac24\_js,
aad11fab-6660-48f9-b28d-4b2ee45a44df\_js,
d31fb840-54e6-4419-b2ca-f532e60327ac\_js,
8003e0ac-cbd3-4236-932f-a79792d54b62\_js
result, different first party:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd\_js,
299e3cd4-7953-4f77-801f-8985b822ac24\_js,
aad11fab-6660-48f9-b28d-4b2ee45a44df\_js,
d31fb840-54e6-4419-b2ca-f532e60327ac\_js,
8003e0ac-cbd3-4236-932f-a79792d54b62\_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:
c0150e2b-e0d0-41b9-b45d-d902a1eb8b52\_js,
fe4b6d38-97a5-47e0-8ce9-abd6b175891b\_js,
3ac91718-3eba-45e8-aceb-765d0391821b\_js,
f2d6741d-a215-4cac-a81a-dec44031672d\_js,
576d3332-f9c6-455d-bddd-b3b643b6c552\_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: 49fe77ef-a8ac-4213-90fb-9b81cb45fd81\_js
result, different first party: null
unsupported: false
passed: true
test failed: 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:
24441439-f1db-4c84-bc96-50682c4e643e\_js,
6d1c53c8-70cf-47eb-9a21-0ba706352479\_js,
5894b594-2a38-4d3a-be5d-e53e01ad93d1\_js,
e198d1f6-c1a6-4343-9907-302129e685e7\_js,
bf62e3cc-149e-4225-8d7b-3b8b3b338e10\_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:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b\_js,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7\_js,
32f534ec-f0c9-4fb9-a393-c743feebc30e\_js,
085080b8-ac7e-4d13-b00e-fceb219d3dac\_js,
e74254c5-9034-45cd-b7ba-b7db726e55ab\_js
result, different first party:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b\_js,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7\_js,
32f534ec-f0c9-4fb9-a393-c743feebc30e\_js,
085080b8-ac7e-4d13-b00e-fceb219d3dac\_js,
e74254c5-9034-45cd-b7ba-b7db726e55ab\_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:
e7085635-2c69-4e98-92d3-97e4c73afa2f,
dad47994-1478-4269-bc67-9d5be7279695,
a224b08b-56ca-430a-8291-a1391ce3f527,
ed625f5b-53f1-45e2-b9d8-f1afa4b755d4,
54ad99c6-a8ab-4b8b-957e-aaa49d517db0
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:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116,
9e792e5f-2682-45df-a4b6-9926c1368572,
96cb1992-e972-4aef-8062-ef9c5ed16a01,
be33e986-4227-4dad-98ab-849158191238,
d1bff213-a9f5-41c3-a065-c8b074cff472
result, different first party:
99f0a2bf-b41a-4758-8d51-b9c5d07dd116,
9e792e5f-2682-45df-a4b6-9926c1368572,
96cb1992-e972-4aef-8062-ef9c5ed16a01,
be33e986-4227-4dad-98ab-849158191238,
d1bff213-a9f5-41c3-a065-c8b074cff472
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: fb5e2f4c-c5b5-411f-a3b3-03e08b0cc599
result, different first party: Error: Type error
unsupported: false
passed: true
test failed: 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:
026115d8-5ec8-4705-b68d-299ea05d729f,
b33c419d-acf6-4795-95e0-d5d753f2f16d,
6a79070f-7300-4f0a-b3e4-67db8452282d,
fc4e16e7-ac2e-48a9-8623-332158912d29,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b
result, different first party:
026115d8-5ec8-4705-b68d-299ea05d729f,
b33c419d-acf6-4795-95e0-d5d753f2f16d,
6a79070f-7300-4f0a-b3e4-67db8452282d,
fc4e16e7-ac2e-48a9-8623-332158912d29,
311d701c-ad7e-4aa7-84a2-afdf4a4a400b
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:
a89ceebb-1801-46fc-bbfa-9268cd1e86b8,
3c6d0906-4d80-439c-9124-ff2647fc503f,
29934d34-345f-4b44-91a5-4cfc4705276b,
c261a896-1dbf-455d-8a32-c51b15883279,
4befec68-5b8d-4639-b156-03db7501a173
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:
15e21312-33db-4994-b766-baad8032803f,
7ccbfb90-229d-427c-9f22-79caffc2fec3,
ab247bb9-7408-43c0-81f4-22f7335617f7,
1cc5af75-9209-4c31-a70b-5f98374d6544,
f1e4b993-6e6c-430d-bd4c-f9214ee02e71
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,
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:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd,
299e3cd4-7953-4f77-801f-8985b822ac24,
aad11fab-6660-48f9-b28d-4b2ee45a44df,
d31fb840-54e6-4419-b2ca-f532e60327ac,
8003e0ac-cbd3-4236-932f-a79792d54b62
result, different first party:
3ae57aff-59cf-478f-83e7-0ce6e2ef84fd,
299e3cd4-7953-4f77-801f-8985b822ac24,
aad11fab-6660-48f9-b28d-4b2ee45a44df,
d31fb840-54e6-4419-b2ca-f532e60327ac,
8003e0ac-cbd3-4236-932f-a79792d54b62
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:
c0150e2b-e0d0-41b9-b45d-d902a1eb8b52,
fe4b6d38-97a5-47e0-8ce9-abd6b175891b,
3ac91718-3eba-45e8-aceb-765d0391821b,
f2d6741d-a215-4cac-a81a-dec44031672d,
576d3332-f9c6-455d-bddd-b3b643b6c552
result, different first party:
Error: Type error,
Error: Type error,
Error: Type error,
Error: Type error,
Error: Type error
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
result, different first party: Error: Unsupported
unsupported: true
passed: undefined
test failed: 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:
24441439-f1db-4c84-bc96-50682c4e643e,
6d1c53c8-70cf-47eb-9a21-0ba706352479,
5894b594-2a38-4d3a-be5d-e53e01ad93d1,
e198d1f6-c1a6-4343-9907-302129e685e7,
bf62e3cc-149e-4225-8d7b-3b8b3b338e10
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:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7,
32f534ec-f0c9-4fb9-a393-c743feebc30e,
085080b8-ac7e-4d13-b00e-fceb219d3dac,
e74254c5-9034-45cd-b7ba-b7db726e55ab
result, different first party:
9d7140bd-04e0-44f3-b6d6-e0234d82e99b,
5a8cb80f-21db-4a7c-bd79-071d7e26aeb7,
32f534ec-f0c9-4fb9-a393-c743feebc30e,
085080b8-ac7e-4d13-b00e-fceb219d3dac,
e74254c5-9034-45cd-b7ba-b7db726e55ab
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\_9779759484487227,
fake\_6435604947722651,
fake\_16629559953023265,
fake\_42172510931189033,
fake\_6114822711875867
result, different first party:
fake\_1306126338742133,
fake\_7099112130713392,
fake\_08345205696376556,
fake\_16832344070277272,
fake\_1747713081783815
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\_7997452452770248,
fake\_44263788403385695,
fake\_44133079893591054,
fake\_49401168311081234,
fake\_8093259252649003
result, different first party:
fake\_29034223184068475,
fake\_43988095687258344,
fake\_35414824064754646,
fake\_4508179452959902,
fake\_21386841891247932
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\_35745384229741695
result, different first party: fake\_09659913620784466
unsupported: false
passed: true
test failed: 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\_32531483983461795,
fake\_38509268987081446,
fake\_4421695170451565,
fake\_5060872504553542,
fake\_14381124077105367
result, different first party:
fake\_16357948975021186,
fake\_14347639572128923,
fake\_48430907079938756,
fake\_1137902390679808,
fake\_34412454921914737
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\_5490680661167049,
fake\_9010011753464402,
fake\_15111527138568115,
fake\_6720260818321364,
fake\_4974649968376741
result, different first party:
fake\_32776140390463837,
fake\_6504799076535981,
fake\_5181377711619153,
fake\_408867162167587,
fake\_9397177605943396
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\_4731919831854967,
fake\_9743435069527882,
fake\_8910597114540044,
fake\_4281916457038477,
fake\_773999145257243
result, different first party:
fake\_1882843474037159,
fake\_7075818996062826,
fake\_01930202742214271,
fake\_6107176992071621,
fake\_38800100900376067
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\_8919835870065644,
fake\_09401998413291346,
fake\_2369129217589485,
fake\_2295514640556504,
fake\_6491921573088903
result, different first party:
fake\_07534515097016681,
fake\_09589348739038672,
fake\_14439794568858866,
fake\_028815283289099547,
fake\_29074152722996427
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\_15612947356419493,
fake\_14064763539077352,
fake\_973118752995801,
fake\_01568890949942503,
fake\_2747235944674129
result, different first party:
fake\_47241023349857847,
fake\_08392673952351859,
fake\_6404076169397679,
fake\_10386815178938069,
fake\_04967718122878284
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\_05043666538509406,
fake\_8770051298159698,
fake\_4734819511609163,
fake\_12522292414825276,
fake\_0639656809295579
result, different first party:
fake\_0636353599214119,
fake\_5128133871054479,
fake\_6207717487023445,
fake\_847116350986443,
fake\_9301412944106957
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\_7137302851983749
result, different first party: fake\_506402076790297
unsupported: false
passed: true
test failed: 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\_4549135921627503,
fake\_6336523240325163,
fake\_2831380459752899,
fake\_6430618136212416,
fake\_9930737337423101
result, different first party:
fake\_9899155880545492,
fake\_7415434607636813,
fake\_5477002722046957,
fake\_8394441796059204,
fake\_5804758045172189
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\_8902634548673958,
fake\_8279770949116481,
fake\_882930686664491,
fake\_2017133143380785,
fake\_38575942662451257
result, different first party:
fake\_4420492947383563,
fake\_46331824650016706,
fake\_5404014753418158,
fake\_8321000628549335,
fake\_31617437124822056
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
result, different first party: 1
unsupported: false
passed: false
test failed: 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: 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: 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
result, different first party: 2
unsupported: false
passed: true
test failed: 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: 2, 2, 2, 2, 2
result, different first party: 3, 3, 3, 3, 3
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"});
le