Grow your CSS skills. Land your dream job.

Play and Pause Buttons for YouTube and Vimeo Videos (via Their APIs)

Published by Chris Coyier

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

1. Make sure the iframe src URL has ?enablejsapi=1 at the end

Like this:

<iframe src="//" 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 = "//";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

3. Create a global function called onYouTubePlayerAPIReady

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 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() {
  var pauseButton = document.getElementById("pause-button");
  pauseButton.addEventListener("click", function() {

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

1. Make sure the iframe src URL has ?api=1 at the end

<iframe src="//" 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() {

var pauseButton = document.getElementById("pause-button");
pauseButton.addEventListener("click", function() {

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!


  1. Cp
    Permalink to comment#

    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:

    • Cp
      Permalink to comment#

      Interesting… onPlayerReady doesn’t seem to be getting called for me.
      Heres a screenshot:

    • Covarr
      Permalink to comment#

      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.

    • Covarr
      Permalink to comment#

      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

    • Todd
      Permalink to comment#

      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.

    • Permalink to comment#

      @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.

    • Permalink to comment#

      Yup, the HTML5 parameter was the bit that fixed it for me too. Shame about that as it’s a really nice implementation.

    • Permalink to comment#

      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…

  2. Dope. Good stuff Chris!

  3. Permalink to comment#

    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.

  4. 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

  5. Marcelo Silva
    Permalink to comment#


  6. Thank you Chris, bookmarked !

  7. Bryan Gruhlke
    Permalink to comment#

    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!

  8. Not working for me. Chrome 32.0.1700.102 / Mac

  9. Permalink to comment#

    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!

  10. Permalink to comment#

    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&amp;player_id=vid1' etc></iframe>

  11. zanrick
    Permalink to comment#

    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.

  12. Andre
    Permalink to comment#

    Still no solution for iOS… Playing a video first time via script is not allowed.

    • Cp
      Permalink to comment#

      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 :(

  13. Play/Pause button Replace default button via padding ?

  14. Permalink to comment#

    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.

  15. Permalink to comment#

    Awesome! The html5 parameter was what i was looking for. thank you guys alot

  16. lawrence
    Permalink to comment#

    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.

  17. Permalink to comment#

    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.


  18. Permalink to comment#

    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!


    • Permalink to comment#

      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

  19. bresson
    Permalink to comment#

    Also doesn’t work in IE9. Anyone with different results?

  20. James Church
    Permalink to comment#

    Thanks for this. It’s fantastic! But how can I get it working for multiple video’s on the same page?!

  21. 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.

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".