testiframe.com

How to Embed a Website in HTML with an Iframe

The iframe element displays another web page inside yours. Here's the code, every attribute worth knowing, the right way to embed YouTube, Google Maps, Docs and Vimeo, and why some sites won't load at all.

Published · 10 min read
Quick answer

To embed a website in HTML, add an iframe with the page's URL in src and a descriptive title: <iframe src="https://example.com" title="Example" width="800" height="600"></iframe>. It only works if the site allows framing. Many sites block it with X-Frame-Options or CSP frame-ancestors, and your page can't override that.

How to embed a website with the iframe tag

An <iframe> (inline frame) creates a separate browsing context inside your page. The framed page loads from its own server, in the visitor's browser, with its own scripts and cookies. You're not copying the content, you're opening a window onto it, which is why the other site gets a say in whether it can be framed.

This is the minimal iframe code that works:

<iframe src="https://example.com" title="Example Domain"></iframe>

Without a size, the browser renders it at 300×150 pixels, which is rarely what you want. A more practical starting point looks like this:

<iframe
  src="https://example.com/pricing"
  title="Example pricing table"
  width="800"
  height="600"
  loading="lazy"
  referrerpolicy="strict-origin-when-cross-origin"
  style="border:0"></iframe>

A few points that trip people up:

  • Always add title. Screen readers announce it when a user reaches the frame. Describe the content ("Store opening hours map"), not the element ("iframe").
  • Don't put fallback text between the tags. Modern browsers ignore anything inside <iframe></iframe>. If you want a fallback, put a normal link next to the frame.
  • Use https:// URLs. An http:// frame inside an https:// page is blocked as mixed content. Local addresses such as http://localhost and 127.0.0.1 are the exception.

Iframe attributes: a complete reference

These are the iframe attributes you'll actually use. Older attributes such as frameborder, scrolling and marginwidth are obsolete; handle those with CSS instead.

AttributeWhat it doesExample and notes
srcURL of the page to load.src="https://example.com/widget". Must be HTTPS on an HTTPS page.
srcdocInline HTML to render instead of a URL.Takes priority over src if both are set. See the srcdoc section.
titleAccessible name for the frame.title="Checkout form". Treat it as required.
width / heightSize in CSS pixels, written without units.width="560" height="315". Default is 300×150. CSS overrides these.
loadingWhen to load the frame.lazy defers off-screen frames until the user scrolls near them; eager is the default.
allowPermissions Policy: which powerful features the frame may use.allow="fullscreen; autoplay; clipboard-write; encrypted-media; picture-in-picture". Also camera, microphone, geolocation, payment, web-share, storage-access and more.
allowfullscreenLegacy boolean that lets the frame go full screen.Same effect as allow="fullscreen". Still common in embed snippets.
sandboxApplies extra restrictions to the framed content.Empty sandbox applies all restrictions; tokens such as allow-scripts or allow-forms opt back in.
referrerpolicyHow much of your page's URL is sent as the Referer header.no-referrer, origin, strict-origin-when-cross-origin (the browser default) and others.
nameNames the frame so links and forms can target it.name="preview", then <a href="…" target="preview">.
allow grants, it doesn't force

Delegating camera or geolocation with allow only makes the feature available to the frame. The visitor still sees the browser's permission prompt, and autoplay with sound is still subject to the browser's autoplay rules.

The sandbox tokens deserve their own page; the complete guide to the iframe sandbox attribute covers every one.

How to embed YouTube, Google Maps, Google Docs and Vimeo

Big platforms block their normal pages from being framed but publish embed URLs built for it. Pasting the address-bar URL into src is the most common reason an embed fails.

YouTube

Use https://www.youtube.com/embed/VIDEO_ID, not /watch?v=VIDEO_ID. The watch page sends X-Frame-Options: SAMEORIGIN, so it will refuse to load on your site. The easiest route is Share → Embed under the video, which gives you the full snippet.

<iframe
  src="https://www.youtube-nocookie.com/embed/VIDEO_ID?start=30"
  title="YouTube video: Product walkthrough"
  width="560" height="315"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
  referrerpolicy="strict-origin-when-cross-origin"
  allowfullscreen
  loading="lazy"
  style="border:0"></iframe>

Swapping youtube.com for youtube-nocookie.com switches on YouTube's privacy-enhanced mode, which reduces tracking before the visitor presses play. It doesn't make the embed tracking-free once the video runs. Useful query parameters include start (seconds), autoplay=1 (usually needs mute=1 to actually autoplay), and rel=0, which limits end-screen suggestions to the same channel.

Keep the referrer on YouTube embeds

YouTube's own snippet sets referrerpolicy="strict-origin-when-cross-origin". Setting no-referrer can make the player show an error instead of the video, so leave it as YouTube provides it.

