Limited availability
Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.
Warning: This feature is currently opposed by one browser vendor. See the Standards positions section below for details.
The Shared Storage API is a client-side storage mechanism that enables unpartitioned, cross-site data access while preserving privacy (i.e., without relying on tracking cookies).
Concepts and usageOne major source of privacy and security problems on the web is the use of cookies set on third-party content embedded in sites (for example via <iframe>
elements). These cookies can be used to track and profile users, and share information across sites.
To prevent cross-site tracking, browsers are working towards partitioning all storage types, including Cookies, Web Storage, IndexedDB, and the Cache API. However, a major barrier to achieving this is the need for several legitimate use cases that rely on cross-site information sharing. Examples of such use cases include advertisers wanting to measure the reach of their ads across sites and generate reports, and site owners wanting to customize user experiences based on the group they are in or their previous site interactions.
The Shared Storage API provides a flexible solution for such use cases. It aims to provide the required data storage, processing, and sharing capabilities without the ability to track and profile users.
Like other storage APIs, you can write to shared storage at any time. However, you can only read shared storage data from inside a worklet. Worklets provide a secure environment inside which you can process shared storage data and return useful results, but you can't directly share the data with the associated browsing context.
To extract useful results from a shared storage worklet, you need to use an output gate. These gates serve specific purposes such as selecting a URL from a provided list to display to the user based on shared storage data. Results meant for the user are shown securely inside a fenced frame where they can't be accessed from the embedding page.
Output gatesThe currently available output gates for the Shared Storage API are discussed in the sections below. In each section, we list typical use cases for each gate and provide links to guides with more information and code examples.
Note: More output gates will likely be added in the future to support additional use cases.
URL SelectionThe URL Selection output gate, accessed via the selectURL()
method, is used to select a URL from a provided list to display to the user, based on shared storage data. This gate be used for the following purposes:
The Run output gate, accessed via the run()
method, is intended to be used in a generic way to process some shared storage data.
The Private Aggregation API can use the Run output gate to process shared storage data and generate aggregated reports. These reports can be used in the following use cases:
There are two parts to using the Shared Storage API â writing data to storage and reading/processing it. To give you an idea of how these parts are handled, we'll walk you through the basic A/B testing example from developer.chrome.com. In this example, a user is assigned to an experiment group, and the group details are stored in shared storage. Other sites are able to use this data when choosing a URL to display in a fenced frame.
Writing data to shared storage is simple â you use methods defined on the SharedStorage
interface to set, append, or delete/clear data.
This functionality is available in two different contexts:
WindowSharedStorage
. This is available via window.sharedStorage
.WorkletSharedStorage
. This is available via this.sharedStorage
.In our A/B testing example, we define a function in our app context that generates a random number â 0 or 1 â to represent an experiment group. We then run the window.sharedStorage.set()
function to assign the user to a group and save the result in shared storage:
// Randomly assigns a user to a group 0 or 1
function getExperimentGroup() {
return Math.round(Math.random());
}
async function injectContent() {
// Assign user to a random group (0 or 1) and store it in shared storage
window.sharedStorage.set("ab-testing-group", getExperimentGroup(), {
ignoreIfPresent: true,
});
}
Note: The ignoreIfPresent: true
option causes the set()
function to abort if the shared storage already contains a data item with the specified key.
As mentioned above, to extract useful results from a shared storage worklet, you need to use an output gate. In this example, we'll use the URL Selection output gate to read the user's experiment group and then display a URL in a fenced frame based on their group.
To use the output gate, you need to:
Below we'll look at these steps one by one.
Define an operation in a worklet moduleThe URL selection is based on the experiment group stored in shared storage. To retrieve this value and choose a URL based on it, we need to define an operation in a SharedStorageWorklet
context. This ensures the raw data is hidden from other contexts, thereby preserving privacy.
The URL Selection operation is a JavaScript class that must follow the rules below (these rules vary for each output gate, depending on their intended use case):
run()
method, which takes an array of objects containing URLs as its first parameter and a data object as its second parameter (when called, the data argument is optional).run()
method must return a number, which will equate to the number of the URL chosen.Note: Each output gate has a corresponding interface that defines the required structure of its class and run()
method. For URL Selection, see SharedStorageSelectURLOperation
.
Once the operation is defined, it needs to be registered using SharedStorageWorkletGlobalScope.register()
.
// ab-testing-worklet.js
class SelectURLOperation {
async run(urls, data) {
// Read the user's experiment group from shared storage
const experimentGroup = await this.sharedStorage.get("ab-testing-group");
// Return the group number
return experimentGroup;
}
}
register("ab-testing", SelectURLOperation);
Notice how the value set in our main app context is retrieved using WorkletSharedStorage.get()
. To reiterate, to preserve privacy and mitigate data leakage, you can read values from shared storage only within a worklet.
Note: It is possible to define and register multiple operations in the same shared storage worklet module script with different names; see SharedStorageOperation
for an example.
To use the operation defined in the worklet module, it needs to be added to the shared storage worklet using window.sharedStorage.worklet.addModule()
. In our main app context, this is done before we set the experiment group value, so that it is ready to use when needed:
async function injectContent() {
// Add the module to the shared storage worklet
await window.sharedStorage.worklet.addModule("ab-testing-worklet.js");
// Assign user to a random group (0 or 1) and store it in shared storage
window.sharedStorage.set("ab-testing-group", getExperimentGroup(), {
ignoreIfPresent: true,
});
}
Choose a URL and load it in a fenced frame
To run the operation defined in the worklet, we call WindowSharedStorage.selectURL()
. This method acts as a proxy to our worklet operation, accessing it securely and returning the result without leaking any data. selectURL()
is the correct method to call our user-defined worklet operation because it was defined with the appropriate class structure for a URL Selection operation, as discussed above.
selectURL()
expects an array of objects containing URLs to choose from, an optional options object, and for the underlying operation to return an integer that it can use to choose a URL.
// Run the URL selection operation
const fencedFrameConfig = await window.sharedStorage.selectURL(
"ab-testing",
[
{ url: `https://your-server.example/content/default-content.html` },
{ url: `https://your-server.example/content/experiment-content-a.html` },
],
{
resolveToConfig: true,
},
);
Because the options object contains resolveToConfig: true
, the returned Promise
will resolve with a FencedFrameConfig
object. This object can be set as the value of the HTMLFencedFrameElement.config
property, resulting in the content of the chosen URL being displayed in the corresponding <fencedframe>
element:
document.getElementById("content-slot").config = fencedFrameConfig;
The full app script looks like so:
// Randomly assigns a user to a group 0 or 1
function getExperimentGroup() {
return Math.round(Math.random());
}
async function injectContent() {
// Add the module to the shared storage worklet
await window.sharedStorage.worklet.addModule("ab-testing-worklet.js");
// Assign user to a random group (0 or 1) and store it in shared storage
window.sharedStorage.set("ab-testing-group", getExperimentGroup(), {
ignoreIfPresent: true,
});
// Run the URL selection operation
const fencedFrameConfig = await window.sharedStorage.selectURL(
"ab-testing",
[
{ url: `https://your-server.example/content/default-content.html` },
{ url: `https://your-server.example/content/experiment-content-a.html` },
],
{
resolveToConfig: true,
},
);
// Render the chosen URL into a fenced frame
document.getElementById("content-slot").config = fencedFrameConfig;
}
injectContent();
The key difference is that shared storage is intended for use with cross-origin data after storage has been partitioned.
localStorage
version of web storage.sessionStorage
.Another important difference between shared storage and web storage is that reading from shared storage is guarded (writing to storage behaves similarly). With localStorage
and sessionStorage
, you can read freely. With shared storage, reading can happen only within a shared storage worklet, and the origin used for reading in the worklet is the same as the browsing context that created it.
Additionally, you cannot extract shared storage data outside of a shared storage worklet, as a tracking protection. You must use one of the output gates to work with your data in shared storage.
Lastly, data in localStorage
persists until it is manually cleared. sessionStorage
clears at the end of a browsing session, whereas shared storage data clears 30 days after the last write call.
Represents the shared storage for a particular origin. It defines methods to write data to the shared storage.
Represents the shared storage for a particular origin as exposed to a standard browsing context. Among other things, it defines methods to use the available output gates, which act as proxies for the operations defined in the worklet.
Represents the shared storage for a particular origin within a worklet context. Among other things, it defines methods to read the shared storage data.
Represents the current origin's shared storage worklet. It contains the addModule()
method for adding modules. Unlike a regular Worklet
, the SharedStorageWorklet
can have only a single module added to it, for privacy reasons.
Represents the global scope of a SharedStorageWorklet
module. It contains the functionality to register a defined operation and access the shared storage.
Represents the base class for all different output gate operation types.
Represents a Run output gate operation.
Represents a URL Selection output gate operation.
Returns the WindowSharedStorage
object for the current origin.
To use the Shared Storage API in your sites, you must specify it in the privacy sandbox enrollment process. If you don't, the Shared Storage API methods won't run successfully.
You can test your Shared Storage API code locally without enrollment. To allow local testing, enable the following Chrome developer flag:
chrome://flags/#privacy-sandbox-enrollment-overrides
For extensive demos, see the Shared Storage API demo site, which also includes some Private Aggregation API examples.
Specifications Standards positionsOne browser vendor opposes this specification. Known standards positions are as follows:
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4