An iframe places another web page inside yours: a map, a video player, a booking widget, a payment form. Each embed runs someone else's code on your page, so it is worth knowing how to limit what it can do, and how to stop it slowing your page down.
A basic embed
<iframe
src="https://www.example.com/booking-widget"
title="Class booking calendar"
width="600"
height="400"
loading="lazy">
</iframe>
| Attribute | Purpose |
|---|---|
src | The URL of the embedded page |
title | An accessible name. Screen readers announce it when they reach the frame. |
width and height | The size of the frame in CSS pixels, which also reserves space |
loading="lazy" | Defers loading until the frame is near the viewport |
Always add a title that says what the frame contains. Without it, screen reader users hear only "frame" and have to go inside to find out what it is.
iframe content cannot be styled from your page's CSS. You control only the frame itself: its size, border and position. To make an embed scale with its container, keep the proportions with CSS:
<style>
.video-embed {
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
border: 0;
}
</style>
<iframe class="video-embed"
src="https://www.youtube-nocookie.com/embed/VIDEO_ID"
title="Video: shaping a sourdough loaf"
allow="encrypted-media; picture-in-picture; fullscreen"
referrerpolicy="strict-origin-when-cross-origin"
loading="lazy">
</iframe>
Replace VIDEO_ID with a real video ID. The youtube-nocookie.com domain is YouTube's privacy-enhanced embed mode.
Same-origin and cross-origin
Browsers keep pages from different origins apart. An origin is the scheme, domain and port, such as https://example.com. A cross-origin iframe cannot read your page, and your page cannot read it. That protection is automatic.
What the embedded page can do by default is quite a lot: run JavaScript, submit forms, open pop-up windows, play media and, in some cases, navigate your whole page away. sandbox and allow let you take those powers away.
sandbox: switch everything off, then allow what is needed
Adding sandbox with no value applies every restriction. The framed page:
- cannot run scripts,
- cannot submit forms,
- cannot open pop-ups or new windows,
- cannot navigate the top-level page,
- is treated as coming from a unique, opaque origin, so it cannot use its own cookies or storage.
You then add back only the capabilities the embed needs, as space-separated tokens:
| Token | Allows |
|---|---|
allow-scripts | Running JavaScript |
allow-forms | Submitting forms |
allow-popups | Opening new windows, for example from target="_blank" links |
allow-popups-to-escape-sandbox | Letting those new windows run without the sandbox |
allow-same-origin | Keeping the frame's real origin, so it can use its own cookies and storage |
allow-top-navigation-by-user-activation | Navigating your page, but only after the user clicks inside the frame |
allow-downloads | Starting downloads |
allow-modals | Using alert(), confirm() and print() |
A widget that needs scripts and forms but should never redirect your page or open pop-ups:
<iframe
src="https://widgets.example.com/newsletter-signup"
title="Newsletter sign-up form"
width="400"
height="300"
sandbox="allow-scripts allow-forms">
</iframe>
Test sandboxed embeds carefully. If something does not work, the Console usually reports which action the sandbox blocked.
Never combine allow-scripts and allow-same-origin for a page from your own origin. The framed page could then use script to remove its own sandbox attribute, and the sandbox would give no protection at all. For third-party content on a different origin, the combination is common and still limits other actions such as pop-ups and top-level navigation.
Showing untrusted HTML
sandbox is also useful for showing HTML you do not control, such as user-submitted content or an HTML email preview. The srcdoc attribute holds the HTML directly:
<iframe
title="Email preview"
sandbox
srcdoc="<p>Hello <b>Sam</b>, your order is ready.</p>">
</iframe>
With a bare sandbox, no scripts in that HTML run.
allow: grant browser features
Powerful browser features such as the camera, microphone, geolocation, full screen and payment are controlled by a Permissions Policy. Cross-origin frames cannot use most of them unless your page grants them with allow:
<iframe
src="https://video.example.com/player/123"
title="Video: our bakery tour"
allow="fullscreen; picture-in-picture; autoplay"
width="640"
height="360">
</iframe>
Grant only what the embed needs. A video player needs fullscreen and perhaps picture-in-picture; it does not need camera or geolocation. Video providers often supply embed code with a long allow list; trim it to what you use.
referrerpolicy
When the iframe loads, the browser normally tells the embedded site which page it is on, through the Referer header. referrerpolicy controls how much is shared:
| Value | Sent to a cross-origin embed |
|---|---|
no-referrer | Nothing |
origin | Only your origin, such as https://example.com/ |
strict-origin-when-cross-origin | Your origin over HTTPS, the full URL for same-origin requests. This is the browser default. |
same-origin | Nothing for cross-origin requests |
If your URLs contain anything private, such as search terms or account identifiers, use no-referrer or origin. Some embeds, including video players that check which sites embed them, need at least the origin to work.
Stopping your site being framed
The reverse problem is other sites embedding your pages, for example to trick people into clicking hidden buttons (clickjacking). That is controlled on the server with the Content-Security-Policy: frame-ancestors header, or the older X-Frame-Options header, not with HTML. Pages such as sign-in and account settings should refuse framing.
Performance
Every iframe loads a whole page with its own scripts, styles and requests. A few habits keep embeds from slowing your page:
- Add
loading="lazy"to embeds below the first screen. - Set
widthandheight, oraspect-ratioin CSS, to avoid layout shift. - For heavy video embeds, consider showing a thumbnail image with a play button that loads the real iframe only when clicked. This is often called a facade.
Ask whether you need an iframe at all. A static map image linked to the full map, or a link to a video, is lighter and often just as useful.
Summary
- Give every
iframea descriptivetitle, dimensions and, below the first screen,loading="lazy". - Use
sandboxto remove capabilities, then add back only the tokens the embed needs. - Never combine
allow-scriptsandallow-same-originfor content from your own origin. - Use
allowto grant only the browser features an embed requires. - Set
referrerpolicyto protect private URLs, and block framing of your own sensitive pages with server headers.