Interacting With The YouTube iFrame API

Interacting With The YouTube iFrame API

YouTube Player APIs

Displaying a YouTube video within a web app is easy; controlling events like starting the video and detecting when it ended gets a little more involved.  Luckily YouTube has player tools that include Player APIs.  For web applications there are currently three Player API choices: the IFrame API; the JavaScript API; and the Flash API (AS3).  These APIs allow the consumer fine-grained control over the Player including the visibility of Player controls, configuring the Player size, and perhaps most importantly, listening to Player events such as start, stop, etc.  All of these exposed items can be seen in action in the YouTube Player Demo.

Choosing a Player API

I was developing a site where it was required that the user watched a specified YouTube video through completion until being allowed to continue on to another page of a web site.  To get started, I had to choose what YouTube API library would work best in this situation.  Given that I couldn’t expect all end users to have Flash installed, I knew right away that the Flash API was out.  Flash is out the door as a technology and most mobile devices don’t support it in favor the HTML5 player.

The IFrame Player API

With the Flash API out, this leaves the iFrame API and the JavaScript API.  Given its name, one may assume that the JavaScript API is the most modern API and may provide HTML5 capabilities, but it doesn’t.  Listed in the requirements for the YouTube JavaScript API is:  “The end user must have Flash Player 10.1 or higher installed to view everything correctly.”.  So that leaves the IFrame API.  To me, the use of an IFrame seems a bit dated, but the API name is sort of a misnomer.  It’s in fact the newest YouTube Player API and it is completely controllable via – you guessed it, JavaScript!

True to its name, the YouTube Player IFrame API does post content to an <iframe> tag on the page that serves an HTML5 player or Flash player depending on the capabilities of the client browser.  It is very simple to use and the documentation even has a great getting started guide complete with a working code sample:

<!DOCTYPE html>
<html>
  <body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
      // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');

      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          height: '390',
          width: '640',
          videoId: 'M7lc1UVf-VE',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }

      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        event.target.playVideo();
      }

      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
        if (event.data == YT.PlayerState.PLAYING && !done) {
          setTimeout(stopVideo, 6000);
          done = true;
        }
      }
      function stopVideo() {
        player.stopVideo();
      }
    </script>
  </body>
</html>

However, not all samples fit all situations.  This sample defines an OnReady event on line 24 that in turn defines a  function named OnPlayerReady.  That OnPlayerReady function is using a command on line 32 to play the video.  This is setting up the video to autoplay when the page loads.  This works great unless you are on an iOS or modern Android device.  Apple specifically disallows autoplay of audio and video on iOS devices in an effort to preserve any of the user’s possible data usage limitations.  What you instead get is the YouTube Player loads and then the screen goes black and no playback controls are visible.

Special Considerations for iOS and Android

Given that attempting to autoplay a video on iOS or Android causes the player to enter an error state, there’s a need to detect if the client’s user agent is iOS or Android and not autoplay the video.  The user will instead have to push the play button on the YouTube Player.  This can be accomplished by modifying the OnPlayerReady function to detect this:

function onPlayerReady(event) {
    var iOS = /(iPad|iPhone|iPod|Android)/g.test(navigator.userAgent);
    if (!iOS) {
        event.target.playVideo();
    }
}

Detecting When The Video Has Ended

In this sample, the onPlayerStateChange function is assigned to the Player’s onStateChange event.  It is here where player events are captured and can be put to use.  In my case, there was a requirement to somehow track that the user had watched the video to completion in order to visit a certain other page.  This can be accomplished by first creating a session cookie when the player detects the video has Ended.

var done = false;
function onPlayerStateChange(event) {
    if (event.data == YT.PlayerState.ENDED && !done) {
        // create session cookie indicating video watched
        document.cookie = "trackview=watched; expires=0; path=/" // using expires=0 sets a session cookie
        done = true;
    }
}

Verifying The Video Was Watched

At this point the iFrame Player is capturing the Ended state of the video and then issues a session cookie.  Now on the page that needs to ensure that the cookie exists, a check can be placed on its window.onload event:

function checkCookie() {
    var x = readCookie('watched');
    if (!x) {
        document.location.href = "/";
    }
}

window.onload = checkCookie;

Here if the cookie doesn’t exist, the user is being sent back to the site root.  If the cookie does exist a general assumption can be made that the user was issued the cookie when the video was watched to completion, thanks to the YouTube IFrame API event that we subscribed to.

Tags: Filled Under: Programming Posted on: August 11, 2014

4 Comments on “Interacting With The YouTube iFrame API”

  • Dave H

    August 30, 2014 at 5:52 pm

    appreciate you taking the time to write this post, it was helpful. in order to work around the mobile limitations, I managed to attach a loadVideoById to a click event that takes place before the actual video to be loaded. in my instance, a tab had to be clicked before a list of videos that can be played are displayed, so I attached this to that tab being clicked:

    var mobes = /(iPad|iPhone|iPod|Android)/g.test(navigator.userAgent);
    if (mobes) {
    if (window.player.getPlayerState() == 5) {
    window.player.loadVideoById(“jNQXAC9IVRw”); // just a random videoId, could be the first in list
    }
    }

    hope this helps someone out there.

  • Paul A

    January 16, 2015 at 2:16 pm

    Following this discussion I did a simple comment out of the
    event.target.playVideo()
    line in the standard Youtube API loader. This simple act allowed videos embedded with this api to work on Android. I will be trying it later today on IOS. I use js to click the play button from my application. One would not think simply commenting out one line, which is latter essentially simulated by a mouse click a moment later, would transform something that was a black dead box, into a working video. But, it did. Amazing.

    4. The API will call this function when the video player is ready.
    function onPlayerReady(event) {
    //event.target.playVideo(); // comment out this line
    }

  • David Moreno

    February 25, 2015 at 1:54 am

    Tnks! Great post!

    • Cheyanne

      April 12, 2017 at 9:56 am

      TYVM you’ve solved all my preoblms

    Leave a Reply

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