Fenced frames
Securely embed content onto a page without sharing cross-site data.
Published on • Updated on
Translated to: 日本語
By Jack J, Alexandra White and Kevin K. Lee
Implementation status
This document outlines a new HTML element: <fencedframe>
.
- The Fenced Frames proposal is now in general availability.
- Chrome Platform Status
Proposal | Status |
---|---|
Web API changes for urn to config Explainer | Now in general availability. |
Add size to API for K-Anon check for URLs and Frame Size Github Issue | Now in general availability. |
Protected Audience Fenced Frames support for event-level reports with Attribution Reporting Github Issue | Now in general availability. |
Protected Audience, Fenced Frames, and Private Aggregation API support urn-iframes reportEvent Github Issue | Now in general availability. |
Protected Audience component ads reporting Github Issue | Now in general availability. |
Deprecate `src` attribute for the config attribute Github Issue | Now in general availability. |
Why do we need fenced frames?
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, let's say 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
.
Strengthen cross-site privacy with storage partitioning
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. This is technology which Chrome has committed to phase out and replace with more privacy-preserving variants.
Chrome is working on storage partitioning, which separates browser storage per-site. Currently, 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
will not 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 data
Fenced 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:
- Protected Audience API allows for interest-based ad serving in a privacy-preserving manner.
- Shared Storage allows access to unpartitioned cross-site data in a secure environment.
Let's consider how fenced frames could 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 could not access this information.
How do fenced frames work?
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 instance 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 opaque-ads
) can contain cross-site data (such as a Protected Audience API interest group), the frame cannot access unpartitioned storage or cookies. An opaque-ads
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.
Feature | iframe | 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 |
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 frames
Fenced frames will work in combination with other Privacy Sandbox APIs to display documents from different storage partitions within a single page. Potential APIs are currently in discussion.
Current candidates for this combination include:
- From the TURTLEDOVE API family (which is the basis for the Protected Audience API), fenced frames could work with Conversion Lift Measurement using Shared Storage.
- Another option is to allow fenced frames to be read-only or access unpartitioned storage.
For more details, refer to the Fenced Frames use cases explainer.
Examples
To 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. Older 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.
Headers
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
Shared Storage context
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.sendHistogramReport({
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 frames
Use 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 detection
To determine if fenced frames are defined:
if (window.HTMLFencedFrameElement) {
// The fenced frame element is defined
}
To determine if the fenced frame config is available:
if (window.FencedFrameConfig && frameConfig instanceof FencedFrameConfig) {
// The fenced frame config is available
}
Browser support
The <fencedframe>
element is still in experimental mode, so it is currently supported from Chrome 97 onwards. At this time, it's not supported by other browsers.
Engage and share feedback
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.
- GitHub: Read the explainer, raise questions, and follow discussion.
- Developer support: Ask questions and join discussions on the Privacy Sandbox Developer Support repo.
Find out more
Updated on • Improve article