Image & Media Delivery

How to Lazy Load Videos and Iframes in WordPress

Why videos and iframes are the heaviest things on your page

You’d be surprised how much of a typical “slow” WordPress page has nothing to do with WordPress itself. A single embedded YouTube video can pull in half a megabyte or more of JavaScript before a visitor ever presses play. A Google Map, a social media post, a review widget — each one is a separate little website running inside your page, and each one adds requests, scripts, and rendering work to your load.

This is the core problem with iframes. An iframe is a window into another site, and the browser has to fetch and execute whatever that site sends back. You can have a beautifully optimized WordPress page — cached, compressed, images converted to WebP — and one embedded video can still double its load time. PageSpeed flags it, visitors feel it, and if you’ve ever wondered why your “optimized” page still scores badly, the answer is often sitting right there in the middle of your content.

Lazy loading is the fix. Instead of loading every embed the moment the page opens, you defer them until the visitor is actually about to see them — or, better still, until they click. Done right, a YouTube embed costs you almost nothing on initial load.

What lazy loading actually does for embeds

When the browser loads a page, it processes resources in order. Anything it needs to fetch — stylesheets, scripts, images, iframes — joins a queue of network requests. Embedded videos are especially expensive because a single YouTube iframe triggers a cascade: the player code, thumbnail images, tracking scripts, fonts, and more, often from several different domains. Each of those domains also needs a DNS lookup and a connection handshake, which adds time on top of the download itself.

Lazy loading changes the order. The browser skips the iframe until it’s close to entering the viewport, then loads it. The initial page load sheds all that third-party weight, which usually shows up as a faster Largest Contentful Paint, less Total Blocking Time, and a noticeably snappier feel — especially on mobile connections.

There are two flavors worth knowing. Standard lazy loading loads the embed when the visitor scrolls near it — the full player loads, just later. The click-to-play “facade” pattern goes further: it shows a lightweight preview image with a play button, and only loads the actual player when someone clicks. The facade is dramatically cheaper, and it’s what I recommend for any video a visitor might never watch.

Method 1: Native iframe lazy loading (the easy default)

Here’s the good news: if you’re running a reasonably current version of WordPress, you may already be doing this. Since WordPress 5.7, core automatically adds loading="lazy" to iframe embeds it generates — YouTube, Vimeo, and other oEmbeds included. You don’t have to configure anything; WordPress handles it when it converts a pasted URL into an embedded player.

You can check whether it’s working in about ten seconds. Open a page with an embed, right-click, choose Inspect, find the iframe element in the markup, and look for the loading="lazy" attribute. If it’s there, native lazy loading is active.

Native lazy loading has limits, though. It only applies to embeds WordPress generates itself — anything your theme or a page builder hard-codes may be missed. And while it delays the load until the iframe is near the viewport, the full player still loads on scroll even if the visitor never intends to watch. For embeds far down the page, that’s perfectly fine. For a video sitting in the first screen, native lazy loading doesn’t help much — and might even hurt, which I’ll come back to.

If you want to force the attribute on embeds from a custom source, the snippet approach is a filter on oembed_dataparse:

add_filter( 'oembed_dataparse', function( $html ) {
    return str_replace( '<iframe', '<iframe loading="lazy"', $html );
}, 10, 1 );

That belongs in a child theme’s functions.php or a code-snippets plugin — never in the parent theme, where an update will wipe it out.

Method 2: The click-to-play facade (the real speed win)

Native lazy loading delays the cost of an embed. A facade eliminates it. The pattern is simple: instead of loading the YouTube player, you show a static thumbnail image with a play button. The image weighs a few dozen kilobytes. When a visitor clicks, you swap in the real player and autoplay it. If nobody clicks, you never pay for the player at all.

The savings are hard to overstate. A standard YouTube embed typically loads several hundred kilobytes of JavaScript and makes dozens of requests. A facade loads one image and a tiny click handler. On pages where the video is supplementary content — a tutorial further down a guide, a testimonial in a sidebar — this is one of the biggest single speed wins available.

The easiest route is a plugin. WP YouTube Lyte has been around for years and does exactly this: it replaces YouTube embeds with lightweight placeholders across your site. If you’re using a caching plugin, check its media settings first — WP Rocket, FlyingPress, and Perfmatters all ship their own YouTube facade or placeholder feature, and there’s no reason to run a second plugin for the same job.

If you’d rather build it yourself, the shape of the solution is straightforward. Take the video’s thumbnail (YouTube serves these at predictable URLs), wrap it in a container styled with a play button, and on click replace the container’s contents with the standard embed URL plus ?autoplay=1. It’s a small piece of front-end work, but the plugin route gets you there faster and stays maintained.

One caution: facades change the visual design of your embeds. A custom play button won’t look identical to YouTube’s player. Most site owners find the trade-off invisible in practice — visitors see a thumbnail with a play button, which is exactly what they expect — but test a page before rolling it out site-wide.

