We want our visitors to get our content as fast as possible, which means the content needs to be light, and with the minimum number of requests. But we want to keep users on our pages, and be entertained. This is where embedding videos enters the scene.

Videos illustrate our textual content, bring life to it, and are often served by a third party. What more to ask? Well, there’s a hidden price tag: Videos are slow and heavy to download, even when the visitor is not watching them.

One simple video on a page called through an innocuous iframe can add up to 6 HTTP requests and as much as 450kb of content. The solution I’m proposing in this article can reduce those numbers to 1 request and about 50kb per video, along with a few bytes of JavaScript (on top of the jQuery library if you don’t like vanilla flavor).

And you know what? This solution is not new. It was previously proposed by Amit Agarwal in April 2013.

So, What’s the Trick?

In Amit’s solution, the DOM is parsed by JavaScript on document load, and each call to a YouTube video (through a special div, not a regular iframe) is replaced by a thumbnail preview to which is attached the iframe when clicking on it.

This way, we get a nice preview thumbnail still served by a third-party server that’s a fraction of the weight of the full video player. The video player is loaded only when the video is actually viewed.

My Little Added Value

I rewrote Amit’s code in plain JavaScript and with jQuery for those interested. I kept the original comments in the code to keep it as understandable as possible. My version adds a new feature in the HTML5 data parameter that enables you to add any parameter to the YouTube URL to customize your video.

YouTube offers a list of parameters to show and hide controls, branding, and info, and to set the video quality or the starting frame of your video (among other things).

  • controls: set this to 0, and the layer controls are not displayed on the video player.
  • modestbranding: set this to 1, and the YouTube logo disappears from the control bar.
  • rel: set this to 0, and no related videos will be shown when the playback of the initial video ends.
  • showinfo: set this to 0, and the player will not display information like the video title and uploader before the video starts playing.
  • start: set this to a number of seconds, and the player begins playing the video from this time (or rather from the closest keyframe).
  • vq: set this to the wanted video quality, if supported (e.g.: hd720 when high quality is available)

When adding the YouTube iframe on the click event, some parameters are given values, namely autoplay (we want the video to start as soon as its thumbnail is clicked) and autohide (to hide the video progress bar and the player controls when no interaction is detected).

Supported YouTube Thumbnails

Each YouTube video comes with a list of generated images. You can access them through the URL http://img.youtube.com/vi/<youtube-video-id>/<youtube-thumbnail> (where img.youtube.com can even be shortened to i.ytimg.com, if you prefer).

The ones we are interested in are:

  • default.jpg (default version, 120px x 90px)
  • hqdefault.jpg (high quality version, 480px × 360px)
  • mqdefault.jpg (medium quality version, 320px × 180px)
  • sddefault.jpg (standard definition version, 640px × 480px)
  • maxresdefault.jpg (maximum resolution version, 1.280px × 720px)

As an example, see this URL, which you can use to play around with the values to see the different image options.

In the following code, we use the sddefault.jpg thumbnail. Depending on your needs and the capabilities of the user’s screen, this can be replaced by any of the listed supported formats.


The HTML code sets the YouTube video ID, styles the video size (width and height), and lists the Youtube URL parameters if needed.

<div class="youtube"
     style="width: 500px; height: 281px;">

<div class="youtube" 
     style="width: 640px; height: 360px;">


In the two videos used as examples, the picture ratio is 16:9, which returns the sddefault.jpg thumbnail with horizontal black bands. To hide them when showing this thumbnail, the background-position property is set with the center value, while setting the picture size inlined in the HTML div tag, like style="width:500px;height:281px;". This way, it is possible to show different video sizes on the same page.

The play icon, which tells the users the content is not a mere picture, is added in a layer on top of the thumbnail with an opacity transition to highlight it. We are using a data URI base64-encoded png here (from IconFinder), which saves an HTTP request and works down to IE8.