Google Maps

A regular google.com/maps/place/… link won't frame. To get embeddable code:

  1. Open Google Maps and search for the place or route.
  2. Click Share, then the Embed a map tab.
  3. Choose a size and click Copy HTML.

The result points at https://www.google.com/maps/embed?pb=…; don't edit the encoded pb value by hand. To build map URLs in code (one per store, say), use the Maps Embed API, which takes readable parameters and a Google Cloud API key:

<iframe
  src="https://www.google.com/maps/embed/v1/place?key=YOUR_API_KEY&q=Eiffel+Tower,Paris+France"
  title="Map: Eiffel Tower"
  width="600" height="450"
  loading="lazy"
  referrerpolicy="no-referrer-when-downgrade"
  style="border:0"
  allowfullscreen></iframe>

Google Docs, Sheets, Slides and Forms

For Docs, Sheets and Slides, go to File → Share → Publish to web, pick the Embed tab, click Publish and copy the iframe. The published version is public to anyone who has the link, and by default Google republishes it automatically when you edit the file. Use the published URL rather than your /edit link; the editor depends on the visitor being signed in with access, so it isn't a reliable embed.

For Forms, click Send, choose the <> embed icon and copy the code. The URL ends in viewform?embedded=true:

<iframe
  src="https://docs.google.com/forms/d/e/FORM_ID/viewform?embedded=true"
  title="Event sign-up form"
  width="640" height="900"
  loading="lazy"
  style="border:0"></iframe>

Vimeo

Vimeo's player lives at https://player.vimeo.com/video/VIDEO_ID. Get the code from Share → Embed. Unlisted videos include an h= hash parameter that must stay in the URL. If a Vimeo embed shows a privacy message instead of the video, the owner has restricted embedding to specific domains in the video's privacy settings.

<iframe
  src="https://player.vimeo.com/video/VIDEO_ID"
  title="Vimeo video: Customer story"
  width="640" height="360"
  allow="autoplay; fullscreen; picture-in-picture"
  loading="lazy"
  style="border:0"></iframe>

Other platforms follow the same pattern: look for an Embed or Share option and paste the code exactly as given.

Check a URL before you embed it

Paste the address you want to frame to see a live preview and the exact header that allows or blocks it.

What is srcdoc? Embedding inline HTML

The srcdoc attribute renders an HTML string directly, with no network request. It's how code playgrounds, email previews and template editors show live output. If an iframe has both srcdoc and src, srcdoc wins.

Because the HTML lives inside an attribute, you must escape & as &amp; and double quotes as &quot;:

<iframe
  title="Rendered preview"
  sandbox
  srcdoc="<h1>Hello</h1><p>Tom &amp; Jerry said &quot;hi&quot;.</p>"></iframe>

From JavaScript it's simpler: set frame.srcdoc = html and the browser handles the escaping.

srcdoc runs with your origin

A srcdoc document inherits the parent page's origin, so its scripts can read your page, cookies and storage. For any HTML you didn't write yourself (user content, emails, AI output), add sandbox and don't include allow-same-origin. If it needs JavaScript, sandbox="allow-scripts" alone keeps it in an opaque origin.

Relative URLs inside srcdoc resolve against the parent page's URL, so <img src="/logo.svg"> loads from your site.

How to style an iframe: border, size and aspect ratio

An iframe is an inline element with a default border. This CSS fixes both and makes it scale with its container:

iframe {
  display: block;          /* removes the gap below inline elements */
  border: 0;               /* replaces the obsolete frameborder="0" */
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;    /* keeps video proportions at any width */
}

iframe.map  { aspect-ratio: 4 / 3; }
iframe.form { aspect-ratio: auto; height: 900px; }

CSS aspect-ratio has been supported in all modern browsers since 2021, so you no longer need the old padding-bottom wrapper hack. It works well for videos and maps, where the proportions are fixed.

Pages and forms are different: their height depends on content. An iframe never grows to fit its content by itself, and your page can't measure a cross-origin frame. The framed page has to report its height with postMessage. The guide to responsive and auto-resizing iframes has working code for both sides.

Load heavy embeds only when needed

Add loading="lazy" to every iframe below the fold. For YouTube, consider a facade: show a thumbnail and swap in the iframe on click. Video players are heavy, and deferring them helps Core Web Vitals. See how iframes affect SEO and page speed for the trade-offs.

Why some websites won't load in an iframe

If you embed a site and get a blank box or a grey "refused to connect" page, the site is almost always blocking you on purpose. The main causes:

