Related Website Sets: developer guide

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.

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 example below, 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 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 here.
  • 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.

Storage Access API

Browser Support

  • 119
  • 85
  • 65
  • 11.1

Source

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.)

Checking and requesting 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; however, the promise is rejected, citing the reason, if access was denied for any reason.

requestStorageAccessFor in Chrome

Browser Support

  • 119
  • 119
  • x
  • x

Source

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.

Checking 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 will not 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.

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 crossorigin attribute on the resources, ensuring explicit opt-in.

Implementation examples

Requesting access to storage from an embedded cross-origin iframe

Diagram showing an embedded site on a top-level.site
Using 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.

Diagram showing requestStorageAccessFor() being used on a top-level site and not within an embed
Using requestStorageAccessFor() on a top-level site for a different origin

Top-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.

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.

To declare the relationship amongst the domains and specify which subset they are part of, follow the steps below:

  1. 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.
  2. Ensure the set formation requirements and set validation requirements are in place.
  3. Declare the Related Website Set in the correct JSON format.
  4. 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

To meet the needs of enterprise users Chrome has a couple of enterprise policies in place:

  • 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.

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: