Related Website Sets (RWS) is a web platform mechanism which helps browsers to understand the relationships amongst a collection of domains. This allows browsers to make key decisions to enable certain site functions (such as whether to allow access to cross-site cookies) and to present this information to users.
As Chrome deprecates third-party cookies, its goal is to maintain key use cases on the web while improving privacy for users. For example, many sites rely on multiple domains to serve a single user experience. Organizations may want to maintain different top-level domains for multiple use cases like country specific domains or service domains for hosting images or video. Related Website Sets allows sites to share data across domains, with specific controls.
What is a Related Website Set?
At a high level, a Related Website Set is a collection of domains, for which there is a single "set primary" and potentially multiple "set members."
In the following example, primary
lists the primary domain, and associatedSites
lists domains that meet the requirements of the associated subset.
{
"primary": "https://primary.com",
"associatedSites": ["https://associate1.com", "https://associate2.com", "https://associate3.com"]
}
The canonical Related Website Sets list is a publicly viewable list in a JSON file format hosted in the Related Website Sets GitHub repository, which serves as the source-of-truth for all sets. Chrome consumes this file to apply to its behavior.
Only those with administrative control over a domain can create a set with that domain. Submitters are required to declare the relationship between each "set member" to its "set primary." Set members could include a range of different domain types and must be part of a subset based on a use case.
If your application depends on access to cross-site cookies (also called third-party cookies) across sites within the same Related Website Set, you can use Storage Access API (SAA) and the requestStorageAccessFor API to request access to those cookies. Depending on the subset that each site is part of, the browser may handle the request differently.
To learn more about the process and requirements for submitting sets, check out the submission guidelines. Submitted sets will go through various technical checks to validate the submissions.
Related Website Sets use cases
Related Website Sets are a good match for cases when an organization needs a form of shared identity across different top-level sites.
Some of the use cases for Related Website Sets are:
- Country customization. Leveraging localized sites while relying on shared infrastructure (example.co.uk may rely on a service hosted by example.ca).
- Service domain integration. Leveraging service domains that users never directly interact with, but provide services across the same organization's sites (example-cdn.com).
- User content separation. Accessing data on different domains that separate user-uploaded content from other site content for security reasons, while allowing the sandboxed domain access to authentication (and other) cookies. If you are serving inactive user-uploaded content, you may also be able to safely host it on the same domain by following best practices.
- Embedded authenticated content. Supporting embedded content from across affiliated properties (videos, documents, or resources restricted to the user signed in on the top-level site).
- Sign-in. Supporting sign-in across affiliated properties. The FedCM API may also be appropriate for some use cases.
- Analytics. Deploying analytics and measurement of user journeys across affiliated properties to improve quality of services.
Related Website Sets integration details
Storage Access API
The Storage Access API (SAA) provides a way for embedded cross-origin content to access the storage that it would normally only have access to in a first-party context.
Embedded resources can use SAA methods to check whether they currently have access to storage, and to request access from the user agent.
When third-party cookies are blocked but Related Website Sets (RWS) is enabled, Chrome will automatically grant permission in intra-RWS contexts, and will show a prompt to the user otherwise. (An "intra-RWS context" is a context, such as an iframe, whose embedded site and top-level site are in the same RWS.)
Check and request storage access
To check whether they currently have access to storage, embedded sites can use Document.hasStorageAccess()
method.
The method returns a promise that resolves with a boolean value indicating whether the document already has access to its cookies or not. The promise also returns true if the iframe is same-origin as the top frame.
To request access to cookies in a cross-site context embedded sites can use Document.requestStorageAccess()
(rSA).
The requestStorageAccess()
API is meant to be called from within an iframe. That iframe has to have just received user interaction (a user gesture, which is required by all browsers), but Chrome additionally requires that at some point in the last 30 days, the user has visited the site that owns that iframe and has interacted with that site specifically—as a top-level document, not in an iframe.
requestStorageAccess()
returns a promise that resolves if the access to storage was granted. The promise is rejected, citing the reason, if access was denied for any reason.
requestStorageAccessFor in Chrome
The Storage Access API only allows embedded sites to request access to storage from within <iframe>
elements that have received user interaction.
This poses challenges in adopting Storage Access API for top-level sites that use cross-site images or script tags requiring cookies.
To address this, Chrome has implemented a way for top-level sites to request storage access on behalf of specific origins with Document.requestStorageAccessFor()
(rSAFor).
document.requestStorageAccessFor('https://target.site')
The requestStorageAccessFor()
API is meant to be called by a top-level document. That document must also have just received user interaction. But unlike requestStorageAccess()
, Chrome doesn't check for an interaction in a top-level document within the last 30 days because the user is already on the page.
Check storage access permissions
Access to some browser features, like camera or geolocation, is based on user-granted permissions. The Permissions API provides a way to check the permission status for accessing an API–whether it has been granted, denied, or it requires some form of user interaction, such as clicking a prompt or interacting with the page.
You can query permission status using navigator.permissions.query()
.
To check the storage access permission for the current context you need to pass in the 'storage-access'
string:
navigator.permissions.query({name: 'storage-access'})
To check the storage access permission for a specified origin, you need to pass in the 'top-level-storage-access'
string:
navigator.permissions.query({name: 'top-level-storage-access', requestedOrigin: 'https://target.site'})
Note that to protect the integrity of the embedded origin, this checks only permissions granted by the top-level document using document.requestStorageAccessFor
.
Depending on whether the permission can be automatically granted or it requires a user gesture, it will return prompt
or granted
.
Per frame model
rSA grants apply per frame. rSA and rSAFor grants are treated as separate permissions.
Each new frame will need to request storage access individually and it will automatically be granted access. Only the first request requires user gesture, any subsequent requests initiated by the iframe, such as navigation or subresources won't need to wait for a user gesture as that will be granted for the browsing session by the initial request.
Refreshing, reloading, or otherwise recreating the iframe will require requesting access again.
Cookie requirements
Cookies must specify both the SameSite=None
and Secure
attributes as rSA only provides access for cookies that are already marked for use in cross-site contexts.
Cookies with SameSite=Lax
, SameSite=Strict
, or without a SameSite
attribute are for first-party use only and will never be shared in a cross-site context regardless of rSA.
Security
For rSAFor, subresource requests require Cross-Origin Resource Sharing (CORS) headers or the crossorigin
attribute on the resources, ensuring explicit opt-in.
Implementation examples
Request access to storage from an embedded cross-origin iframe
![Diagram showing an embedded site on a top-level.site](https://developers-dot-devsite-v2-prod.appspot.com/static/privacy-sandbox/assets/images/SV7SXAQRcVnBZEgjgxYc.png?authuser=6)
requestStorageAccess()
in an embed on another site.Check if you have storage access
To check if you already have storage access use document.hasStorageAccess()
.
If the promise resolves true, you can access storage in the cross-site context. If it resolves false, you need to request storage access.
document.hasStorageAccess().then((hasAccess) => {
if (hasAccess) {
// You can access storage in this context
} else {
// You have to request storage access
}
});
Request storage access
If you need to request storage access, first check the storage access permission navigator.permissions.query({name: 'storage-access'})
to see if that requires a user gesture or it can be automatically granted.
If the permission is granted
you can call document.requestStorageAccess()
and it should succeed without a user gesture.
If the permission status is prompt
you need to initiate the document.requestStorageAccess()
call after a user gesture, such as a button click.
Example:
navigator.permissions.query({name: 'storage-access'}).then(res => {
if (res.state === 'granted') {
// Permission has already been granted
// You can request storage access without any user gesture
rSA();
} else if (res.state === 'prompt') {
// Requesting storage access requires user gesture
// For example, clicking a button
const btn = document.createElement("button");
btn.textContent = "Grant access";
btn.addEventListener('click', () => {
// Request storage access
rSA();
});
document.body.appendChild(btn);
}
});
function rSA() {
if ('requestStorageAccess' in document) {
document.requestStorageAccess().then(
(res) => {
// Use storage access
},
(err) => {
// Handle errors
}
);
}
}
Subsequent requests from within the frame, navigations or subresources, will automatically have permission for accessing cross-site cookies. hasStorageAccess()
returns true and cross-site cookies from the same Related Website Set will be sent on those requests without any additional JavaScript calls.
Top-level sites requesting cookie access on behalf of cross-origin sites
![Diagram showing requestStorageAccessFor() being used on a top-level site and not within an embed](https://developers-dot-devsite-v2-prod.appspot.com/static/privacy-sandbox/assets/images/jRgDgWl7yb1cEcwpcdMo.png?authuser=6)
requestStorageAccessFor()
on a top-level site for a different originTop-level sites can use requestStorageAccessFor()
to request storage access on behalf of specific origins.
hasStorageAccess()
only checks whether the site calling it has storage access, so a top level site can check the permissions for another origin.
To discover if the user will be prompted or if storage access has already been granted to specified origin, call navigator.permissions.query({name: 'top-level-storage-access', requestedOrigin: 'https://target.site'})
.
If the permission is granted
you can call document.requestStorageAccessFor('https://target.site')
. It should succeed without a user gesture.
If the permission is prompt
then you will need to hook the document.requestStorageAccessFor('https://target.site')
call behind the user gesture, such as a button click.
Example:
navigator.permissions.query({name:'top-level-storage-access',requestedOrigin: 'https://target.site'}).then(res => {
if (res.state === 'granted') {
// Permission has already been granted
// You can request storage access without any user gesture
rSAFor();
} else if (res.state === 'prompt') {
// Requesting storage access requires user gesture
// For example, clicking a button
const btn = document.createElement("button");
btn.textContent = "Grant access";
btn.addEventListener('click', () => {
// Request storage access
rSAFor();
});
document.body.appendChild(btn);
}
});
function rSAFor() {
if ('requestStorageAccessFor' in document) {
document.requestStorageAccessFor().then(
(res) => {
// Use storage access
},
(err) => {
// Handle errors
}
);
}
}
After a successful requestStorageAccessFor()
call, cross-site requests will include cookies if they include CORS or the crossorigin attribute, so sites may want to wait before triggering a request.
The requests must use the credentials: 'include'
option and resources must include crossorigin="use-credentials"
attribute.
function checkCookie() {
fetch('https://related-website-sets.glitch.me/getcookies.json', {
method: 'GET',
credentials: 'include'
})
.then((response) => response.json())
.then((json) => {
// Do something
});
}
How to test locally
Prerequisites
To test Related Website Sets locally, use Chrome 119 or higher launched from the command line and enable the test-third-party-cookie-phaseout
Chrome flag.
Enable the Chrome flag
To enable the necessary Chrome flag, navigate to chrome://flags#test-third-party-cookie-phaseout
from the address bar and change the flag to Enabled
. Make sure to restart the browser after the flags have been changed.
Launch Chrome with a with local Related Website Set
To launch Chrome with locally declared Related Website Set, create a JSON object that contains URLs that are members of a set and pass it to --use-related-website-set
.
Learn more about how to run Chromium with flags.
--use-related-website-set="{\"primary\": \"https://related-website-sets.glitch.me\", \"associatedSites\": [\"https://rws-member-1.glitch.me\"]}" \
https://related-website-sets.glitch.me/
Example
To enable Related Website Sets locally, you need to enable the test-third-party-cookie-phaseout
in chrome://flags
and launch Chrome from the command-line with the --use-related-website-set
flag with the JSON object containing the URLs that are members of a set.
--use-related-website-set="{\"primary\": \"https://related-website-sets.glitch.me\", \"associatedSites\": [\"https://rws-member-1.glitch.me\"]}" \
https://related-website-sets.glitch.me/
Verify that you have access to cross-site cookies
Call the APIs (rSA or rSAFor) from the sites that are being tested and validate access to the cross-site cookies.
Related Website Sets submission process
To declare the relationship between domains, and specify which subset they are part of, follow these steps:
- Identify the relevant domains, this includes the set primary and set members, that will be part of the Related Website Set. Also identify which subset type each set member belongs to.
- Ensure the set formation requirements and set validation requirements are in place.
- Declare the Related Website Set in the correct JSON format.
- Submit the Related Website Set by creating a pull request (PR) to the
related_website_sets.JSON
where Chrome will host the canonical Related Website Set list. (A GitHub account is required to create PRs, and you will need to sign a Contributor's License Agreement (CLA) to contribute to the list.)
Once the PR is created, a series of checks will happen to validate that the requirements from step 2 are in place.
If successful, the PR will indicate that checks have been passed. Approved PRs will be manually merged in batches to the canonical Related Website Set list once per week (Tuesdays at 12pm Eastern Time).
If any of the checks fails, the submitter will be notified through a PR failure on GitHub. The submitter can fix the errors and update the PR, and keep in mind that:
- When the PR fails, an error message will provide additional information on why the submission may have failed (example).
- All technical checks governing set submissions are conducted on GitHub, and consequently all submission failures resulting from technical checks will be viewable on GitHub.
Enterprise policies
Chrome has two policies in place to meet the needs of enterprise users:
- Systems that might not be able to integrate with Related Website Sets can disable the Related Website Sets feature in all enterprise instances of Chrome with the
RelatedWebsiteSetsEnabled
policy. - Some enterprise systems have internal-only sites (such as an intranet) with registrable domains that differ from the domains in their Related Website Set. If they need to treat these sites as part of their Related Website Set without exposing them publicly (as the domains may be confidential) they can augment or override their public Related Website Sets list with the
RelatedWebsiteSetsOverrides
policy.
Chrome resolves any intersection of the public and Enterprise sets in one of two
ways, depending on whether replacemements
or additions
are specified.
For example, for the public set {primary: A, associated: [B, C]}
:
replacements set: |
{primary: C, associated: [D, E]} |
Enterprise set absorbs the common site to form a new set. | |
Resulting sets: | {primary: A, associated: [B]} {primary: C, associated: [D, E]} |
additions set: |
{primary: C, associated: [D, E]} |
Public and Enterprise sets are combined. | |
Resulting set: | {primary: C, associated: [A, B, D, E]} |
Troubleshoot Related Website Sets
"User prompt" and "user gesture"
A "user prompt" and "user gesture" are different things. Chrome won't show a
permission prompt
to users for sites that are in the same Related Website Set, but Chrome still
requires that the user has interacted with the page. Before granting permission,
Chrome requires a
user gesture,
also called "user interaction" or "user activation". This is because usage of
the Storage Access API outside of a Related Website Set context (namely
requestStorageAccess()
) also requires a user gesture, because of
web platform design principles.
Access other sites' cookies or storage
Related Website Sets doesn't merge storage for different sites: it just allows
easier (prompt-free) requestStorageAccess()
calls. Related Website
Sets only lowers the user friction of using the Storage Access API, but doesn't
dictate what to do once access has been restored. If A and B are different sites
in the same Related Website Set, and A embeds B, B can call
requestStorageAccess()
and get access to first-party storage without prompting
the user. Related Website Sets doesn't perform any cross-site communication. For
example, setting up a Related Website Set won't cause the cookies belonging
to B to start being sent to A. If you
want to share that data, you will have to share it yourself, for example by
sending a window.postMessage
from a B iframe to an
A frame.
Unpartitioned cookie access by default
Related Website Sets does not allow implicit unpartitioned cookie access
without invoking any API. Cross-site cookies are not made available
by default within the set; Related Website Sets just allows sites within the set to
skip the Storage Access API permission prompt.
An iframe must call document.requestStorageAccess()
if it wants to access its
cookies, or the top-level page can call document.requestStorageAccessFor()
.
Share feedback
Submitting a set on GitHub and working with the Storage Access API and the requestStorageAccessFor
API are opportunities to share your experience with the process and any issues you run into.
To join discussions about Related Website Sets:
- Join the Related Website Sets public mailing list.
- Raise issues and follow the discussion on Related Website Sets GitHub repo.