.youtube {
    background-position: center;
    background-repeat: no-repeat;
    position: relative;
    display: inline-block;
    overflow: hidden;
    transition: all 200ms ease-out;
    cursor: pointer;

.youtube .play {
    background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAERklEQVR4nOWbTWhcVRTHb1IJVoxGtNCNdal2JYJReC6GWuO83PM/59yUS3FRFARdFlwYP1CfiojQWt36sRCUurRIdVFXIn41lAoVdRGrG1M01YpKrWjiYmaSl8ybZJL3cd+YA//NLObd3++eO8x79z5jSq5Gw+8kov0AP8vMR5l1BtBZQM4B8ks75wCdZdYZZj5qLZ4hov2Nht9Z9vhKKSIaB/gI4M4w62KeAO6Mte4lYOq20FxrlqqOibhHmeWbvNC9ZfDX1mLae391aN6limO/gwgvAPJbWeAZuSDingdwXTBw7/0IsyaA/Fkh+KqOkD+YNfHej1QKD+y7iVlOhgLvFqFfNJvNGyuBJ+KDAF8MDd0tgS8y64OlgSdJMsysL4cG7SOHkyQZLhTee7+d2R2rAVy/S+Jd7/32ouBHAP4gNNRGQyTHc/84NhqNywZp5rvjjnnvt21aABFeCQ+RLwAf2hQ8s7sv9OCLk6AHNgQvIrvbfzKCD76g/O6cu7lf/iER/aQGgy448pExZmhdegAPhR9sObFWH1gT3lp7DaA/5bkIgJhZPgsNmz02novj+KqeApj1ubwXWe4kdyeznAgNvTpE/HQmvKqOMeuFogTUVQSRno+iaLRLAJF7uIgL9O4ubgL8aWgB7S44mNX+35YpICUiAvS9sBLkq1WzT+NFffl6AuoiApi6NT37h6sWkBIRZGkQ8YtLgyji6e1mBYTqCEBPG2Naz+0BWQgtoGoRgCzEsd9hAN1X5BfnFZASUfrSAFQNsyZ1FJASUVpHiLinDJG8U2cBZYogkrcNs5waBAGdstbeU9zdqpw0gPwwSAI6VUxHyFlDpOcHUUBBIuYNs14aZAE5RVwyzPr3/0EAEY0TyfGNjBWQvwZ +CTSbehfAH29mrID8bET0+0EUkAd8WYDOmqJ3ecsG30yr9wqRfm6Y+a1BEFDEjHfHvWmY9ck6CygHvBVr8Xhtb4ZE5HZA3y8DvBNA1TjnrmXWf+sioMwZX5V/VHXMGGMMoKdDCxCRvRWBdzKzdHEO+EisilbPyopHYqp6S9UCAsz4iojI7hUDAtyXVQgIDd6KnOoaWNkbI6FaPSuZGyMArsi7MZoloB4zviI/Nhr3X95jltwTRQmoIfgisy5ai+me67OI7fE4nrqjrqfK1t0eby0FPRB6oGVlchL3rgnfrq19RKbVBdhV9IOSwJmfmJi4vi/4ThERitwyCxVAFqydshuCX5awhQ9KtmuIWd8IDZED/nXT77rvVVv6sHRKwjYi91poqP7Dr+Y6JJ1VSZIMA3wkPNy6bX+o8Bcm0sXMdwM8Fxo0A3xORPaWBp6uPXsmbxCRD0NDL0dOANhVCXy6iAjMcjbcrMt3RITKwdMVRdFo+y5yvkL4eWZ+zHt/ZVD4dEVRNGotpst+dZZZH8k86lqn2pIvT/eqrNfn2xuyqYPZ8mv7s8pfn/8Pybm4TIjanscAAAAASUVORK5CYII=") no-repeat center center;
    background-size: 64px 64px;
    position: absolute;
    height: 100%;
    width: 100%;
    opacity: .8;
    filter: alpha(opacity=80);
    transition: all 0.2s ease-out;

.youtube .play:hover {
    opacity: 1;
    filter: alpha(opacity=100);

Vanilla JavaScript Implementation

With no dependency and the fastest implementation, the vanilla JavaScript version uses the smallest DOM ready code I could find.

Browser differences still have to be taken into account, like the lack of support for the getElementsByClassName method in IE8.

'use strict';
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
    if (!document.getElementsByClassName) {
        // IE8 support
        var getElementsByClassName = function(node, classname) {
            var a = [];
            var re = new RegExp('(^| )'+classname+'( |$)');
            var els = node.getElementsByTagName("*");
            for(var i=0,j=els.length; i<j; i++)
            return a;
        var videos = getElementsByClassName(document.body,"youtube");
    } else {
        var videos = document.getElementsByClassName("youtube");

    var nb_videos = videos.length;
    for (var i=0; i<nb_videos; i++) {
        // Based on the YouTube ID, we can easily find the thumbnail image
        videos[i].style.backgroundImage = 'url(http://i.ytimg.com/vi/' + videos[i].id + '/sddefault.jpg)';

        // Overlay the Play icon to make it look like a video player
        var play = document.createElement("div");

        videos[i].onclick = function() {
            // Create an iFrame with autoplay set to true
            var iframe = document.createElement("iframe");
            var iframe_url = "https://www.youtube.com/embed/" + this.id + "?autoplay=1&autohide=1";
            if (this.getAttribute("data-params")) iframe_url+='&'+this.getAttribute("data-params");

            // The height and width of the iFrame should be the same as parent
            iframe.style.width  = this.style.width;
            iframe.style.height = this.style.height;

            // Replace the YouTube thumbnail with YouTube Player
            this.parentNode.replaceChild(iframe, this);

And here is a demo of the code in action:

See the Pen YouTube Embed Optimized with JavaScript by SitePoint (@SitePoint) on CodePen.

The jQuery Implementation

While being more expressive to my eyes and with wider browser support, the jQuery implementation comes with the price of the whole jQuery library and slightly slower performance.

"use strict";
$(function() {
    $(".youtube").each(function() {
        // Based on the YouTube ID, we can easily find the thumbnail image
        $(this).css('background-image', 'url(http://i.ytimg.com/vi/' + this.id + '/sddefault.jpg)');
        // Overlay the Play icon to make it look like a video player
        $(this).append($('<div/>', {'class': 'play'}));
        $(document).delegate('#'+this.id, 'click', function() {
            // Create an iFrame with autoplay set to true
            var iframe_url = "https://www.youtube.com/embed/" + this.id + "?autoplay=1&autohide=1";
            if ($(this).data('params')) iframe_url+='&'+$(this).data('params');
            // The height and width of the iFrame should be the same as parent
            var iframe = $('<iframe/>', {'frameborder': '0', 'src': iframe_url, 'width': $(this).width(), 'height': $(this).height() })
            // Replace the YouTube thumbnail with YouTube HTML5 Player

And here is a demo of the jQuery version:

See the Pen YouTube Embeds Optimized (jQuery Edition) by SitePoint (@SitePoint) on CodePen.

The Final Results

Now, let’s talk about what we gain in real-world situations.

This solution was implemented on this page, which is an article that contains 3 embedded YouTube videos. Here are the results:

  • Before implementing that solution, we had 20 HTTP requests and 636.2kb of content downloaded, which took 2.22s (3.59s on load).
  • Once implemented, we went down to 17 requests, 370.7kb, and 1.05s (onload: 733ms).
  • This means 15% fewer requests, and a web page that’s 41% lighter and 52% faster (onload: 80% faster).

The results are quite good even with only one embedded YouTube video, like on this next page, which is our next example. Here are the results for the single-video page:

  • Before implementing the solution we had 20 HTTP requests and 684.4kb of content downloaded, which took 2.13s (2.14s onload).
  • Once implemented, we went down to 17 requests, 322.4kb, and 1.24s (onload: 975ms).
  • This means we ended up with 15% fewer requests, and a web page that’s 53% lighter and 42% faster (onload: 54% faster).


In closing, I think we can all agree that cutting down on page weight from between 40 to 50% is worth that little piece of code, don’t you think?

If you have any thoughts on the code, or would like to improve it, feel free to fork the code on CodePen or share your views in the comments.

This article is also available in French, Spanish and Portuguese.

Tags: youtube embeds, youtube javascript, youtube performance
Alexis Ulrich is a full-stack web developer based in Paris, France. He is interested in the way content can be created, optimized, used and shared on the web. When not working on his pet sites (languagesandnumbers.com and mancko.com), he shares his MOOC experiences on web-technos.blogspot.com.

Free Guide:

How to Choose the Right Charting Library for Your Application

How do you make sure that the charting library you choose has everything you need? Sign up to receive this detailed guide from FusionCharts, which explores all the factors you need to consider before making the decision.

  • http://blog.piotrnalepa.pl/ Piotr Nalepa

    Nice article. I didn’t know about the thumbnails …

  • http://johngraham.mr John Graham

    Thanks for this, I tried it out on my site today. I put another little twist on it by running the iframe through fitvids.js when it’s added to the DOM.

    • http://www.mancko.com Alexis

      That’s a good idea. Maybe you could fork the CodePen to show us how you did it, as you can link external javascript resources to it.

      • http://johngraham.mr John Graham

        I have created a pen showing how added fitVids.js to your code:


        Here are the rough steps of what I changed:

        1. Remove all css/js/markup that sizes the container

        2. Add the thumbnail as an image inside the youTube container instead of as a background.

        3. Use CSS to position the thumb and help combat the letterboxed effect.

        4. Load the youTube iframe into the container instead of replacing it.

        5. Add a loaded class to the container. This flips the display attribute from inline-block to block in the CSS.

        6. Call fitVids.js on the container.

        • Mathew

          Hi John,
          I tried your solution and the videos were responsive, but the images were not.
          Is it possible to make the images responsive as well.

  • Prashant Palikhe

    Why is the image embedded through JS instead of through html markup. I think within the img tags, the request to the thumbnails would be dispatched earlier, improving the load time. Unless the images are being lazy loaded on-scroll or something similar, which is not the case here.

    • LouisLazaris

      I was discussing with Alexis the possibility of using a class on the HTML to determine the video size and quality of the image. So in that case, you’d have to use JS, because he’s constructing the URL to the image on the fly. In this case, you’re probably right that if you’re only going to load one image and not change it, then it could be done right in the HTML. Unless I’m missing something.

      • http://www.mancko.com Alexis

        You are right. If we had set an image tag within the div directly in HTML, the picture would have been displayed earlier, and the perceived loading time would have been shorter.
        As Louis said, for the sake of genericity, everything is performed in the javascript code.
        However, as the image size is hard-coded in the inlined CSS, which is not a perfect solution, it allows us to define our own image size independently of YouTube preset thumbnails.
        As a side-effect, the lazy loading is de facto handled by javascript (as long as it is run after page load).

  • http://iamntz.com Ionuț Staicu

    I made a plugin for this kind of stuff back in the day. Maybe it will help someone else as well :)
    (also add some goodies like events & triggers)


  • Mike

    Too bad it’s not responsive.

    • http://www.mancko.com Alexis

      You should give an eye to John Graham’s solution in the comments: he has created a CodePen using FitVids.js to handle the responsiveness.

  • RidleyO

    How difficult would it be to do this for an embedded playlist (as opposed to an individual video)?

  • http://www.mancko.com Alexis

    Your plugin is really interesting. Definitively a way to go as you can white label the whole YouTube embed player, even though you download the player code whether your visitor is watching the video or not.

    • http://iamntz.com Ionuț Staicu

      Well, you are right.

      Requirement was to easily embed & interact with videos whenever i wanted to (these videos were placed into some kind of carousel and needed to play/pause when the current video was out of viewport).

      As for responsive, there is a better way of doing this (other than using a 10kb lib!):


  • http://www.mancko.com Alexis

    Thank you for that impressive solution.

  • Wei

    Thanks for the tutorial! That’s brilliant!
    Unfortunately on ios device require to click twice to play the video as autoplay doesn’t kicks in :( http://stackoverflow.com/questions/8141652/youtube-embedded-video-autoplay-feature-not-working-in-iphone

  • Iza

    Lighter is better, but I can’t get to the play button using the keyboard. If these videos can only be played with a mouse, this will be a big issue for keyboard and some assistive technology users. I’m not a developer, so can’t suggest a solution, but I hope you can, Alexis!

    • http://www.mancko.com Alexis

      Challenge accepted!

      The regular YouTube embeds can be accessed through keyboard with the [Tab] key.
      Let’s mimic it.
      The first step is to add a tabindex attribute to the video div (the tabindex value is chosen manually).
      Then we set a handler for keyboard input, and specifically the return key (which has the keyCode 13, while the mouse left button click has the keycode 1).
      – jQuery: the delegate method can take different event types, like ‘click keydown’ (http://codepen.io/mancko/pen/cDewr)
      – vanilla javascript: when pressing the [Return] key, we launch a click event (http://codepen.io/mancko/pen/yGDFp)

  • http://www.echteinfach.tv/ Echt Einfach TV

    How I wished the guys from youtube would implement such an embed option by default to save the entire internet world zettabytes of server loads and trillions of hours of waiting time… thanks for the article. That made me dive into “lazy load youtube plugins” for jquery ;-)

  • mauriciomantilla

    We made a jquery plugin that does somthing like that: https://github.com/8manos/async-media-load
    It works with youtube and vimeo

  • Mike Badgley

    Any particular reason why you wouldn’t just go with the YouTube iFrame API? Otherwise this sort of feels like we’re reinventing the wheel…

    • http://www.mancko.com Alexis

      I have not used that API yet (here’s a link to its documentation: https://developers.google.com/youtube/iframe_api_reference ), but what I can see at a quick glance is that even though the iframe code download can be made asynchronous, the code is downloaded nevertheless, which can be a burden for a mobile device on a limited data plan.
      So it does not seem possible to download only a photo from the video and postpone the full player download until the user actually clicks on it. But I’d be happy you prove me wrong with a working example, though.

      I prefer to play safe with that API to be the less dependent possible on it, both for maintanability issues (there should be only minimal testing in case of an upgrade), and to be able to adapt the code to other providers too (Vimeo, Dailymotion or others).
      Apart from that point, the API offers a way deeper control over the player (volume, playlists…), which can be useful if you want to manage more interaction with the player.

      • Mike Badgley

        Yah good point, I guess it really all comes down to what you what or need. If you need minimal to no control over the video, than your approach is definitely the quickest-and-easiest to go with.

        Thanks for the reply! :)

  • techwgl

    Thank you for this nice article.. java script of youtube is useful for me.

  • චාම‍ර

    Hi Alexis
    Thank you for this nice article..
    How to Change the Iframe to previous state.(like a image link)after stop the video

  • athep

    hey alex, what if you want to embed playlists?

  • http://www.in-ear-studio.com André Santos

    I have a html page with lots of youtube embeds and it’s very heavy. I know the answer to my problem is in this article but i have a few questions: I need to have a local .JS with the code right? Where can i download it? And do i use the css code or html in my html page? The page in question is: http://www.clubfmgroup.com/videosfmgroup.html

  • Stove

    Awesome article! I think one important thing may have been overlooked…

    Regarding autoplay, I don’t believe YouTube counts the views of videos that are embedded and on auto-play, so if you care about getting more actual views on your videos (like me) this might be an issue.

    To avoid this you’d have to remove the autoplay part from the code and the user would have to click twice to start the video.

    Thoughts anybody??

  • paulfenley

    This isn’t working on Mac Safari 5.1.10, OS 10.6.8. Click play and the area turns to black. Nothing else happens. I’m looking for solution to keep youtube video in place. On Safari 5.1.10, the video drops out of position using WordPress x-theme in a column. here: http:reagentmap.com. Any advice would be appreciated. Thank you for the tips!

  • http://www.gamerinside.org/ Yoav

    No solution for the responsive images?

  • http://aarontgrogg.com/ Aaron T. Grogg

    Might want to prepend this article with a note stating that everything here is now deprecated:


  • http://www.james-nock.co.uk James Nock

    I like this and have used it on a website today. My page load speed has increased by over 75%! Thanks for sharing.

  • http://schoberg.net/ Jesse Schoberg

    I’ve made an updated version of this that is responsive, image free, and just a bit more tidy: http://schoberg.net/2015/08/fast-agile-youtube-embed-responsive-iframe-load-delay-with-jquery/

  • easynow

    Is there a way to get the fullscreen button working with this method??
    I assume the API needs ‘allowfullscreen’ appended somewhere.

    ‘fs=1′ is already the default and makes no difference when specified.


    Useful Guideline….

  • Nicolas Dietrich

    Note that the used play icon is licensed CC-BY-NC, i.e. don’t use the code as is on a commercial site.

  • Aivo Kivi

    Any way to include a function in here from Youtube API to stop playing one video if the other is clicked?

  • Aivo Kivi

    Any way to include a function in here from Youtube API to stop playing one video if the other is clicked?

  • Tasha

    I did read through Amit’s version but didn’t have any luck :-(

    Your’s worked perfectly though! Brilliant! Thank you! :-)

Special Offer
Free course!

Git into it! Bonus course Introduction to Git is yours when you take up a free 14 day SitePoint Premium trial.