Circumventing required user interaction to play HTML5 media

Posted on August 25, 2015 permalink comments

Webkit (and Blink) includes a limitation on mobile, that calling HTMLMediaElement#play has no effect unless it was initiated by user interaction. That supposed to make autoplay impossible, thus saving mobile users from unwanted data traffic in their plan by background music and autoplaying videos. Fair enough.

If you are using something like secure tokens to protect your media URLs, you ask your backend for a fresh token to get the actual video URL to play. Since this operation is asynchronous, you can’t call play soon enough, having your call disarmed. To the end user, this means that they have to tap your play button twice to start the video.

This “feature” is surprisingly poorly documented. No implementation details, just a few bug reports, all about breaking autoplay. After a few hours of empirical testing, I found out that there can be maximum one second between a click event and your #play call, otherwise you’re just trying to get blood out of a stone.

There’s a loophole though: once you have “woken” up your <video> tag with a legitimate #play(), every subsequent call will work afterwards. You don’t even have to have an URL loaded to do so.

So the workaround looks something like this:

Interestingly, if you remove the v.pause() call, it won’t work. I suspect that the browser would find out that there is no media to play in the next tick, rendering the playback state change invalid.

Tested on iOS7+ Safari and Chrome for Android.