From 09f74e0b9c2e1f790e0bc8c3ae0e91f76270f8fb Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 19 Jul 2023 15:09:52 +0100 Subject: [PATCH 01/18] Add first draft of Shared Storage API landing page --- .../en-us/web/api/shared_storage_api/index.md | 243 ++++++++++++++++++ files/jsondata/GroupData.json | 16 ++ 2 files changed, 259 insertions(+) create mode 100644 files/en-us/web/api/shared_storage_api/index.md diff --git a/files/en-us/web/api/shared_storage_api/index.md b/files/en-us/web/api/shared_storage_api/index.md new file mode 100644 index 000000000000000..d8d7b5a57b6df53 --- /dev/null +++ b/files/en-us/web/api/shared_storage_api/index.md @@ -0,0 +1,243 @@ +--- +title: Shared Storage API +slug: Web/API/Shared_storage_API +page-type: web-api-overview +status: + - experimental +browser-compat: api.SharedStorage +--- + +{{SeeCompatTable}}{{DefaultAPISidebar("Shared Storage API")}} + +The **Shared Storage API** is a client-side storage mechanism that enables unpartitioned, cross-site data access in a privacy-preserving manner for specific use cases that require it. + +## Concepts and usage + +One major source of [privacy](/en-US/docs/Web/Privacy) and [security](/en-US/docs/Web/Security) problems on the web is third-party cookies set on content embedded in {{htmlelement("iframe")}} elements, which can be used to share information and track users across sites. + +To prevent cross-site tracking, browsers are working towards partitioning all forms of storage — this includes [Cookies](/en-US/docs/Web/HTTP/Cookies), [Web Storage](/en-US/docs/Web/API/Web_Storage_API), [IndexedDB](/en-US/docs/Web/API/IndexedDB_API), [Cache API](/en-US/docs/Web/API/Cache), etc. However, a major barrier to achieving this is that there are several legitimate use cases that rely on sharing information across sites, for example advertisers wishing to measure the reach of their ads across sites and generate reports, or site owners wishing to customize user experiences based on what group they are in, or what content they've already seen on other properties. + +The Shared Storage API provides a flexible solution to fulfill such use cases — aiming to provide the required data storage, processing, and sharing — but without sharing user data with parties that shouldn't have access to it. + +Like other storage APIs, you can write to shared storage at any time. However, you can only read shared storage data from inside a {{domxref("SharedStorageWorklet", "worklet", "", "nocode")}}. 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**. Output gates are mechanisms that fulfill a specific type of use case, for example selecting a URL from a provided list to display to the user based on shared storage data. Any results to be displayed to the user will be shown securely inside a [fenced frame](/en-US/docs/Web/API/Fenced_Frame_API) where they can't be accessed from the embedding page. + +### Use cases + +The Shared Storage API's currently available output gates are discussed in the sections below. In each section, we list typical use cases for each one, and link to guides that provide more information and code examples. + +> **Note:** More output gates will likely be added in the future, to support additional use cases. + +#### Select URL + +The **Select URL** output gate (via the {{domxref("WindowSharedStorage.selectURL", "selectURL()")}} method) is used to select a URL from a provided list to display to the user, based on shared storage data. This can be used for the following purposes: + +- [**Creative rotation**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/creative-rotation/): Store data such as creative IDs, view counts, and user interaction, to determine which creative users' see across different sites. This allows you to balance views and avoid oversaturation of certain content, which can help you avoid a negative user experience. +- [**A/B testing**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/ab-testing/): Assign a user to an experiment group, then store group details in shared storage to be accessed cross-site. +- [**Custom user experiences**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/known-customer/): Share custom content and calls-to-action based on a user's registration status or other user states. + +#### Run + +The **Run** output gate is intended as a generic way to process some shared storage data. + +The [Private Aggregation API](https://developer.chrome.com/docs/privacy-sandbox/private-aggregation/) can use the Run output gate to process shared storage data and generate aggregated reports. These can be used for the following use cases: + +- [**Unique reach reporting**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/unique-reach/): Content producers and advertisers often want to know how many unique people saw their content. You can use shared storage to report on the first time a user saw your ad or embedded publication, and prevent duplicative counting of that same user on a different site, giving you an aggregated noisy report of your approximate unique reach. +- [**User demographic reporting**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/user-demographics/): Content producers often want to understand the demographics of their audience. You can use shared storage to record user demographic data on your main site, and use aggregated reporting to report on it across other sites, in embedded contexts. +- [**K+ frequency measurement**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/k-freq-reach/): Sometimes described as "effective frequency", K frequency refers to the minimum number of views before a user will recognize or recall certain content (often used in the context of ad views). You can use shared storage to build reports of unique users that have seen a piece of content at least K times. + +## How does Shared Storage work? + +There are two parts to using the Shared Storage API — writing data to storage, and reading and processing it. To give you an idea of how these parts are handled, we'll walk you through the basic [A/B testing](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/ab-testing/) example from developer.chrome.com. This example assigns a user to an experiment group, stores the group details in shared storage, and then allows other sites to use that data when choosing a URL to display in a [fenced frame](/en-US/docs/Web/API/Fenced_Frame_API). + +### Writing to shared storage + +Writing the data is simple — you use methods defined on the {{domxref("SharedStorage")}} interface to {{domxref("SharedStorage.set", "set", "", "nocode")}}, {{domxref("SharedStorage.append", "append", "", "nocode")}}, or {{domxref("SharedStorage.delete", "delete", "", "nocode")}}/{{domxref("SharedStorage.clear", "clear", "", "nocode")}} data. + +This functionality is available in two difference contexts: + +- In the main browsing context that your site or app is running in, on {{domxref("WindowSharedStorage")}}, which is available via `window.sharedStorage`. +- In the context of your shared storage worklet, on {{domxref("WorkletSharedStorage")}}, which 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 to assign the current user to, and then run the {{domxref("SharedStorage.set", "window.sharedStorage.set()")}} function to assign the user to a group and save the result in shared storage: + +```js +// 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 name. + +### Reading and processing data from shared storage + +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 Select URL output gate to read the user's experiment group and then load a URL in a fenced frame based on their group. + +To use the output gate, you need to: + +- Define an operation in a worklet script to handle choosing the URL, and register it. +- Add the worklet module to your app context. +- Choose the URL using the worklet operation and load it in a fenced frame. + +Let's look at these one by one. + +#### Define an operation in a worklet + +The URL will be chosen based on the experiment group stored in shared storage. To retrieve this value choose a URL based on it, we need to define an operation in a {{domxref("SharedStorageWorklet")}} context — it must be inside a worklet to keep the raw data hidden from other contexts and therefore preserve privacy. + +The Select URL operation takes the form of a JavaScript class. It can be written in any way you like, as long as it follows certain rules (some of the rules for each output gate differ, depending on what kind of use case they fulfill): + +- The actual functionality must be contained inside an asynchronous `run()` method, which must have an array of objects containing URLs as its first paramater, and a data object as its second parameter (when called, the data argument is optional). +- The `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 signature of its `run()` method. For example, for Select URL, see {{domxref("SharedStorageSelectURLOperation.run()")}}. + +Once the operation is defined, it needs to be registered using {{domxref("SharedStorageWorkletGlobalScope.register()")}}. + +```js +// 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 corresponding URL (first or second item in the array) + return urls.indexOf(experimentGroup); + } +} + +register("ab-testing", SelectURLOperation); +``` + +Note how the value set in our main app context is retrieved using {{domxref("WorkletSharedStorage.get()")}} — to reiterate, you can only read values back out of shared storage inside a worklet. + +#### Add the worklet + +To make use of the operation defined in the worklet, it needs to be added to the main app using {{domxref("Worklet.addModule", "window.sharedStorage.worklet.addModule()")}}. This is done in our main app context, before we set the experiment group value, so that it is ready to use when needed: + +```js +async function injectContent() { + // Register 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 {{domxref("WindowSharedStorage.selectURL()")}} — this 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 `run()` method signature for a Select URL 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. + +```js +// 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 {{jsxref("Promise")}} will resolve with a {{domxref("FencedFrameConfig")}} object, which can be set as the value of the {{domxref("HTMLFencedFrameElement.config")}} property, resulting in the chosen URL being displayed in the associated {{htmlelement("fencedframe")}} element: + +```js +document.getElementById("content-slot").config = fencedFrameConfig; +``` + +The full app script looks like so: + +```js +// Randomly assigns a user to a group 0 or 1 +function getExperimentGroup() { + return Math.round(Math.random()); +} + +async function injectContent() { + // Register 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(); +``` + +## Interfaces + +- {{domxref("SharedStorage")}} + - : Represents the shared storage for a particular origin. Defines methods to write data to the shared storage. +- {{domxref("WindowSharedStorage")}} + - : Represents the shared storage for a particular origin, as it is exposed to a standard browsing context. Among others, defines methods to use the available output gates, which act as proxies for the operations defined in the worklet. +- {{domxref("WorkletSharedStorage")}} + - : Represents the shared storage for a particular origin, as it is exposed to a worklet context. Among others, defines methods to read the shared storage data. +- {{domxref("SharedStorageWorklet")}} + - : Contains the {{domxref("Worklet.addModule", "addModule()")}} method used to add a module to the shared storage worklet. Unlike a regular {{domxref("Worklet")}}, `SharedStorageWorklet` can only have a single module added to it, for privacy reasons. +- {{domxref("SharedStorageWorkletGlobalScope")}} + - : Represents the global scope of a {{domxref("SharedStorageWorklet")}} module. contains functionality to {{domxref("SharedStorageWorkletGlobalScope.register", "register", "", "nocode")}} a defined operation, and {{domxref("SharedStorageWorkletGlobalScope.sharedStorage", "access the shared storage", "", "nocode")}}. + +### Output gate operation signature definitions + +- {{domxref("SharedStorageOperation")}} + - : Represents the base class for all different output gate operation types. +- {{domxref("SharedStorageRunOperation")}} + - : Represents a Run output gate operation. +- {{domxref("SharedStorageSelectURLOperation")}} + - : Represents a Select URL output gate operation. + +### Extensions to other interfaces + +- {{domxref("Window.sharedStorage")}} + - : Returns the {{domxref("WindowSharedStorage")}} object for the current origin. + +## Examples + +For extensive demos, see [Shared Storage API demos](https://shared-storage-demo.web.app/) (which also includes some Private Aggregation API examples). + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/) on developer.chrome.com +- [The Privacy Sandbox](https://developer.chrome.com/docs/privacy-sandbox/) on developer.chrome.com diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index e8f31a86a4c93b6..5cbba94d805fda9 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -1259,6 +1259,22 @@ "properties": ["Navigator.serviceWorker"], "events": [] }, + "Shared Storage API": { + "overview": ["Shared Storage API"], + "interfaces": [ + "SharedStorage", + "SharedStorageOperation", + "SharedStorageRunOperation", + "SharedStorageSelectURLOperation", + "SharedStorageWorklet", + "SharedStorageWorkletGlobalScope", + "WindowSharedStorage", + "WorkletSharedStorage" + ], + "methods": [], + "properties": [], + "events": [] + }, "Storage": { "overview": ["Storage API"], "guides": [ From 7a1984efadc480c138b4fc1093042442edbd4aa9 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 19 Jul 2023 19:00:48 +0100 Subject: [PATCH 02/18] Add sharedstorage class --- .../en-us/web/api/shared_storage_api/index.md | 18 ++--- .../web/api/sharedstorage/append/index.md | 67 +++++++++++++++++ .../web/api/sharedstorage/clear/index.md | 53 ++++++++++++++ .../web/api/sharedstorage/delete/index.md | 64 ++++++++++++++++ files/en-us/web/api/sharedstorage/index.md | 51 +++++++++++++ .../en-us/web/api/sharedstorage/set/index.md | 73 +++++++++++++++++++ files/en-us/web/api/window/index.md | 2 + .../web/api/window/sharedstorage/index.md | 40 ++++++++++ files/jsondata/GroupData.json | 2 +- 9 files changed, 360 insertions(+), 10 deletions(-) create mode 100644 files/en-us/web/api/sharedstorage/append/index.md create mode 100644 files/en-us/web/api/sharedstorage/clear/index.md create mode 100644 files/en-us/web/api/sharedstorage/delete/index.md create mode 100644 files/en-us/web/api/sharedstorage/index.md create mode 100644 files/en-us/web/api/sharedstorage/set/index.md create mode 100644 files/en-us/web/api/window/sharedstorage/index.md diff --git a/files/en-us/web/api/shared_storage_api/index.md b/files/en-us/web/api/shared_storage_api/index.md index d8d7b5a57b6df53..ef7c2411ed2e22f 100644 --- a/files/en-us/web/api/shared_storage_api/index.md +++ b/files/en-us/web/api/shared_storage_api/index.md @@ -47,7 +47,7 @@ The [Private Aggregation API](https://developer.chrome.com/docs/privacy-sandbox/ - [**User demographic reporting**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/user-demographics/): Content producers often want to understand the demographics of their audience. You can use shared storage to record user demographic data on your main site, and use aggregated reporting to report on it across other sites, in embedded contexts. - [**K+ frequency measurement**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/k-freq-reach/): Sometimes described as "effective frequency", K frequency refers to the minimum number of views before a user will recognize or recall certain content (often used in the context of ad views). You can use shared storage to build reports of unique users that have seen a piece of content at least K times. -## How does Shared Storage work? +## How does shared storage work? There are two parts to using the Shared Storage API — writing data to storage, and reading and processing it. To give you an idea of how these parts are handled, we'll walk you through the basic [A/B testing](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/ab-testing/) example from developer.chrome.com. This example assigns a user to an experiment group, stores the group details in shared storage, and then allows other sites to use that data when choosing a URL to display in a [fenced frame](/en-US/docs/Web/API/Fenced_Frame_API). @@ -69,14 +69,14 @@ function getExperimentGroup() { } async function injectContent() { - // Assign user to a random group (0 or 1) and store it in Shared Storage + // 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 name. +> _Note:_ The `ignoreIfPresent: true` option causes the `set()` function to abort if the shared storage already contains a data item with the specified key. ### Reading and processing data from shared storage @@ -84,8 +84,8 @@ As mentioned above, to extract useful results from a shared storage worklet you To use the output gate, you need to: -- Define an operation in a worklet script to handle choosing the URL, and register it. -- Add the worklet module to your app context. +- Define an operation in a worklet module script to handle choosing the URL, and register it. +- Add the module to your shared storage worklet. - Choose the URL using the worklet operation and load it in a fenced frame. Let's look at these one by one. @@ -107,7 +107,7 @@ Once the operation is defined, it needs to be registered using {{domxref("Shared // ab-testing-worklet.js class SelectURLOperation { async run(urls, data) { - // Read the user's experiment group from Shared Storage + // Read the user's experiment group from shared storage const experimentGroup = await this.sharedStorage.get("ab-testing-group"); // Return the corresponding URL (first or second item in the array) @@ -122,11 +122,11 @@ Note how the value set in our main app context is retrieved using {{domxref("Wor #### Add the worklet -To make use of the operation defined in the worklet, it needs to be added to the main app using {{domxref("Worklet.addModule", "window.sharedStorage.worklet.addModule()")}}. This is done in our main app context, before we set the experiment group value, so that it is ready to use when needed: +To make use of the operation defined in the worklet module, it needs to be added to the shared storage worklet using {{domxref("Worklet.addModule", "window.sharedStorage.worklet.addModule()")}}. This is done in our main app context, before we set the experiment group value, so that it is ready to use when needed: ```js async function injectContent() { - // Register the shared storage worklet + // 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 @@ -171,7 +171,7 @@ function getExperimentGroup() { } async function injectContent() { - // Register the shared storage worklet + // 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 diff --git a/files/en-us/web/api/sharedstorage/append/index.md b/files/en-us/web/api/sharedstorage/append/index.md new file mode 100644 index 000000000000000..8295c76c2096acc --- /dev/null +++ b/files/en-us/web/api/sharedstorage/append/index.md @@ -0,0 +1,67 @@ +--- +title: "SharedStorage: append() method" +short-title: append() +slug: Web/API/SharedStorage/append +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.SharedStorage.append +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`append()`** method of the +{{domxref("SharedStorage")}} interface appends a string to the value of an existing key/value pair in the current origin's shared storage. + +## Syntax + +```js-nolint +append(key, value) +``` + +### Parameters + +- `key` + - : A string representing the key of the key/value pair you want to append a string to. +- `value` + - : A string that you want to append to the existing value. + +### Return value + +A {{jsxref("Promise")}} that fulfills with `undefined`. + +### Exceptions + +In the case of {{domxref("WindowSharedStorage")}}: + +- If the key/value pair doesn't exist in the shared storage, the operation is aborted silently, without rejecting. + +In the case of {{domxref("WorkletSharedStorage")}}, the `Promise` rejects with a {{jsxref("TypeError")}}: + +- If the key/value pair doesn't exist in the shared storage. +- If the worklet module has not been added with {{domxref("Worklet.addModule", "SharedStorageWorklet.addModule()")}}. +- If the appended entry was not successfully stored in the database for some other reason. + +In both cases: + +- The `Promise` rejects with a {{jsxref("TypeError")}} if `key` and/or `value` exceed the browser-defined maximum length. + +## Examples + +```js +window.sharedStorage + .append("integer-list", ",9") + .then(console.log("Value appended to integer list")); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstorage/clear/index.md b/files/en-us/web/api/sharedstorage/clear/index.md new file mode 100644 index 000000000000000..78383f3a658055f --- /dev/null +++ b/files/en-us/web/api/sharedstorage/clear/index.md @@ -0,0 +1,53 @@ +--- +title: "SharedStorage: clear() method" +short-title: clear() +slug: Web/API/SharedStorage/clear +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.SharedStorage.clear +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`clear()`** method of the +{{domxref("SharedStorage")}} interface clears the current origin's shared storage, removing all data from it. + +## Syntax + +```js-nolint +clear() +``` + +### Parameters + +None. + +### Return value + +A {{jsxref("Promise")}} that fulfills with `undefined`. + +### Exceptions + +In the case of {{domxref("WorkletSharedStorage")}}, the `Promise` rejects with a {{jsxref("TypeError")}}: + +- If the worklet module has not been added with {{domxref("Worklet.addModule", "SharedStorageWorklet.addModule()")}}. +- If the clearing operation was not successful for some reason. + +## Examples + +```js +window.sharedStorage.clear().then(console.log("Shared storage cleared")); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstorage/delete/index.md b/files/en-us/web/api/sharedstorage/delete/index.md new file mode 100644 index 000000000000000..e874797bc1e83c9 --- /dev/null +++ b/files/en-us/web/api/sharedstorage/delete/index.md @@ -0,0 +1,64 @@ +--- +title: "SharedStorage: delete() method" +short-title: delete() +slug: Web/API/SharedStorage/delete +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.SharedStorage.delete +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`delete()`** method of the +{{domxref("SharedStorage")}} interface deletes an existing key/value pair from the current origin's shared storage. + +## Syntax + +```js-nolint +delete(key) +``` + +### Parameters + +- `key` + - : A string representing the key of the key/value pair you want to delete. + +### Return value + +A {{jsxref("Promise")}} that fulfills with `undefined`. + +### Exceptions + +In the case of {{domxref("WindowSharedStorage")}}: + +- If the key/value pair doesn't exist in the shared storage, the operation is aborted silently, without rejecting. + +In the case of {{domxref("WorkletSharedStorage")}}, the `Promise` rejects with a {{jsxref("TypeError")}}: + +- If the key/value pair doesn't exist in the shared storage, or the delete operation was unsuccessful for some other reason. +- If the worklet module has not been added with {{domxref("Worklet.addModule", "SharedStorageWorklet.addModule()")}}. + +In both cases: + +- The `Promise` rejects with a {{jsxref("TypeError")}} if `key` exceeds the browser-defined maximum length. + +## Examples + +```js +window.sharedStorage + .delete("ab-testing-group") + .then(console.log("Value deleted")); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstorage/index.md b/files/en-us/web/api/sharedstorage/index.md new file mode 100644 index 000000000000000..86ebee638e2b7f2 --- /dev/null +++ b/files/en-us/web/api/sharedstorage/index.md @@ -0,0 +1,51 @@ +--- +title: SharedStorage +slug: Web/API/SharedStorage +page-type: web-api-interface +status: + - experimental +browser-compat: api.SharedStorage +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`SharedStorage`** interface of the {{domxref("Shared Storage API", "Shared Storage API", "", "nocode")}} represents the shared storage for a particular origin, defining methods to write data to the shared storage. + +`SharedStorage` is the base class for: + +- {{domxref("WindowSharedStorage")}}, accessed via {{domxref("Window.sharedStorage")}}. +- {{domxref("WorkletSharedStorage")}}, accessed via {{domxref("SharedStorageWorkletGlobalScope.sharedStorage")}}. + +{{InheritanceDiagram}} + +## Instance methods + +- {{domxref("SharedStorage.append", "append()")}} {{Experimental_Inline}} + - : Appends a string to the value of an existing key/value pair in the current origin's shared storage. +- {{domxref("SharedStorage.clear", "clear()")}} {{Experimental_Inline}} + - : Clears the current origin's shared storage, removing all data from it. +- {{domxref("SharedStorage.delete", "delete()")}} {{Experimental_Inline}} + - : Deletes an existing key/value pair from the current origin's shared storage. +- {{domxref("SharedStorage.set", "set()")}} {{Experimental_Inline}} + - : Stores new key/value pair in the current origin's shared storage, or updates an existing one. + +## Examples + +```js +window.sharedStorage + .set("ab-testing-group", "0") + .then(console.log("Value saved to shared storage")); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- {{domxref("WindowSharedStorage")}} +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstorage/set/index.md b/files/en-us/web/api/sharedstorage/set/index.md new file mode 100644 index 000000000000000..359a00c82261e3b --- /dev/null +++ b/files/en-us/web/api/sharedstorage/set/index.md @@ -0,0 +1,73 @@ +--- +title: "SharedStorage: set() method" +short-title: set() +slug: Web/API/SharedStorage/set +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.SharedStorage.set +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`set()`** method of the +{{domxref("SharedStorage")}} interface stores new key/value pair in the current origin's shared storage, or updates an existing one. + +## Syntax + +```js-nolint +set(key, value) +set(key, value, options) +``` + +### Parameters + +- `key` + - : A string representing the key of the key/value pair you want to add or update. +- `value` + - : A string representing the value you want to add or update. +- `options` {{optional_inline}} + - : An options object containing the following properties: + - `ignoreIfPresent` + - : A boolean value that, if set to `true`, will cause the set operation to abort if a key/value pair with the specified `key` already exists. The default value, `false`, will cause the set operation to go ahead and overwrite the previous value, in such cases. + +### Return value + +A {{jsxref("Promise")}} that fulfills with `undefined`. + +### Exceptions + +In the case of {{domxref("WindowSharedStorage")}}: + +- If the key/value pair doesn't exist in the shared storage, the operation is aborted silently, without rejecting. + +In the case of {{domxref("WorkletSharedStorage")}}, the `Promise` rejects with a {{jsxref("TypeError")}}: + +- If the worklet module has not been added with {{domxref("Worklet.addModule", "SharedStorageWorklet.addModule()")}}. +- If the created/updated entry was not successfully stored in the database for some other reason. + +In both cases: + +- The `Promise` rejects with a {{jsxref("TypeError")}} if `key` and/or `value` exceed the browser-defined maximum length. + +## Examples + +```js +window.sharedStorage + .set("ab-testing-group", "0", { + ignoreIfPresent: true, + }) + .then(console.log("Set operation completed")); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/window/index.md b/files/en-us/web/api/window/index.md index 602c69e8d5a4001..428c0e922dd52ca 100644 --- a/files/en-us/web/api/window/index.md +++ b/files/en-us/web/api/window/index.md @@ -121,6 +121,8 @@ Note that properties which are objects (e.g., for overriding the prototype of bu - : Returns an object reference to the window object itself. - {{domxref("Window.sessionStorage")}} - : Returns a reference to the session storage object used to store data that may only be accessed by the origin that created it. +- {{domxref("Window.sharedStorage")}} {{ReadOnlyInline}} + - : Returns the {{domxref("WindowSharedStorage")}} object for the current origin. This is the main entry point for writing data to shared storage using the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API). - {{domxref("Window.speechSynthesis")}} {{ReadOnlyInline}} - : Returns a {{domxref("SpeechSynthesis")}} object, which is the entry point into using [Web Speech API](/en-US/docs/Web/API/Web_Speech_API) speech synthesis functionality. - {{domxref("Window.statusbar")}} {{ReadOnlyInline}} diff --git a/files/en-us/web/api/window/sharedstorage/index.md b/files/en-us/web/api/window/sharedstorage/index.md new file mode 100644 index 000000000000000..14a80eb9b3d5e06 --- /dev/null +++ b/files/en-us/web/api/window/sharedstorage/index.md @@ -0,0 +1,40 @@ +--- +title: "Window: sharedStorage property" +short-title: sharedStorage +slug: Web/API/Window/sharedStorage +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.Window.sharedStorage +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The global read-only **`sharedStorage`** property returns the {{domxref("WindowSharedStorage")}} object for the current origin. This is the main entry point for writing data to shared storage using the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API). + +> **Note:** `sharedStorage` is not available inside workers. It is implemented by [`Window`](/en-US/docs/Web/API/Window#scheduler), and is also available in shared storage worklets (see {{domxref("SharedStorageWorkletGlobalScope.sharedStorage")}}, which returns {{domxref("WorkletSharedStorage")}}). + +## Value + +A {{domxref("WindowSharedStorage")}} object instance. + +## Examples + +```js +window.sharedStorage + .set("ab-testing-group", "0") + .then(console.log("Value saved to shared storage")); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- {{domxref("WindowSharedStorage")}} +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index 5cbba94d805fda9..d7dd954504654d2 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -1272,7 +1272,7 @@ "WorkletSharedStorage" ], "methods": [], - "properties": [], + "properties": ["Window.sharedStorage"], "events": [] }, "Storage": { From d4dced46d8a437f538ad1a4d9e2b6d1cbc6999d7 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Sun, 23 Jul 2023 21:34:01 +0100 Subject: [PATCH 03/18] Lots more progress on documenting the interfaces --- .../en-us/web/api/shared_storage_api/index.md | 18 +-- .../web/api/sharedstorageoperation/index.md | 53 +++++++ .../api/sharedstoragerunoperation/index.md | 90 ++++++++++++ .../sharedstoragerunoperation/run/index.md | 45 ++++++ .../web/api/sharedstorageworklet/index.md | 68 +++++++++ .../sharedstorageworkletglobalscope/index.md | 55 ++++++++ .../register/index.md | 71 ++++++++++ .../sharedstorage/index.md | 47 +++++++ .../web/api/windowsharedstorage/index.md | 80 +++++++++++ .../web/api/windowsharedstorage/run/index.md | 75 ++++++++++ .../windowsharedstorage/selecturl/index.md | 107 ++++++++++++++ .../api/windowsharedstorage/worklet/index.md | 70 ++++++++++ files/en-us/web/api/worklet/index.md | 11 ++ .../api/workletsharedstorage/context/index.md | 34 +++++ .../api/workletsharedstorage/entries/index.md | 53 +++++++ .../web/api/workletsharedstorage/get/index.md | 132 ++++++++++++++++++ .../web/api/workletsharedstorage/index.md | 115 +++++++++++++++ .../api/workletsharedstorage/keys/index.md | 53 +++++++ .../api/workletsharedstorage/length/index.md | 58 ++++++++ .../remainingbudget/index.md | 58 ++++++++ .../api/workletsharedstorage/values/index.md | 53 +++++++ 21 files changed, 1337 insertions(+), 9 deletions(-) create mode 100644 files/en-us/web/api/sharedstorageoperation/index.md create mode 100644 files/en-us/web/api/sharedstoragerunoperation/index.md create mode 100644 files/en-us/web/api/sharedstoragerunoperation/run/index.md create mode 100644 files/en-us/web/api/sharedstorageworklet/index.md create mode 100644 files/en-us/web/api/sharedstorageworkletglobalscope/index.md create mode 100644 files/en-us/web/api/sharedstorageworkletglobalscope/register/index.md create mode 100644 files/en-us/web/api/sharedstorageworkletglobalscope/sharedstorage/index.md create mode 100644 files/en-us/web/api/windowsharedstorage/index.md create mode 100644 files/en-us/web/api/windowsharedstorage/run/index.md create mode 100644 files/en-us/web/api/windowsharedstorage/selecturl/index.md create mode 100644 files/en-us/web/api/windowsharedstorage/worklet/index.md create mode 100644 files/en-us/web/api/workletsharedstorage/context/index.md create mode 100644 files/en-us/web/api/workletsharedstorage/entries/index.md create mode 100644 files/en-us/web/api/workletsharedstorage/get/index.md create mode 100644 files/en-us/web/api/workletsharedstorage/index.md create mode 100644 files/en-us/web/api/workletsharedstorage/keys/index.md create mode 100644 files/en-us/web/api/workletsharedstorage/length/index.md create mode 100644 files/en-us/web/api/workletsharedstorage/remainingbudget/index.md create mode 100644 files/en-us/web/api/workletsharedstorage/values/index.md diff --git a/files/en-us/web/api/shared_storage_api/index.md b/files/en-us/web/api/shared_storage_api/index.md index ef7c2411ed2e22f..9abd0ca6ea59ea5 100644 --- a/files/en-us/web/api/shared_storage_api/index.md +++ b/files/en-us/web/api/shared_storage_api/index.md @@ -39,13 +39,13 @@ The **Select URL** output gate (via the {{domxref("WindowSharedStorage.selectURL #### Run -The **Run** output gate is intended as a generic way to process some shared storage data. +The **Run** output gate (via the {{domxref("WindowSharedStorage.run", "run()")}} method) is intended as a generic way to process some shared storage data. The [Private Aggregation API](https://developer.chrome.com/docs/privacy-sandbox/private-aggregation/) can use the Run output gate to process shared storage data and generate aggregated reports. These can be used for the following use cases: - [**Unique reach reporting**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/unique-reach/): Content producers and advertisers often want to know how many unique people saw their content. You can use shared storage to report on the first time a user saw your ad or embedded publication, and prevent duplicative counting of that same user on a different site, giving you an aggregated noisy report of your approximate unique reach. - [**User demographic reporting**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/user-demographics/): Content producers often want to understand the demographics of their audience. You can use shared storage to record user demographic data on your main site, and use aggregated reporting to report on it across other sites, in embedded contexts. -- [**K+ frequency measurement**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/k-freq-reach/): Sometimes described as "effective frequency", K frequency refers to the minimum number of views before a user will recognize or recall certain content (often used in the context of ad views). You can use shared storage to build reports of unique users that have seen a piece of content at least K times. +- [**K+ frequency measurement**](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/k-freq-reach/): Sometimes described as "effective frequency", K+ frequency refers to the minimum number of views before a user will recognize or recall certain content (often used in the context of ad views). You can use shared storage to build reports of unique users that have seen a piece of content at least K times. ## How does shared storage work? @@ -80,7 +80,7 @@ async function injectContent() { ### Reading and processing data from shared storage -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 Select URL output gate to read the user's experiment group and then load a URL in a fenced frame based on their group. +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 Select URL output gate to read the user's experiment group and then load a URL in a fenced frame based on their group. To use the output gate, you need to: @@ -88,7 +88,7 @@ To use the output gate, you need to: - Add the module to your shared storage worklet. - Choose the URL using the worklet operation and load it in a fenced frame. -Let's look at these one by one. +Below we'll look at these steps one by one. #### Define an operation in a worklet @@ -201,15 +201,15 @@ injectContent(); ## Interfaces - {{domxref("SharedStorage")}} - - : Represents the shared storage for a particular origin. Defines methods to write data to the shared storage. + - : Represents the shared storage for a particular origin. It defines methods to write data to the shared storage. - {{domxref("WindowSharedStorage")}} - - : Represents the shared storage for a particular origin, as it is exposed to a standard browsing context. Among others, 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, as it is 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. - {{domxref("WorkletSharedStorage")}} - - : Represents the shared storage for a particular origin, as it is exposed to a worklet context. Among others, defines methods to read the shared storage data. + - : Represents the shared storage for a particular origin, as it is exposed to a worklet context. Among other things, it defines methods to read the shared storage data. - {{domxref("SharedStorageWorklet")}} - - : Contains the {{domxref("Worklet.addModule", "addModule()")}} method used to add a module to the shared storage worklet. Unlike a regular {{domxref("Worklet")}}, `SharedStorageWorklet` can only have a single module added to it, for privacy reasons. + - : Represents the current origin's shared storage worklet. Contains the {{domxref("Worklet.addModule", "addModule()")}} method used to add a module to it. Unlike a regular {{domxref("Worklet")}}, `SharedStorageWorklet` can only have a single module added to it, for privacy reasons. - {{domxref("SharedStorageWorkletGlobalScope")}} - - : Represents the global scope of a {{domxref("SharedStorageWorklet")}} module. contains functionality to {{domxref("SharedStorageWorkletGlobalScope.register", "register", "", "nocode")}} a defined operation, and {{domxref("SharedStorageWorkletGlobalScope.sharedStorage", "access the shared storage", "", "nocode")}}. + - : Represents the global scope of a {{domxref("SharedStorageWorklet")}} module. Contains functionality to {{domxref("SharedStorageWorkletGlobalScope.register", "register", "", "nocode")}} a defined operation, and {{domxref("SharedStorageWorkletGlobalScope.sharedStorage", "access the shared storage", "", "nocode")}}. ### Output gate operation signature definitions diff --git a/files/en-us/web/api/sharedstorageoperation/index.md b/files/en-us/web/api/sharedstorageoperation/index.md new file mode 100644 index 000000000000000..90b69df8e3b9d2f --- /dev/null +++ b/files/en-us/web/api/sharedstorageoperation/index.md @@ -0,0 +1,53 @@ +--- +title: SharedStorageOperation +slug: Web/API/SharedStorageOperation +page-type: web-api-interface +status: + - experimental +browser-compat: api.SharedStorageOperation +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`SharedStorageOperation`** interface of the {{domxref("Shared Storage API", "Shared Storage API", "", "nocode")}} represents the base class for all different output gate operation types. + +{{InheritanceDiagram}} + +The different output gate types are detailed below: + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionDefined byInvoked by
Select URLUsed to select a URL from a provided list to display to the user, based on shared storage data.{{domxref("SharedStorageSelectURLOperation")}}{{domxref("WindowSharedStorage.selectURL()", "selectURL()")}}
RunA generic way to process some shared storage data. Used, for example, by the Private Aggregation API to process shared storage data and generate aggregated reports. {{domxref("SharedStorageRunOperation")}}{{domxref("WindowSharedStorage.run()", "run()")}}
+ +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstoragerunoperation/index.md b/files/en-us/web/api/sharedstoragerunoperation/index.md new file mode 100644 index 000000000000000..83ce9ce5d38bc48 --- /dev/null +++ b/files/en-us/web/api/sharedstoragerunoperation/index.md @@ -0,0 +1,90 @@ +--- +title: SharedStorageRunOperation +slug: Web/API/SharedStorageRunOperation +page-type: web-api-interface +status: + - experimental +browser-compat: api.SharedStorageRunOperation +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`SharedStorageRunOperation`** interface of the {{domxref("Shared Storage API", "Shared Storage API", "", "nocode")}} represents a run output gate operation. + +{{InheritanceDiagram}} + +## Instance methods + +- {{domxref("SharedStorageRunOperation.run", "run()")}} {{Experimental_Inline}} + - : Defines the structure that the `run()` method defined inside a run output gate operation should conform to. + +## Examples + +In a worklet, a class called `ReachMeasurementOperation` is defined and registered using {{domxref("SharedStorageWorkletGlobalScope.register()")}} with a name of `reach-measurement`. `SharedStorageRunOperation` defines the structure this class needs to conform to, which in real terms means the parameters the `run()` method is required to have. + +```js +// reach-measurement-worklet.js +const SCALE_FACTOR = 65536; + +function convertContentIdToBucket(contentId) { + return BigInt(contentId); +} + +class ReachMeasurementOperation { + async run(data) { + const { contentId } = data; + + // Read from Shared Storage + const key = "has-reported-content"; + const hasReportedContent = (await this.sharedStorage.get(key)) === "true"; + + // Do not report if a report has been sent already + if (hasReportedContent) { + return; + } + + // Generate the aggregation key and the aggregatable value + const bucket = convertContentIdToBucket(contentId); + const value = 1 * SCALE_FACTOR; + + // Send an aggregatable report via the Private Aggregation API + privateAggregation.sendHistogramReport({ bucket, value }); + + // Set the report submission status flag + await this.sharedStorage.set(key, true); + } +} + +// Register the operation +register("reach-measurement", ReachMeasurementOperation); +``` + +In the main browsing context, the `reach-measurement` operation is invoked using the {{domxref("WindowSharedStorage.run()")}} method: + +```js +async function measureUniqueReach() { + // Load the Shared Storage worklet + await window.sharedStorage.worklet.addModule("reach-measurement-worklet.js"); + + // Run the reach measurement operation + await window.sharedStorage.run("reach-measurement", { + data: { contentId: "1234" }, + }); +} + +measureUniqueReach(); +``` + +See [Unique reach measurement](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/unique-reach/) for more details of this example, and [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) for more examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstoragerunoperation/run/index.md b/files/en-us/web/api/sharedstoragerunoperation/run/index.md new file mode 100644 index 000000000000000..688084e88de5e0e --- /dev/null +++ b/files/en-us/web/api/sharedstoragerunoperation/run/index.md @@ -0,0 +1,45 @@ +--- +title: "SharedStorageRunOperation: run() method" +short-title: run() +slug: Web/API/SharedStorageRunOperation/run +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.SharedStorageRunOperation.run +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`run()`** method of the +{{domxref("SharedStorageRunOperation")}} interface defines the structure that the `run()` method defined inside a run output gate operation should conform to. + +## Syntax + +```js-nolint +run(data) +``` + +### Parameters + +- `data` + - : An object representing any data required for executing the operation. + +### Return value + +A {{jsxref("Promise")}} that fulfills with `undefined`. + +## Examples + +See the main {{domxref("SharedStorageRunOperation")}} page for an example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstorageworklet/index.md b/files/en-us/web/api/sharedstorageworklet/index.md new file mode 100644 index 000000000000000..69631e82c895272 --- /dev/null +++ b/files/en-us/web/api/sharedstorageworklet/index.md @@ -0,0 +1,68 @@ +--- +title: SharedStorageWorklet +slug: Web/API/SharedStorageWorklet +page-type: web-api-interface +status: + - experimental +browser-compat: api.SharedStorageWorklet +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`SharedStorageWorklet`** interface of the {{domxref("Shared Storage API", "Shared Storage API", "", "nocode")}} represents the current origin's shared storage worklet. + +`SharedStorageWorklet` has no properties or methods directly defined on it; it inherits the {{domxref("Worklet.addModule", "addModule()")}} method from the {{domxref("Worklet")}} interface, which is used to add a module to it. Unlike a regular {{domxref("Worklet")}}, `SharedStorageWorklet` can only have a single module added to it, for privacy reasons. + +`SharedStorageWorklet` is accessed via {{domxref("WindowSharedStorage.worklet")}}. + +{{InheritanceDiagram}} + +## Examples + +```js +// 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(); +``` + +See the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) landing page for a walkthrough of this example, and links to other examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstorageworkletglobalscope/index.md b/files/en-us/web/api/sharedstorageworkletglobalscope/index.md new file mode 100644 index 000000000000000..41b7bf904ec5b05 --- /dev/null +++ b/files/en-us/web/api/sharedstorageworkletglobalscope/index.md @@ -0,0 +1,55 @@ +--- +title: SharedStorageWorkletGlobalScope +slug: Web/API/SharedStorageWorkletGlobalScope +page-type: web-api-interface +status: + - experimental +browser-compat: api.SharedStorageWorkletGlobalScope +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`SharedStorageWorkletGlobalScope`** interface of the {{domxref("Shared Storage API", "Shared Storage API", "", "nocode")}} represents the global scope of a {{domxref("SharedStorageWorklet")}} module. + +{{InheritanceDiagram}} + +## Instance properties + +- {{domxref("SharedStorageWorkletGlobalScope.sharedStorage", "sharedStorage")}} {{Experimental_Inline}} + - : Contains a {{domxref("WorkletSharedStorage")}} object instance representing the shared storage for a particular origin, as it is exposed to a worklet context. + +## Instance methods + +- {{domxref("SharedStorageWorkletGlobalScope.register", "register()")}} {{Experimental_Inline}} + - : Registers an {{domxref("SharedStorageOperation", "operation", "", "nocode")}} defined inside the current worklet module. + +## Examples + +```js +// 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 corresponding URL (first or second item in the array) + return urls.indexOf(experimentGroup); + } +} + +register("ab-testing", SelectURLOperation); +``` + +See the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) landing page for a walkthrough of this example, and links to other examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstorageworkletglobalscope/register/index.md b/files/en-us/web/api/sharedstorageworkletglobalscope/register/index.md new file mode 100644 index 000000000000000..a2e88db1eb34df1 --- /dev/null +++ b/files/en-us/web/api/sharedstorageworkletglobalscope/register/index.md @@ -0,0 +1,71 @@ +--- +title: "SharedStorageWorkletGlobalScope: register() method" +short-title: register() +slug: Web/API/SharedStorageWorkletGlobalScope/register +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.SharedStorageWorkletGlobalScope.register +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`register()`** method of the +{{domxref("SharedStorageWorkletGlobalScope")}} interface registers an {{domxref("SharedStorageOperation", "operation", "", "nocode")}} defined inside the current worklet module. + +## Syntax + +```js-nolint +register(name, operationCtor) +``` + +### Parameters + +- `name` + - : A string representing the name you want to register the operation with. When the operation is invoked (for example via {{domxref("WindowSharedStorage.run()")}} or {{domxref("WindowSharedStorage.selectURL()")}}), the name is used to identify the operation you want to run. +- `operationCtor` + - : The class name of the operation to be registered. In real terms, this is the class constructor, which is invoked behind the scenes when the operation is run. + +### Return value + +None (`undefined`). + +### Exceptions + +- {{jsxref("TypeError")}} + - : Thrown if: + - An operation has already been registered with the specified name. + - The `operationCtor` is not a valid constructor. + - The class does not contain a valid `run()` method. + - The worklet module has not been added with {{domxref("Worklet.addModule", "SharedStorageWorklet.addModule()")}}. + +## Examples + +```js +// 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 corresponding URL (first or second item in the array) + return urls.indexOf(experimentGroup); + } +} + +register("ab-testing", SelectURLOperation); +``` + +See the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) landing page for a walkthrough of this example, and links to other examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstorageworkletglobalscope/sharedstorage/index.md b/files/en-us/web/api/sharedstorageworkletglobalscope/sharedstorage/index.md new file mode 100644 index 000000000000000..ae09b1653fce340 --- /dev/null +++ b/files/en-us/web/api/sharedstorageworkletglobalscope/sharedstorage/index.md @@ -0,0 +1,47 @@ +--- +title: "SharedStorageWorkletGlobalScope: sharedStorage property" +short-title: sharedStorage +slug: Web/API/SharedStorageWorkletGlobalScope/sharedStorage +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.SharedStorageWorkletGlobalScope.sharedStorage +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`context`** read-only property of the +{{domxref("SharedStorageWorkletGlobalScope")}} interface contains a {{domxref("WorkletSharedStorage")}} object instance representing the shared storage for a particular origin, as it is exposed to a worklet context. + +## Value + +A {{domxref("WorkletSharedStorage")}} object instance. + +## Examples + +```js +// 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 corresponding URL (first or second item in the array) + return urls.indexOf(experimentGroup); + } +} + +register("ab-testing", SelectURLOperation); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/windowsharedstorage/index.md b/files/en-us/web/api/windowsharedstorage/index.md new file mode 100644 index 000000000000000..944d01705010f72 --- /dev/null +++ b/files/en-us/web/api/windowsharedstorage/index.md @@ -0,0 +1,80 @@ +--- +title: WindowSharedStorage +slug: Web/API/WindowSharedStorage +page-type: web-api-interface +status: + - experimental +browser-compat: api.WindowSharedStorage +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`WindowSharedStorage`** interface of the {{domxref("Shared Storage API", "Shared Storage API", "", "nocode")}} represents the shared storage for a particular origin, as it is exposed to a standard browsing context. + +`WindowSharedStorage` is accessed via {{domxref("Window.sharedStorage")}}. + +{{InheritanceDiagram}} + +## Instance properties + +- {{domxref("WindowSharedStorage.worklet", "worklet")}} {{Experimental_Inline}} + - : Contains the {{domxref("SharedStorageWorklet")}} instance representing the shared storage worklet for the current origin. `SharedStorageWorklet` has the {{domxref("Worklet.addModule", "addModule()")}} method available on it, which is used to add a module to the shared storage worklet. + +## Instance methods + +_`WindowSharedStorage` inherits properties from its parent interface, {{domxref("SharedStorage")}}._ + +- {{domxref("WindowSharedStorage.run", "run()")}} {{Experimental_Inline}} + - : Executes a run operation registered in a module added to the {{domxref("SharedStorageWorklet")}} associated with the current origin. +- {{domxref("WindowSharedStorage.selectURL", "selectURL()")}} {{Experimental_Inline}} + - : Executes a select URL operation registered in a module added to the {{domxref("SharedStorageWorklet")}} associated with the current origin. + +## Examples + +```js +// 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(); +``` + +See the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) landing page for a walkthrough of this example, and links to other examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/windowsharedstorage/run/index.md b/files/en-us/web/api/windowsharedstorage/run/index.md new file mode 100644 index 000000000000000..965ea18ca39bf63 --- /dev/null +++ b/files/en-us/web/api/windowsharedstorage/run/index.md @@ -0,0 +1,75 @@ +--- +title: "WindowSharedStorage: run() method" +short-title: run() +slug: Web/API/WindowSharedStorage/run +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.WindowSharedStorage.run +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`run()`** method of the +{{domxref("WindowSharedStorage")}} interface executes a run operation registered in a module added to the {{domxref("SharedStorageWorklet")}} associated with the current origin. + +> **Note:** The **Run** output gate is intended as a generic way to process some shared storage data. + +## Syntax + +```js-nolint +run(name) +run(name, options) +``` + +### Parameters + +- `name` + - : A string representing the name of the operation registered inside the shared storage worklet module that is to be run. This must match the name given to the operation when it is registered with {{domxref("SharedStorageWorkletGlobalScope.register()")}}. +- `options` {{optional_inline}} + - : An options object, which can contain the following properties: + - `data` {{optional_inline}} + - : An object representing any data required for executing the operation. + - `keepAlive` {{optional_inline}} + - : A boolean value. If set to `true`, the {{domxref("SharedStorageWorkletGlobalScope")}} of the associated worklet is kept alive, and the operation can be run multiple times. The default value, `false`, means that the {{domxref("SharedStorageWorkletGlobalScope")}} is terminated after the operation is run. In such cases, to use the worklet module again it would have to be re-added using {{domxref("Worklet.addModule", "addModule()")}}. + +### Return value + +A {{jsxref("Promise")}} that fulfills with `undefined`. + +### Exceptions + +- {{jsxref("TypeError")}} + - : Thrown if: + - The worklet module has not yet been added with {{domxref("Worklet.addModule", "addModule()")}} + - The operation failed for some other reason. + +## Examples + +```js +async function measureUniqueReach() { + // Load the Shared Storage worklet + await window.sharedStorage.worklet.addModule("reach-measurement-worklet.js"); + + // Run the reach measurement operation + await window.sharedStorage.run("reach-measurement", { + data: { contentId: "1234" }, + }); +} + +measureUniqueReach(); +``` + +See [Unique reach measurement](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/unique-reach/) for a full explanation of this example, and [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) for more examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/windowsharedstorage/selecturl/index.md b/files/en-us/web/api/windowsharedstorage/selecturl/index.md new file mode 100644 index 000000000000000..d991d962f7997de --- /dev/null +++ b/files/en-us/web/api/windowsharedstorage/selecturl/index.md @@ -0,0 +1,107 @@ +--- +title: "WindowSharedStorage: selectURL() method" +short-title: selectURL() +slug: Web/API/WindowSharedStorage/selectURL +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.WindowSharedStorage.selectURL +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`selectURL()`** method of the +{{domxref("WindowSharedStorage")}} interface executes a select URL operation registered in a module added to the {{domxref("SharedStorageWorklet")}} associated with the current origin. + +> **Note:** The **Select URL** output gate is used to select a URL from a provided list to display to the user, based on shared storage data. + +## Syntax + +```js-nolint +selectURL(name, urls) +selectURL(name, urls, options) +``` + +### Parameters + +- `name` + - : A string representing the name of the operation registered inside the shared storage worklet module that is to be run. This must match the name given to the operation when it is registered with {{domxref("SharedStorageWorkletGlobalScope.register()")}}. +- `urls` + - : An array of objects representing the URLs to be chosen between by the select URL operation. Each object contains two properties: + - `url` + - : A string representing the URL. + - `reportingMetadata` {{optional_inline}} + - : An object containing properties with names equal to event types, and values equal to URLs where reporting destinations are located, for example, `"click" : "my-reports/report1.html"`. These act as destinations for reports submitted with a destination type of `"shared-storage-select-url"`, for example via a {{domxref("Fence.reportEvent()")}} or {{domxref("Fence.setReportEventDataForAutomaticBeacons()")}} method call. +- `options` {{optional_inline}} + - : An options object, which can contain the following properties: + - `data` {{optional_inline}} + - : An object representing any data required for executing the operation. + - `keepAlive` {{optional_inline}} + - : A boolean value. If set to `true`, the {{domxref("SharedStorageWorkletGlobalScope")}} of the associated worklet is kept alive, and the operation can be run multiple times. The default value, `false`, means that the {{domxref("SharedStorageWorkletGlobalScope")}} is terminated after the operation is run. In such cases, to use the worklet module again it would have to be re-added using {{domxref("Worklet.addModule", "addModule()")}}. + - `resolveToConfig` {{optional_inline}} + - : A boolean value. If set to `true`, the fulfillment value of the {{jsxref("Promise")}} returned by `run()` will be a {{domxref("FencedFrameConfig")}} object that can be used to load content into a {{htmlelement("fencedframe")}} via its `config` attribute. The default value, `false`, means that the fulfillment value will be a URL that can be used to embed content into an {{htmlelement("iframe")}}. + +### Return value + +A {{jsxref("Promise")}} that fulfills with a {{domxref("FencedFrameConfig")}} object or a string representing a URL, depending on the value of the `resolveToConfig` option. + +### Exceptions + +- {{jsxref("TypeError")}} + - : Thrown if: + - The worklet module has not yet been added with {{domxref("Worklet.addModule", "addModule()")}} + - `urls` is empty or exceeds the maximum allowed length (which is browser-specific). + - An object inside `urls` contains no `url` property. + - The operation failed for some other reason. + +## Examples + +### Basic A/B testing example + +```js +// 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(); +``` + +See the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) landing page for a walkthrough of this example, and links to other examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/windowsharedstorage/worklet/index.md b/files/en-us/web/api/windowsharedstorage/worklet/index.md new file mode 100644 index 000000000000000..14728885a26c1b4 --- /dev/null +++ b/files/en-us/web/api/windowsharedstorage/worklet/index.md @@ -0,0 +1,70 @@ +--- +title: "WindowSharedStorage: worklet property" +short-title: worklet +slug: Web/API/WindowSharedStorage/worklet +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.WindowSharedStorage.worklet +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`worklet`** read-only property of the +{{domxref("WindowSharedStorage")}} interface contains the {{domxref("SharedStorageWorklet")}} instance representing the shared storage worklet for the current origin. + +`SharedStorageWorklet` has the {{domxref("Worklet.addModule", "addModule()")}} method available on it, which is used to add a module to the shared storage worklet. + +## Value + +A {{domxref("SharedStorageWorklet")}} object. + +## Examples + +```js +// 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(); +``` + +See the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) landing page for a walkthrough of this example, and links to other examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/worklet/index.md b/files/en-us/web/api/worklet/index.md index e1a1f54e21e564a..c50dfaaf4e71912 100644 --- a/files/en-us/web/api/worklet/index.md +++ b/files/en-us/web/api/worklet/index.md @@ -62,6 +62,17 @@ Worklets are restricted to specific use cases; they cannot be used for arbitrary > + + {{domxref("SharedStorageWorklet")}} + For running private operations on cross-site data, without risk of data leakage. + Main thread + + Shared Storage API + + diff --git a/files/en-us/web/api/workletsharedstorage/context/index.md b/files/en-us/web/api/workletsharedstorage/context/index.md new file mode 100644 index 000000000000000..d6ebcf39d7dbb33 --- /dev/null +++ b/files/en-us/web/api/workletsharedstorage/context/index.md @@ -0,0 +1,34 @@ +--- +title: "WorkletSharedStorage: context property" +short-title: context +slug: Web/API/WorkletSharedStorage/context +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.WorkletSharedStorage.context +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`context`** read-only property of the +{{domxref("WorkletSharedStorage")}} interface contains contextual data passed into the shared storage worklet from the associated browsing context via the {{domxref("FencedFrameConfig.setSharedStorageContext()")}} method. + +## Value + +`context` can contain any value type (string, number, array, object). The value will match the value passed into the {{domxref("FencedFrameConfig.setSharedStorageContext()")}} method. + +## Examples + +See the main {{domxref("WorkletSharedStorage")}} page for an example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/workletsharedstorage/entries/index.md b/files/en-us/web/api/workletsharedstorage/entries/index.md new file mode 100644 index 000000000000000..db5803834bf624c --- /dev/null +++ b/files/en-us/web/api/workletsharedstorage/entries/index.md @@ -0,0 +1,53 @@ +--- +title: "WorkletSharedStorage: entries() method" +short-title: entries() +slug: Web/API/WorkletSharedStorage/entries +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.WorkletSharedStorage.entries +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`entries()`** method of the +{{domxref("WorkletSharedStorage")}} interface returns an [async iterator](/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) providing an array of a `WorkletSharedStorage` instance's enumerable property `[key, value]` pairs, in the same order as a [`for...in`](/en-US/docs/Web/JavaScript/Reference/Statements/for...in) loop (the difference being that a for-in loop enumerates properties in the prototype chain as well). + +## Syntax + +```js-nolint +entries() +``` + +### Parameters + +None. + +### Return value + +An array of the `WorkletSharedStorage`'s enumerable property key/value pairs. + +## Examples + +```js +// entries() available inside a shared storage worklet module +const storage = await this.sharedStorage; + +async function logEntries() { + for await (const [key, value] of storage.entries()) { + console.log({ key, value }); + } +} +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/workletsharedstorage/get/index.md b/files/en-us/web/api/workletsharedstorage/get/index.md new file mode 100644 index 000000000000000..bfc3393b35df5ed --- /dev/null +++ b/files/en-us/web/api/workletsharedstorage/get/index.md @@ -0,0 +1,132 @@ +--- +title: "WorkletSharedStorage: get() method" +short-title: get() +slug: Web/API/WorkletSharedStorage/get +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.WorkletSharedStorage.get +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`get()`** method of the +{{domxref("WorkletSharedStorage")}} interface retrieves a value from shared storage. + +## Syntax + +```js-nolint +get(key) +``` + +### Parameters + +- `key` + - : A string representing the key of the key/value pair you want to retrieve. + +### Return value + +A {{jsxref("Promise")}} that fulfills with a string equal to the value of the retrieved key/value pair. + +### Exceptions + +- {{jsxref("TypeError")}} + - : Thrown if: + - The worklet module has not yet been added with {{domxref("Worklet.addModule", "addModule()")}}. + - `key` exceeds the browser-defined maximum length. + - A key/value with the specified `key` is not found in the shared storage. + +## Examples + +### K+ frequency measurement example + +The following example measures the K+ frequency of content views. Sometimes described as "effective frequency", K frequency refers to the minimum number of views before a user will recognize or recall certain content (often used in the context of ad views). + +The main page script: + +```js +// k-frequency-measurement.js + +async function injectContent() { + // Load the Shared Storage worklet + await window.sharedStorage.worklet.addModule('k-freq-measurement-worklet.js'); + + // Run the K-frequency measurement operation + await window.sharedStorage.run('k-freq-measurement', { data: { kFreq: 3, contentId: 123 }); +} + +injectContent(); +``` + +The worklet module is shown below: + +```js +// k-frequency-measurement-worklet.js + +// Learn more about noise and scaling from the Private Aggregation fundamentals +// documentation on Chrome blog +const SCALE_FACTOR = 65536; + +/** + * The bucket key must be a number, and in this case, it is simply the content + * ID itself. For more complex bucket key construction, see other use cases in + * this demo. + */ +function convertContentIdToBucket(contentId) { + return BigInt(contentId); +} + +class KFreqMeasurementOperation { + async run(data) { + const { kFreq, contentId } = data; + + // Read from Shared Storage + const hasReportedContentKey = "has-reported-content"; + const impressionCountKey = "impression-count"; + const hasReportedContent = + (await this.sharedStorage.get(hasReportedContentKey)) === "true"; + const impressionCount = parseInt( + (await this.sharedStorage.get(impressionCountKey)) || 0, + ); + + // Do not report if a report has been sent already + if (hasReportedContent) { + return; + } + + // Check impression count against frequency limit + if (impressionCount < kFreq) { + await this.sharedStorage.set(impressionCountKey, impressionCount + 1); + return; + } + + // Generate the aggregation key and the aggregatable value + const bucket = convertContentIdToBucket(contentId); + const value = 1 * SCALE_FACTOR; + + // Send an aggregatable report via the Private Aggregation API + privateAggregation.sendHistogramReport({ bucket, value }); + + // Set the report submission status flag + await this.sharedStorage.set(hasReportedContentKey, "true"); + } +} + +// Register the operation + +register("k-freq-measurement", KFreqMeasurementOperation); +``` + +See [K+ frequency measurement](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/k-freq-reach/) for more explanation of this example, and the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) landing page for links to other examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/workletsharedstorage/index.md b/files/en-us/web/api/workletsharedstorage/index.md new file mode 100644 index 000000000000000..fb41bf28abc46d2 --- /dev/null +++ b/files/en-us/web/api/workletsharedstorage/index.md @@ -0,0 +1,115 @@ +--- +title: WorkletSharedStorage +slug: Web/API/WorkletSharedStorage +page-type: web-api-interface +status: + - experimental +browser-compat: api.WorkletSharedStorage +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`WorkletSharedStorage`** interface of the {{domxref("Shared Storage API", "Shared Storage API", "", "nocode")}} Represents the shared storage for a particular origin, as it is exposed to a worklet context. + +`WorkletSharedStorage` is accessed via {{domxref("SharedStorageWorkletGlobalScope.sharedStorage")}}. + +{{InheritanceDiagram}} + +## Instance properties + +- {{domxref("WorkletSharedStorage.context", "context")}} {{Experimental_Inline}} + - : Contains contextual data passed into the shared storage worklet from the associated browsing context via the {{domxref("FencedFrameConfig.setSharedStorageContext()")}} method. + +## Instance methods + +_`WorkletSharedStorage` inherits properties from its parent interface, {{domxref("SharedStorage")}}._ + +- {{domxref("WorkletSharedStorage.get", "get()")}} {{Experimental_Inline}} + - : Retrieves a value from shared storage. +- {{domxref("WorkletSharedStorage.length", "length()")}} {{Experimental_Inline}} + - : Returns the number of entries currently stored in shared storage for the current origin. +- {{domxref("WorkletSharedStorage.remainingBudget", "remainingBudget()")}} {{Experimental_Inline}} + - : Returns the remaining navigation budget for the current origin. + +`WorkletSharedStorage` also has the following methods available because it has an [async iterator](/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) defined on it: + +- {{domxref("WorkletSharedStorage.entries", "entries()")}} {{Experimental_Inline}} + - : Returns a new async iterator of a `WorkletSharedStorage` object instance's enumerable property key/value pairs. +- {{domxref("WorkletSharedStorage.keys", "keys()")}} {{Experimental_Inline}} + - : Returns a new async iterator containing the keys for each item in a `WorkletSharedStorage` object instance. +- {{domxref("WorkletSharedStorage.values", "values()")}} {{Experimental_Inline}} + - : Returns a new async iterator containing the values for each index in a `WorkletSharedStorage` object instance. +- `WorkletSharedStorage[@@asyncIterator]()` {{Experimental_Inline}} + - : Returns the {{domxref("WorkletSharedStorage.entries", "entries()")}} function by default. + +## Examples + +### Passing contextual data via `setSharedStorageContext()` + +You can use the [Private Aggregation API](https://developer.chrome.com/docs/privacy-sandbox/private-aggregation/) to create reports that combine event-level data inside fenced frames with contextual data from the embedding document. `setSharedStorageContext()` can be used to pass contextual data from the embedder to shared storage worklets initiated by the [Protected Audience API](https://developer.chrome.com/docs/privacy-sandbox/fledge/). + +In the following example, we store data from both the embedding page and the fenced frame in [shared storage](https://developer.chrome.com/docs/privacy-sandbox/shared-storage/). + +In the embedding page, we will set a mock event ID as the shared storage context using `setSharedStorageContext()`: + +```js +const frameConfig = await navigator.runAdAuction({ resolveToConfig: true }); + +// Data from the embedder that you want to pass to the shared storage worklet +frameConfig.setSharedStorageContext("some-event-id"); + +const frame = document.createElement("fencedframe"); +frame.config = frameConfig; +``` + +Inside the fenced frame, we add the worklet module with {{domxref("Worklet.addModule","window.sharedStorage.worklet.addModule()")}}, and then send the event-level data into the shared storage worklet module using {{domxref("WindowSharedStorage.run","window.sharedStorage.run()")}} (this is unrelated to the contextual data from the embedding document): + +```js +const frameData = { + // Data available only inside the fenced frame +}; + +await window.sharedStorage.worklet.addModule("reporting-worklet.js"); + +await window.sharedStorage.run("send-report", { + data: { + frameData, + }, +}); +``` + +In the `reporting-worklet.js` worklet, we read the embedding document's event ID from `sharedStorage.context` and the frame's event-level data from the data object, then report them through Private Aggregation: + +```js +class ReportingOperation { + convertEventIdToBucket(eventId) { ... } + convertEventPayloadToValue(info) { ... } + + async run(data) { + // Data from the embedder + const eventId = sharedStorage.context; + + // Data from the fenced frame + const eventPayload = data.frameData; + + privateAggregation.sendHistogramReport({ + bucket: convertEventIdToBucket(eventId), + value: convertEventPayloadToValue(eventPayload) + }); + } +} + +register('send-report', ReportingOperation); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/workletsharedstorage/keys/index.md b/files/en-us/web/api/workletsharedstorage/keys/index.md new file mode 100644 index 000000000000000..70ffc9837c17e56 --- /dev/null +++ b/files/en-us/web/api/workletsharedstorage/keys/index.md @@ -0,0 +1,53 @@ +--- +title: "WorkletSharedStorage: keys() method" +short-title: keys() +slug: Web/API/WorkletSharedStorage/keys +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.WorkletSharedStorage.keys +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`keys()`** method of the +{{domxref("WorkletSharedStorage")}} interface returns an [async iterator](/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) containing the keys for each item in a `WorkletSharedStorage` instance. + +## Syntax + +```js-nolint +keys() +``` + +### Parameters + +None. + +### Return value + +An array of the `WorkletSharedStorage`'s enumerable property keys. + +## Examples + +```js +// keys() available inside a shared storage worklet module +const storage = await this.sharedStorage; + +async function logKeys() { + for await (const key of storage.keys()) { + console.log(key); + } +} +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/workletsharedstorage/length/index.md b/files/en-us/web/api/workletsharedstorage/length/index.md new file mode 100644 index 000000000000000..5e0c90f14be23e6 --- /dev/null +++ b/files/en-us/web/api/workletsharedstorage/length/index.md @@ -0,0 +1,58 @@ +--- +title: "WorkletSharedStorage: length() method" +short-title: length() +slug: Web/API/WorkletSharedStorage/length +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.WorkletSharedStorage.length +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`length()`** method of the +{{domxref("WorkletSharedStorage")}} interface returns the number of entries currently stored in shared storage for the current origin. + +## Syntax + +```js-nolint +length() +``` + +### Parameters + +None. + +### Return value + +A {{jsxref("Promise")}} that fulfills with a number representing the number of key/value pairs currently in shared storage. + +### Exceptions + +- {{jsxref("TypeError")}} + - : Thrown if: + - The worklet module has not yet been added with {{domxref("Worklet.addModule", "addModule()")}}. + - The browser fails to retrieve the number of entries for some other reason. + +## Examples + +```js +// length() available inside a shared storage worklet module + +async function retrieveLength() { + const length = await this.sharedStorage.length(); + console.log(length); +} +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/workletsharedstorage/remainingbudget/index.md b/files/en-us/web/api/workletsharedstorage/remainingbudget/index.md new file mode 100644 index 000000000000000..1c79d5588ae2587 --- /dev/null +++ b/files/en-us/web/api/workletsharedstorage/remainingbudget/index.md @@ -0,0 +1,58 @@ +--- +title: "WorkletSharedStorage: remainingBudget() method" +short-title: remainingBudget() +slug: Web/API/WorkletSharedStorage/remainingBudget +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.WorkletSharedStorage.remainingBudget +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`remainingBudget()`** method of the +{{domxref("WorkletSharedStorage")}} interface returns the remaining navigation budget for the current origin. + +The navigation budget is the number of navigations permitted inside a {{htmlelement("fencedframe")}} as a result of {{domxref("WindowSharedStorage.selectURL()")}} calls, per origin, in a 24-hour period. This is a mechanism designed to limit the rate of leakage of cross-site data to the destination pages navigated to in [fenced frames](/en-US/docs/Web/API/Fenced_frames_API). Each time a `selectURL()` navigation occurs, an amount is deducted from the corresponding origin's budget. + +## Syntax + +```js-nolint +remainingBudget() +``` + +### Parameters + +None. + +### Return value + +A {{jsxref("Promise")}} that fulfills with a number representing the remaining navigation budget. + +### Exceptions + +- {{jsxref("TypeError")}} + - : Thrown if the worklet module has not yet been added with {{domxref("Worklet.addModule", "addModule()")}}. + +## Examples + +```js +// remainingBudget() available inside a shared storage worklet module + +async function retrieveBudget() { + const budget = await this.sharedStorage.remainingBudget(); + console.log(budget); +} +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/workletsharedstorage/values/index.md b/files/en-us/web/api/workletsharedstorage/values/index.md new file mode 100644 index 000000000000000..5c34a4146c1d8c4 --- /dev/null +++ b/files/en-us/web/api/workletsharedstorage/values/index.md @@ -0,0 +1,53 @@ +--- +title: "WorkletSharedStorage: values() method" +short-title: values() +slug: Web/API/WorkletSharedStorage/values +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.WorkletSharedStorage.values +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`values()`** method of the +{{domxref("WorkletSharedStorage")}} interface returns an [async iterator](/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) containing the values for each item in a `WorkletSharedStorage` instance. + +## Syntax + +```js-nolint +values() +``` + +### Parameters + +None. + +### Return value + +An array of the `WorkletSharedStorage`'s enumerable property values. + +## Examples + +```js +// values() available inside a shared storage worklet module +const storage = await this.sharedStorage; + +async function logValues() { + for await (const value of storage.values()) { + console.log(value); + } +} +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) From 1928e1732d062203e284e0f8a148e3df1096a15a Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 24 Jul 2023 09:07:49 +0100 Subject: [PATCH 04/18] final bits of content --- .../en-us/web/api/shared_storage_api/index.md | 26 +++-- .../api/sharedstoragerunoperation/index.md | 2 +- .../sharedstorageselecturloperation/index.md | 89 ++++++++++++++++++ .../run/index.md | 51 ++++++++++ .../api/web_storage_api/embedded-content.png | Bin 0 -> 6349 bytes files/en-us/web/api/web_storage_api/index.md | 11 +++ 6 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 files/en-us/web/api/sharedstorageselecturloperation/index.md create mode 100644 files/en-us/web/api/sharedstorageselecturloperation/run/index.md create mode 100644 files/en-us/web/api/web_storage_api/embedded-content.png diff --git a/files/en-us/web/api/shared_storage_api/index.md b/files/en-us/web/api/shared_storage_api/index.md index 9abd0ca6ea59ea5..b2971a5e8c4e0bb 100644 --- a/files/en-us/web/api/shared_storage_api/index.md +++ b/files/en-us/web/api/shared_storage_api/index.md @@ -1,6 +1,6 @@ --- title: Shared Storage API -slug: Web/API/Shared_storage_API +slug: Web/API/Shared_Storage_API page-type: web-api-overview status: - experimental @@ -92,14 +92,14 @@ Below we'll look at these steps one by one. #### Define an operation in a worklet -The URL will be chosen based on the experiment group stored in shared storage. To retrieve this value choose a URL based on it, we need to define an operation in a {{domxref("SharedStorageWorklet")}} context — it must be inside a worklet to keep the raw data hidden from other contexts and therefore preserve privacy. +The URL will be chosen 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 {{domxref("SharedStorageWorklet")}} context — it must be inside a worklet to keep the raw data hidden from other contexts and therefore preserve privacy. The Select URL operation takes the form of a JavaScript class. It can be written in any way you like, as long as it follows certain rules (some of the rules for each output gate differ, depending on what kind of use case they fulfill): - The actual functionality must be contained inside an asynchronous `run()` method, which must have an array of objects containing URLs as its first paramater, and a data object as its second parameter (when called, the data argument is optional). - The `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 signature of its `run()` method. For example, for Select URL, see {{domxref("SharedStorageSelectURLOperation.run()")}}. +> **Note:** Each output gate has a corresponding interface that defines the required structure of its class and `run()` method. For Select URL, see {{domxref("SharedStorageSelectURLOperation")}}. Once the operation is defined, it needs to be registered using {{domxref("SharedStorageWorkletGlobalScope.register()")}}. @@ -118,11 +118,11 @@ class SelectURLOperation { register("ab-testing", SelectURLOperation); ``` -Note how the value set in our main app context is retrieved using {{domxref("WorkletSharedStorage.get()")}} — to reiterate, you can only read values back out of shared storage inside a worklet. +Note how the value set in our main app context is retrieved using {{domxref("WorkletSharedStorage.get()")}}. To reiterate, to preserve privacy and mitigate data leakage you can only read values back out of shared storage inside a worklet. #### Add the worklet -To make use of the operation defined in the worklet module, it needs to be added to the shared storage worklet using {{domxref("Worklet.addModule", "window.sharedStorage.worklet.addModule()")}}. This is done in our main app context, before we set the experiment group value, so that it is ready to use when needed: +To use the operation defined in the worklet module, it needs to be added to the shared storage worklet using {{domxref("Worklet.addModule", "window.sharedStorage.worklet.addModule()")}}. This is done in our main app context, before we set the experiment group value, so that it is ready to use when needed: ```js async function injectContent() { @@ -138,7 +138,7 @@ async function injectContent() { #### Choose a URL and load it in a fenced frame -To run the operation defined in the worklet, we call {{domxref("WindowSharedStorage.selectURL()")}} — this 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 `run()` method signature for a Select URL operation, as discussed above. +To run the operation defined in the worklet, we call {{domxref("WindowSharedStorage.selectURL()")}} — this 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 Select URL 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. @@ -198,6 +198,20 @@ async function injectContent() { injectContent(); ``` +## How does shared storage differ from web storage? + +The key difference is that shared storage is intended for use with cross-origin data once storage has been partitioned. + +- If you are a publisher and you want to store first-party data that is accessible to you only, use the [`localStorage`](/en-US/docs/Web/API/Window/localStorage) version of [web storage](/en-US/docs/Web/API/Web_Storage_API). +- If you want that data to persist only for that browser session, use [`sessionStorage`](/en-US/docs/Web/API/Window/sessionStorage). +- If you are operating as a third-party on another site, and you want to record data from that site for you to access later on another site, use shared storage. + +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 only happen inside a shared storage worklet, and the origin used for reading in the worklet is the same as the browsing context that created it. + +Also, you cannot extract shared storage data to the outside of a shared storage worklet (for tracking protection). You must use one of the output gates provided if you want to work with your data in shared storage. + +Last, data in `localStorage` persists until manually cleared (`sessionStorage` is cleared at the end of a browsing session). Shared storage data is cleared 30 days after the last write call. + ## Interfaces - {{domxref("SharedStorage")}} diff --git a/files/en-us/web/api/sharedstoragerunoperation/index.md b/files/en-us/web/api/sharedstoragerunoperation/index.md index 83ce9ce5d38bc48..6064059bd3664ec 100644 --- a/files/en-us/web/api/sharedstoragerunoperation/index.md +++ b/files/en-us/web/api/sharedstoragerunoperation/index.md @@ -20,7 +20,7 @@ The **`SharedStorageRunOperation`** interface of the {{domxref("Shared Storage A ## Examples -In a worklet, a class called `ReachMeasurementOperation` is defined and registered using {{domxref("SharedStorageWorkletGlobalScope.register()")}} with a name of `reach-measurement`. `SharedStorageRunOperation` defines the structure this class needs to conform to, which in real terms means the parameters the `run()` method is required to have. +In a worklet, a class called `ReachMeasurementOperation` is defined and registered using {{domxref("SharedStorageWorkletGlobalScope.register()")}} with a name of `reach-measurement`. `SharedStorageRunOperation` defines the structure this class needs to conform to, which in real terms means the parameters the `run()` method is required to have. Apart from that, the functionality of the class is flexible in terms of how it is defined. ```js // reach-measurement-worklet.js diff --git a/files/en-us/web/api/sharedstorageselecturloperation/index.md b/files/en-us/web/api/sharedstorageselecturloperation/index.md new file mode 100644 index 000000000000000..90f3271c36305b5 --- /dev/null +++ b/files/en-us/web/api/sharedstorageselecturloperation/index.md @@ -0,0 +1,89 @@ +--- +title: SharedStorageSelectURLOperation +slug: Web/API/SharedStorageSelectURLOperation +page-type: web-api-interface +status: + - experimental +browser-compat: api.SharedStorageSelectURLOperation +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`SharedStorageSelectURLOperation`** interface of the {{domxref("Shared Storage API", "Shared Storage API", "", "nocode")}} represents a select URL output gate operation. + +{{InheritanceDiagram}} + +## Instance methods + +- {{domxref("SharedStorageSelectURLOperation.run", "run()")}} {{Experimental_Inline}} + - : Defines the structure that the `run()` method defined inside a select URL output gate operation should conform to. + +## Examples + +In a worklet, a class called `SelectURLOperation` is defined and registered using {{domxref("SharedStorageWorkletGlobalScope.register()")}} with a name of `ab-testing`. `SharedStorageSelectURLOperation` defines the structure this class needs to conform to, which in real terms means the parameters and return value the `run()` method is required to have. Apart from that, the functionality of the class is flexible in terms of how it is defined. + +```js +// 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 corresponding URL (first or second item in the array) + return urls.indexOf(experimentGroup); + } +} + +// Register the operation +register("ab-testing", SelectURLOperation); +``` + +In the main browsing context, the `ab-testing` operation is invoked using the {{domxref("WindowSharedStorage.selectURL()")}} method: + +```js +// Randomly assigns a user to a group 0 or 1 +function getExperimentGroup() { + return Math.round(Math.random()); +} + +async function injectContent() { + // Register 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(); +``` + +See the [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) landing page for more information about this example, and links to other examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/sharedstorageselecturloperation/run/index.md b/files/en-us/web/api/sharedstorageselecturloperation/run/index.md new file mode 100644 index 000000000000000..751c19d8dc2290a --- /dev/null +++ b/files/en-us/web/api/sharedstorageselecturloperation/run/index.md @@ -0,0 +1,51 @@ +--- +title: "SharedStorageSelectURLOperation: run() method" +short-title: run() +slug: Web/API/SharedStorageSelectURLOperation/run +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.SharedStorageSelectURLOperation.run +--- + +{{APIRef("Shared Storage API")}}{{SeeCompatTable}} + +The **`run()`** method of the +{{domxref("SharedStorageSelectURLOperation")}} interface defines the structure that the `run()` method defined inside a select URL output gate operation should conform to. + +## Syntax + +```js-nolint +run(urls, data) +``` + +### Parameters + +- `urls` + - : An array of objects representing the URLs to be chosen between by the select URL operation. Each object contains two properties: + - `url` + - : A string representing the URL. + - `reportingMetadata` {{optional_inline}} + - : An object containing properties with names equal to event types, and values equal to URLs where reporting destinations are located, for example, `"click" : "my-reports/report1.html"`. These act as destinations for reports submitted with a destination type of `"shared-storage-select-url"`, for example via a {{domxref("Fence.reportEvent()")}} or {{domxref("Fence.setReportEventDataForAutomaticBeacons()")}} method call. +- `data` + - : An object representing any data required for executing the operation. + +### Return value + +A {{jsxref("Promise")}} that fulfills with a number defining the array index of the URL selected by the operation. + +## Examples + +See the main {{domxref("SharedStorageSelectURLOperation")}} page for an example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Shared Storage API](/en-US/docs/Web/API/Shared_storage_API) diff --git a/files/en-us/web/api/web_storage_api/embedded-content.png b/files/en-us/web/api/web_storage_api/embedded-content.png new file mode 100644 index 0000000000000000000000000000000000000000..88a8ad6094a1a206930f49c1ba754f38c073adbb GIT binary patch literal 6349 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 **Note:** Access to Web Storage from third-party IFrames is denied if the user has [disabled third-party cookies](https://support.mozilla.org/en-US/kb/third-party-cookies-firefox-tracking-protection). +## Determining storage access by a third-party + +Each origin has its own storage (this is the same for web storage and [shared storage](/en-US/docs/Web/API/Shared_Storage_API)), but what about third-party (i.e. embedded) code access to shared storage? The [browsing context](/en-US/docs/Glossary/Browsing_context) of where the third-party code from another origin is executed determines whose storage that third-party code can access. + +![A box diagram showing a top-level browsing context called publisher.com, with third-party content embedded in it](embedded-content.png) + +Third-party code can be added to another site by injecting it with a {{htmlelement("script")}} element, or navigating an {{htmlelement("iframe")}} to a site that contains it. If you are a third-party from another origin, how you are added to another site determines the browsing context of your code. + +- If your third-party code is added to another site with a `