CauseWhat you seeWho can fix it
X-Frame-Options: DENY or SAMEORIGINChrome: "example.com refused to connect", plus a console error naming the header.The site owner.
CSP frame-ancestors that doesn't list your originSame as above; the console names frame-ancestors.The site owner.
Mixed content (http:// frame on an https:// page)Blank frame and a mixed-content console error.You: switch to HTTPS.
Your own CSP frame-src or child-srcBlank frame and a CSP violation on your page.You: add the origin to frame-src.
Frame-busting JavaScript or a bot challengeYour page gets redirected, or the frame shows a challenge.Usually the site owner.
Blocked third-party cookiesThe page loads but shows as logged out.The site owner, via cookie settings or the Storage Access API.

X-Frame-Options and frame-ancestors are response headers on the other site. Nothing you put in your HTML can override them. The two options are to use the site's official embed URL, if it has one, or to link to the page instead. Proxying the page through your own server to strip the headers tends to break logins and scripts, and may break the site's terms of use.

For a step-by-step diagnosis, read why an iframe says "refused to connect" and how to fix it. If you run the site you're trying to embed, X-Frame-Options vs CSP frame-ancestors shows how to allow specific domains safely.

Iframe security basics

The same-origin policy stops a cross-origin frame from reading your page, and you from reading it. But a framed page can still open popups, show dialogs, use permissions you delegated and try to navigate your page away. Keep embeds tight:

  • Embed sources you trust. You're running someone else's code in your visitors' browsers.
  • Sandbox untrusted content. Start with an empty sandbox and add only the tokens the embed needs. Never combine allow-scripts and allow-same-origin for same-origin content, because the frame can then remove its own sandbox.
  • Delegate the minimum in allow. A map needs no camera. A video player needs fullscreen and perhaps autoplay.
  • Limit the referrer with referrerpolicy if your URLs contain anything private, such as tokens or search terms.
  • Validate messages. If the frame talks to your page, check event.origin against an allowlist on every message. The postMessage guide shows the pattern.
<!-- A third-party widget that needs scripts and forms, nothing else -->
<iframe
  src="https://widgets.example.net/feedback"
  title="Feedback widget"
  sandbox="allow-scripts allow-forms allow-same-origin"
  referrerpolicy="origin"
  loading="lazy"
  style="border:0; width:100%; height:420px"></iframe>

allow-same-origin is fine here because the widget is on another origin: it keeps its own cookies but still can't reach into your page.

To stop other sites framing yours, send frame-ancestors 'self' plus X-Frame-Options: SAMEORIGIN; the homepage prevention section has server snippets.

How to check if a URL can be embedded

The quickest check is to paste the URL into the testiframe.com iframe tester. It loads the page in a live frame and runs a server-side check that reports:

  • the X-Frame-Options and CSP frame-ancestors values, and whether they allow framing;
  • mixed-content problems, likely frame-busting scripts and bot challenges;
  • how cookies will behave in Chrome and Edge, Firefox and Safari;
  • whether the page would load when framed from your origin, using the "Would it load on your site?" check.

You can also link straight to a result. Comparing a YouTube watch page with its embed URL makes the difference obvious: test a watch URL, then test the embed URL. The tester also has device-size presets, sandbox and allow toggles, and an embed-code generator that writes the snippet for you. Local addresses like http://localhost:3000 work for the preview, though the server check can't reach them.

From a terminal, you can read the headers yourself:

curl -sI https://example.com | grep -iE 'x-frame-options|content-security-policy'

No output means neither header is set, though a login redirect or your own CSP can still get in the way.

FAQ

How do I embed a website in HTML?

Add an iframe element with the page's URL in the src attribute and a short title, for example <iframe src="https://example.com" title="Example site" width="800" height="600"></iframe>. Size it with CSS and add loading="lazy" if it sits below the fold. It only works if the other site allows framing.

Why does my iframe say "refused to connect"?

The site you are embedding sends an X-Frame-Options header or a CSP frame-ancestors directive that doesn't allow your page to frame it. Chrome shows "refused to connect" and logs the reason in the console. Only the site owner can change those headers.

Can I embed any website in an iframe?

No. Many sites, including most banks, social networks and large web apps, block framing to protect against clickjacking. Use the site's official embed option if it has one, or link to the page instead.

How do I embed a YouTube video in HTML?

Use the /embed/ URL, not the /watch?v= page. Click Share, then Embed, under the video and copy the iframe code, or build it yourself with https://www.youtube.com/embed/VIDEO_ID. Swap the domain for youtube-nocookie.com to use privacy-enhanced mode.

How do I make an iframe responsive?

Give it width: 100%, height: auto and a CSS aspect-ratio such as 16 / 9, and remove the border with border: 0. For content whose height changes, the framed page has to report its height to the parent with postMessage.

What is the difference between src and srcdoc?

src loads a document from a URL. srcdoc takes an HTML string and renders it directly. If both are set, srcdoc wins. A srcdoc document shares your page's origin, so sandbox it when the HTML isn't fully trusted.