Securely embed content onto a page without sharing cross-site data.
Implementation statusThis document outlines a new HTML element: <fencedframe>
.
reportEvent()
Beacons
Referer
header in beacons
A fenced frame (<fencedframe>
) is an HTML element for embedded content, similar to an iframe. Unlike iframes, a fenced frame restricts communication with its embedding context to allow the frame access to cross-site data without sharing it with the embedding context. Some Privacy Sandbox APIs may require select documents to render within a fenced frame.
Similarly, any first-party data in the embedding context cannot be shared with the fenced frame.
For example, if news.example
(the embedding context) embeds an ad from shoes.example
in a fenced frame, news.example
cannot exfiltrate data from the shoes.example
ad, and shoes.example
cannot learn first-party data from news.example
.
While browsing the web, you've probably looked at products on one site, and then you've seen them appear again in an ad on a completely different site.
Today, this advertising technique is achieved primarily through tracking technology that uses third-party cookies to share information across sites.
Chrome is working on storage partitioning, which separates browser storage per-site. Without partioning, if an iframe from shoes.example
is embedded on news.example
, and that iframe stores a value into storage, then that value can be read from the shoes.example
site. When storage has been partitioned, cross-site iframes will no longer share storage, therefore shoes.example
won't be able to access information stored by the iframe. If the iframe is served from *.shoes.example
and embedded on *.shoes.example
, browser storage will be shared as these are considered same-site.
Storage partitioning will be applied to standard storage APIs including LocalStorage, IndexedDB, and cookies. In a partitioned world, information leakage across first-party storage will be significantly reduced.
Work with cross-site dataFenced frames is a Privacy Sandbox feature which suggests top-level sites should partition data. Many Privacy Sandbox proposals and APIs aim to satisfy cross-site use cases without third-party cookies or other tracking mechanisms. For example:
Fenced frames are designed to work with the Protected Audience API. With the Protected Audience API, a user's interests are registered on an advertiser's site in interest groups, along with ads that may be of interest to the user. Then, on a separate site (known as a "publisher"), the ads registered in relevant interest groups are auctioned and the winning ad is displayed in a fenced frame.
If the publisher displays the winning ad in an iframe and the script can read the iframe's src
attribute, the publisher can infer information about the visitor's interests from that ad's URL. This is not privacy-preserving.
With a fenced frame, the publisher could display an ad which matches visitor interests, but the src
and interest group will be known only to the advertiser in the frame. The publisher couldn't access this information.
Fenced frames use the FencedFrameConfig
object for navigation. This object can be returned from a Protected Audience API auction or Shared Storage's URL selection operation. Then, the config object is set as the config
attribute on the fenced frame element. This differs from an iframe where a URL or opaque URN is assigned to the src
attribute. The FencedFrameConfig
object has a read-only url
property; however, since the current use-cases require the actual URL of the internal resource to be hidden, this property returns the string opaque
when read.
A fenced frame can't use postMessage
to communicate with its embedder. However, a fenced frame can use postMessage
with iframes inside the fenced frame.
Fenced frames will be isolated from the publisher in other ways. For example, the publisher won't have access to the DOM inside of a fenced frame, and the fenced frame cannot access the publisher's DOM. Further, attributes such as name
—which can be set to any value to and observed by the publisher—aren't available in fenced frames.
Fenced frames behave like a top-level browsing context (such as a browser tab). Although a fenced frame in certain use cases (such as interest-based retargeting ads) can contain cross-site data (such as a Protected Audience API interest group), the frame cannot access unpartitioned storage or cookies. The fenced frame can access a unique, nonce-based cookie and storage partition.
The characteristics of fenced frames are further detailed in the explainer.
How do fenced frames compare to iframes?Now that you know what fenced frames will and won't do, it's useful to compare to existing iframe features.
Featureiframe
fencedframe
Embed content Yes Yes Embedded content can access embedding context DOM Yes No Embedding context can access embedded content DOM Yes No Observable attributes, such as name
Yes No URLs (http://example.com
) Yes Yes (dependent on use case) Browser-managed opaque source (urn:uuid
) No Yes (dependent on use case) Access to cross-site data No Yes (dependent on use case)
Fenced frames support fewer external communication options to preserve privacy.
Will fenced frames replace iframes?Ultimately, fenced frames won't replace iframes and you won't have to use them. Fenced frames are a more private frame for usage when data from different top-level partitions needs to be displayed on the same page.
Same-site iframes (sometimes known as friendly iframes) are considered trusted content.
Use fenced framesFenced frames will work in combination with other Privacy Sandbox APIs to display documents from different storage partitions within a single page. Potential APIs are in discussion.
Current candidates for this combination include:
For more details, refer to the Fenced Frames use cases explainer.
ExamplesTo obtain a fenced frame config
object, you must pass in resolveToConfig: true
to Protected Audience API's runAdAuction()
call or Shared Storage's selectURL()
call. If the property is not added (or is set to false
), the resulting promise will resolve to a URN that can only be used in an iframe.
Get fenced frame config from Protected Audience API auction
const frameConfig = await navigator.runAdAuction({ // ...auction configuration resolveToConfig: true });
Get fenced frame config from Shared Storage URL Selection
const frameConfig = await sharedStorage.selectURL('operation-name', { resolveToConfig: true });
Once you have obtained the config, you can assign it to a fenced frame's config
attribute to navigate the frame to the resource represented by the config. Earlier versions of Chrome don't support the resolveToConfig
property, so you must still confirm that the promise resolved to a FencedFrameConfig
before navigating:
Set config to the fenced frame attribute
if (window.FencedFrameConfig && frameConfig instanceof FencedFrameConfig) { const frame = document.createElement('fencedframe'); frame.config = frameConfig; }
To learn more, see the Fenced Frame and Fenced Frame config explainers.
Browsers will set Sec-Fetch-Dest: fencedframe
for requests made from fenced frames and iframes that are embedded within a fenced frame.
Sec-Fetch-Dest: fencedframe
The server must set the Supports-Loading-Mode: fenced-frame
response header for a document to be loaded in a fenced frame. The header must be present for any iframes inside of a fenced frame, as well.
Supports-Loading-Mode: fenced-frame
You may want to use Private Aggregation to report event-level data in fenced frames associated with contextual data from the embedder. By using the fencedFrameConfig.setSharedStorageContext()
method, you can pass some contextual data, such as an event ID, from the embedder to shared storage worklets initiated by the Protected Audience API.
In the following example, we store some data available on the embedder page and some data available in the fenced frame in shared storage. From the embedder page, a mock event ID is set as the shared storage context. From the fenced frame, the frame event data is passed in.
From the embedder page, you can set contextual data as the shared storage context:
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;
From the fenced frame, you can pass in event-level data from the frame into the shared storage worklet (unrelated to the contextual data from the embedder above):
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
},
});
You can read the embedder's contextual information from sharedStorage.context
and the frame's event-level data from the data
object, then report them through Private Aggregation:
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.contributeToHistogram({
bucket: convertEventIdToBucket(eventId),
value: convertEventPayloadToValue(eventPayload)
});
}
}
register('send-report', ReportingOperation);
To learn more about the embedder's context in a fenced frame config object, see the explainer.
Try fenced framesUse Chrome flags to enable the Fenced Frame API at chrome://flags/#enable-fenced-frames
.
There are multiple choices in the dialog. We strongly recommend you select *Enable*, which allows Chrome to automatically update to new architecture as it becomes available.
The other options, Enabled with ShadowDOM and Enabled with multiple page architecture, offer different implementation strategies which are only relevant to browser engineers. Today, Enable works in the same way as Enabled with ShadowDOM. In the future, Enable will map to Enable with multiple page architecture.
Feature detectionTo determine if fenced frames are defined:
if (window.HTMLFencedFrameElement) {
// The fenced frame element is defined
}
To determine if the fenced frame config is available: js if (window.FencedFrameConfig && frameConfig instanceof FencedFrameConfig) { // The fenced frame config is available }
Fenced Frames are under active discussion and subject to change in the future. If you try this API and have feedback, we'd love to hear it.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.3