Using the YouTube iFrame API
In Articulate Storyline, you can embed videos and you have full control over them. However, many times you want to show an external YouTube video and yet, you want to be able to pause, restart, rewind, change the speed and jump to certain point…
Maybe you’re planning to pop a question time to time, and based on the answer, you jump to different parts of the YouTube video? Let users select from a playlist? Build a Q&A where learner select the question and you jump to the answer in a YouTube video without having the learner looking for that 30 seconds? Awarding learners coins/points in a game for watching, not just launching a video? 🙂 Anything is possible.
The following example shows how to control a YouTube video via its iFrame API. You can download the source and play around with it. This is really just the basic framework to show a potential implementation.
How does it work?
If you haven’t used YouTube’s iFrame API, here’s the link for a deep dive.
What you see in the example is a Storyline course with a WebObject. Not video! The WebObject is actually an html page, called placeholder.html. This html page is loaded inside Storyline. The purpose of the html page is to load the YouTube video using the API framework. This might sound exotic like a Mr. Robot episode but believe me, it’s really simple. Once you download the source you’ll see that it’s couple of lines of JavaScript and you’re good to go.
As a recap, we have the Storyline course with the control buttons and a WebObject that does the magic of hooking up with YouTube. The rest is just making sure Storyline can talk to the video itself (and the video can send back status messages). The buttons you see on the screen execute JavaScript calls to the WebObject.
It’s like a situation like in the (very) old days when we used to have antennas on the roof. Someone was standing on the roof adjusting the antenna, while the other was inside the house watching the TV reception. They couldn’t see each other. With no cellphones, the only communication was shouting: left, left, too much. Right. Now! And occasionally, a shout from the roof: SH@!#!$T!
Storyline is “blind” to what the video is playing. It can send commands to the html page what to do with the video like play, start, seek, etc. The html page can also “shout back” if anything happens like the clip ends, for example.
The placeholder.html is a file you embed as a WebObject. It connects to YouTube via its iFrame API, and replaces the “Loading video…”
temporary text with the actual video with the id “hJpyMhbqNbc” (that’s my video clip, you would change this to yours, of course). This is the YouTube ID you can get from the browser for your video. You can set the initial controls for your video player (just like you would in a link like “rel=0” won’t load random related videos at the end).
You also declare some functions (this is the shouting from the roof back to the guy in the house what’s going on SH@!#!#!) like “onReady.” This is called when the video is ready to play. These parameters are defined in the API. You can also play with the height and width. The parameters below were just for testing.
placeholder.html
<HTML> <BODY> <div id="myplayer">Loading video...</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() {
//Use playerVars to control your player. player = new YT.Player('myplayer', { height: '500', width: '100%', videoId: 'hJpyMhbqNbc', playerVars: { 'autoplay': 1, 'controls': 0, 'rel':0 }, 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. // When the video is over (or you could use any given time) it tells Storyline. var done = false; function onPlayerStateChange(event) { if (event.data == YT.PlayerState.ENDED && !done) { parent.ended(); done = true; } } // Video player functions function pauseVideo() { player.pauseVideo(); } function playVideo() { player.playVideo(); } function restartVideo() { player.stopVideo(); player.seekTo(0); player.playVideo(); } function playVideoFrom(sec) { player.seekTo(sec); player.playVideo(); } // This would be better calling the available playback rate options first. The sp (speed) is just the suggested speed. function speedVideo(sp) { player.setPlaybackRate(sp) } </script>
 Download the Source
You can download the source from here. In order to make it work for you, you must do the following steps:
- Upload the placeholder.html to a webserver. It will not run from your laptop drive.
- Grab the URL to the newly uploaded placeholder.html (full URL like http://mywebserver/folder/placeholder.html)
- Open the Storyline source.
- Edit the WebObject and change the original URL to yours.
- Publish the Storyline course.
- Open the user.js file in the /story_content folder. At the bottom of the file, add the following code:
function ended() { var player=GetPlayer(); player.SetVar("End",1); }
- Why the code? When you publish your Storyline course, it overwrites the user.js file and these couple of lines disappear. You need to add it back after each publish!!This is the function your placeholder.html will call when the clip ends. This function then changes the variable “End” to 1 in Storyline and there’s a trigger to show a layer. If you don’t have these lines in your user.js, the layer will not show.Similar to that, you can add a function that is called at a position of the timeline. Maybe you want to question at 1:05 minute.
- Upload your Storyline course to the webserver (preferably the same domain as the placeholder.html) and test.
- You can then edit the placeholder.html and change the YouTube ID to your video… And the fun starts.
juan
November 3, 2016 9:54 amGood afternoon, first of all thanks for showing how to implement through playholder.html youtube videos that are so unpredictable. Working on the idea of ​​creating a function to interact with the timeline had doubts, the first question is that if that role should go in user.js and how should be implemented for 3 minutes to reach a layer opens in .story. Thank you very much for everything and a great contribution.
Trevor White-Miller
January 31, 2017 1:07 pmHi, I sent an email to olahzolt@hotmail.com asking about the same solution but for Vimeo video clips instead of youtube clips. I can’t seem to be able to adapt the code to get it to work with the Vimeo API. Can I contact you directly for advice? I’m also happy to pay for the solution.
Regards
Trevor
olahzsolt@hotmail.com
February 11, 2017 10:54 pmHi,
The email you sent to has a typo, so I never got it. It’s olahzsolt (with zs not just z). I haven’t worked with Vimeo API but I can check it out.
Bryan
March 8, 2019 10:52 amThis is great work. Thank you. I am also interested in using this for Vimeo, but can;t get it to work. Any ideas?
Stephen Hesketh
May 12, 2019 9:50 pmHi,
This is a great idea!
Could you adapt this code to run via an Arduino that would stop and start a youtube clip when you pushed a button, which could link to a project?