Sometimes you just need to start a video playing by some user interaction on the page other than clicking right on that video itself. Perhaps a “Play Video” button of your own creation lives on your page and you want to start that video when that button is clicked. That’s JavaScript territory. And if that video is a YouTube or Vimeo video, we’ll need to make use of the APIs they provide. No problem.
For these examples, we’ll assume you’ve already picked out a video and you’re going to put it on the page in an
For YouTube
?enablejsapi=1
at the end
1. Make sure the iframe src URL has Like this:
<iframe src="//www.youtube.com/embed/FKWwdQu6_ok?enablejsapi=1" frameborder="0" allowfullscreen id="video"></iframe>
I also put an id attribute on the iframe so it will be easy and fast to target with JavaScript.
2. Load the YouTube Player API
You could just link to it in a <script>
, but all their documentation shows loading it async style, which is always good for third-party scripts, so let’s do that:
// Inject YouTube API script
var tag = document.createElement('script');
tag.src = "//www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
onYouTubePlayerAPIReady
3. Create a global function called This is the callback function that the YouTube API will call when it’s ready. It needs to be named this.
function onYouTubePlayerAPIReady() {
}
It’s likely you have some structure to your JavaScript on your page, so generally I’d recommend just having this function call another function that is inside your organizational system and get going on the right track right away. But for this tutorial, let’s just keep it soup-y.
4. Create the Player object
This is the object that has the ability to control that video. We’ll create it using the id
attribute on that iframe in our HTML.
var player;
function onYouTubePlayerAPIReady() {
// create the global player from the specific iframe (#video)
player = new YT.Player('video', {
events: {
// call this function when player is ready to use
'onReady': onPlayerReady
}
});
}
Another callback!
5. Create the “player ready” callback and bind events
We named this function when we created the player object. It will automatically be passed the event object, in which event.target is the player, but since we already have a global for it let’s just use that.
Here we bind a simple click event to an element on the page with the id #play-button (whatever custom button you want) and call the player object’s playVideo
method.
function onPlayerReady(event) {
// bind events
var playButton = document.getElementById("play-button");
playButton.addEventListener("click", function() {
player.playVideo();
});
var pauseButton = document.getElementById("pause-button");
pauseButton.addEventListener("click", function() {
player.pauseVideo();
});
}
All Together Now
And that’ll do it! Here’s a demo:
See the Pen Play Button for YouTube by Chris Coyier (@chriscoyier) on CodePen.
I used a little SVG templating in there for the buttons just for fun.
For Vimeo
?api=1
at the end
1. Make sure the iframe src URL has <iframe src="//player.vimeo.com/video/80312270?api=1" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen id="video"></iframe>
I also put an id
attribute on the iframe so it will be easy and fast to target with JavaScript.
2. Load the “froogaloop” JS library
The Vimeo player API actually works by sending commands through postMessage
right to the iframe. You don’t need the froogaloop library to do that, but postMessage
has some inherent complexities that this library (by Vimeo themselves) makes way easier. Plus it’s only 1.8kb so I’d recommend it.
<script src="froogaloop.min.js"></script>
3. Create the player object
var iframe = document.getElementById('video');
// $f == Froogaloop
var player = $f(iframe);
We target the iframe by the id
attribute we added. Then we create the player using the special froogaloop $f
.
4. Bind events
All we have to do now is call methods on that player object to play and pause the video, so let’s call them when our play and pause buttons are clicked.
var playButton = document.getElementById("play-button");
playButton.addEventListener("click", function() {
player.api("play");
});
var pauseButton = document.getElementById("pause-button");
pauseButton.addEventListener("click", function() {
player.api("pause");
});
All Together Now
That’ll do it for Vimeo. Here’s a demo:
See the Pen Pause / Play Buttons for Vimeo Videos by Chris Coyier (@chriscoyier) on CodePen.
You can do much more with the APIs for both of these services. It can be pretty fun, just dive in!
YouTube example seems to be busted in Chrome, Version 32.0.1700.77
Weird. Here’s a screencast of the exact same browser working fine for me: https://chriscoyier.viewscreencasts.com/c8bf7c6643664632a1eee2dcc738e1ad
Interesting… onPlayerReady doesn’t seem to be getting called for me.
Heres a screenshot:
I think it’s related to codepen. I can’t get a YouTube iframe to work at all, even all on its own, but I can get it working just fine elsewhere.
I would go with a full browser cache flush. That worked for someone else today. We made some infrastructural changes at CodePen in the last few days that might be causing weirdness here.
Nope, that doesn’t seem to be it either. Running in incognito mode (which should be 100% clear cache) and it still isn’t working. :/
I also went ahead and double checked if Chrome was just not playing nice with iframes inside iframes, but that ain’t it either. Oh well, the code snippet works just fine elsewhere, which I guess is the point of the article anyway :P
Doesn’t seem to be working to me for me either. Chrome version 32.0.1700.102
I had a number of people try it in Chrome and it works for about 50% of people. I wish I could tell you why. I’ll update this if I can. I think if you use the actual code on your site it will probably work fine. As you can see in the video I posted above, I’m using the exact same browser as ya’ll and it works.
It’s just you need to force the html5 player by adding a &html5=1 after the enablejsapi=1
Some people may have chosen to always have the html5 player on their google account.. Those that don’t are seeing a flash player fail.
@Paul adding &html5=1 solved the problem for me in Chrome, although I think this would make it fail in other browsers that require flash. Still a better solution rather than not supporting Chrome at all though.
Yup, the HTML5 parameter was the bit that fixed it for me too. Shame about that as it’s a really nice implementation.
To clarify I don’t know for certain that the html5 player is required for all implementations of this technique. I suspect it is not, but for using YouTube on codepen in general it will be necessary. Likely due to multiple iframes.
Ubuntu 12.04, Fx 26.0, YouTube demo not working for me either…
Dope. Good stuff Chris!
Vimeo is working but youtube result is not working #justsaying Thanks btw
There is a thread about this above. If you have additional info to add, definitely let me know, but I think we’ll just stick with one “it’s not working” thread.
That’s funny I just did some research about thoses Apis last week and … It didn’t work. I think I did not managed whell the callback function for Yt with the imposed name. Are you sure it can’t be customized ?
Thanks a lot
Great!!!
Thank you Chris, bookmarked !
Once you have the YouTube API working there are obviously a ton of additional things you can do with it. I often have custom event tracking set up with Google Analytics – so I can detect when a video is started and how many watch the whole thing (or to a certain point within the video).
You could do a lot more than that, of course, but that seems to me to be a common need for people that are embedding YouTube videos on their pages.
Thanks for the article, Chris! Always good to get people thinking about the possibilities of a sometimes overlooked service!
Not working for me. Chrome 32.0.1700.102 / Mac
Again we’re gonna keep the “not working” stuff to that above thread.
Brilliant as always, Chris.
I’m going to try and mix this with more code to create an autostart once the video is in the viewport and is scrolled to, a la Facebook’s latest feature.
Thanks again!
Just did an in-depth write up on my site about the Vimeo API and running some javascript when videos play, pause, or finish.
http://www.mburnette.com/blog/vimeo-javascript-api-basics
Also, I’m getting a weird error on the Vimeo CodePen example (Firefox 26.0 on Mac).
http://cl.ly/TdDW
Thanks a lot for the examples. Vimeo/froogaloop2 has issues running locally which doesn’t explain CodePen errors. To get up and running I referenced the id twice like so:
<iframe id='vid1' src='url/?api=1&player_id=vid1' etc></iframe>
Love the article. Just one question, in addition to the play and pause functionality how do you create the progress bar functionality when creating a custom youtube player.
Still no solution for iOS… Playing a video first time via script is not allowed.
yeah, u’ll have to take that one up with Apple… The thought is, auto-playing a video means that you’re using a lot of data without really authorizing it. If sites start auto-playing video ads in the background, that would cause a lot of problems with people’s data plans :(
Play/Pause button Replace default button via padding ?
Could you expand this so you can have different buttons for different time stamps within the video?
I have been looking for a solution for time stamps for a videocast I do so viewers can load specific sections of the episode.
Awesome! The html5 parameter was what i was looking for. thank you guys alot
Just so everyone knows, playing a video via the javascript API does not count towards a Youtube view. You’ll need to track the views using another analytics resource. Its a big problem for some clients that just want their Youtube view count number to grow.
Anyone know what I would need to do to make this work for iOS as well? When I click the play button, I just get a black frame…
I assume this has to do with how iOS uses the YouTube app to open YouTube links. Suggestions I could try? Excellent post btw.
Thanks!
Hi Chris,
it works like a charm, even without the “?enablejsapi=1” at the end of a youtube video src. Trying to change the z-index of the iframe in Firefox, I replaced the “?enablejsapi=1” with “?wmode=transparent” and works just as well in Chrome and Firefox. I thought this is worth mentioning.
Thank you!
Levi
wmode=transparent is specifically a flash setting, so in this case it will only affect the youtube flash player. It is a necessary setting when using z-index and the flash player is involved, however you may want to keep the jsapi flag in case your users aren’t seeing the flash player and you are using the javascript api.
So you’d want your string to be ?enablejsapi=1&wmode=transparent
Also doesn’t work in IE9. Anyone with different results?
Thanks for this. It’s fantastic! But how can I get it working for multiple video’s on the same page?!
Hi all! Just thought I’d add my comments regarding the Vimeo play/pause API methodology.
Two things:
First, don’t try to use jQuery to query elements and pass into Froogaloop. It will break.
Secondly, if you’re trying this locally, be sure to run a local server. I had been appending the iframe ‘src’ with ‘http:’ to get the videos to run locally, which threw me off. I wasn’t getting any errors and the click events fired properly, but the API event wasn’t getting called.