Method 3: Let your optimization plugin handle it

If you already run a performance plugin, open its settings before installing anything new. This is the fastest path for most sites:

  • Perfmatters: its Lazy Loading section covers iframes and includes a YouTube preview-thumbnail mode — the facade, built in. See my Perfmatters vs Asset CleanUp comparison for how it stacks up against alternatives.
  • WP Rocket: enables iframe lazy loading under Media, and can replace YouTube iframes with preview thumbnails.
  • FlyingPress: includes iframe lazy loading and YouTube placeholder support in its media settings.
  • LiteSpeed Cache: offers lazy load for iframes under its media settings if you’re on a LiteSpeed server.

The pattern is the same everywhere: one checkbox for lazy-loading iframes, another for the YouTube placeholder. Turn both on, clear your cache, and verify on a real page. The plugin route also has a quiet advantage — these tools exclude the right things automatically and play well with the rest of their feature set.

Lazy loading embeds in Gutenberg

The block editor makes most of this automatic. Pasting a YouTube or Vimeo URL into a paragraph creates an Embed block, and WordPress applies its native iframe lazy loading to it, as described above. The Video block works the same way for uploaded video files — and it has an extra option worth knowing: in the block settings under “Preload”, you can choose how much of the video the browser fetches before playback. “Metadata” (the default) is usually right; “None” is lighter still for videos most visitors won’t play.

One thing the block editor won’t do for you is the facade pattern. If you want click-to-play for YouTube embeds, that still comes from a plugin setting, not from Gutenberg.

What you should NOT lazy load

Lazy loading is a “below the fold” technique, and applying it above the fold backfires. The rules are simple:

  • Never lazy load the hero video. If a video is the first thing visitors see — a hero background video, a product demo at the top of a landing page — lazy loading delays the very content the page is about. The Largest Contentful Paint suffers, and the video can pop in late with a visible shift.
  • Don’t lazy load the LCP element. If PageSpeed tells you your LCP element is an image or video that loads lazily, that’s a direct instruction to exclude it. The same principle applies to iframes that form part of the first screen.
  • Leave interactive embeds alone. Anything a visitor needs to interact with immediately — a booking widget, a checkout embed, a contact form — should load normally. Deferring these trades perceived speed for actual annoyance.

Most plugins let you exclude specific iframes or videos by URL or CSS class. If you find an embed loading late that shouldn’t be, that’s where you fix it. My LCP checklist and the guide to lazily-loaded LCP images cover the same mistake from the image side — the logic is identical.

How to verify lazy loading is actually working

Don’t trust the settings page. Check the page itself:

  1. Open the page in Chrome and open DevTools (F12), then the Network tab.
  2. Reload and watch the requests. With a facade in place, you should see the thumbnail image but no youtube.com or player requests until you click. With plain lazy loading, iframe requests should appear only as you scroll the embed into view.
  3. Search the page source for loading="lazy" on the iframe to confirm native handling.
  4. Run PageSpeed Insights before and after. Watch Largest Contentful Paint and Total Blocking Time — these are the metrics embeds move most.

Testing in an incognito window matters, because admin-bar scripts and logged-in caching exclusions can skew what you see. And always test on a throttled mobile connection — that “Fast 4G” preset in DevTools is where embed weight is most visible. If you want a refresher on reading the results properly, my guide on testing WordPress site speed the right way walks through the whole workflow.

Common mistakes and how to fix them

The facade breaks the layout. A placeholder image with the wrong aspect ratio causes layout shift when the player loads — the exact problem CLS measures. Fix: set an explicit aspect ratio (16/9 for most video) on the container so the space is reserved before anything loads.

Lazy loading fights with the caching plugin. Running two tools that both rewrite embeds — say, a dedicated YouTube plugin plus your caching plugin’s media feature — can produce double-wrapped or broken players. Fix: pick one tool for embeds and disable the feature in the other.

Autoplay videos go silent. Background hero videos with autoplay and the facade pattern don’t mix — a click-to-play placeholder on an autoplay video is just a broken design. Fix: exclude autoplay videos from lazy loading entirely; they’re above the fold anyway.

Cookie-consent tools block the preview. Some consent plugins block YouTube’s thumbnail domain along with the player, leaving a blank box. Fix: whitelist the thumbnail CDN in your consent tool, or serve the preview image from your own media library.

“It works in the editor but not on the site.” Nine times out of ten this is caching — the page cache is serving the old markup. Fix: purge all caches (page cache, and your CDN if you use one) after changing media settings.

Get these right and embedded content stops being a tax on every pageview. A facade on your YouTube embeds plus native lazy loading on the rest is a combination that takes minutes to set up and keeps paying off on every single visit.

Leave a Reply

Your email address will not be published. Required fields are marked *