How to handle "Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first." on Desktop with Chrome 66?
Asked Answered
O

20

282

I'm getting the error message..

Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.

..when trying to play video on desktop using Chrome version 66.

I did find an ad that began playback automatically on a website however using the following HTML:

<video
    title="Advertisement"
    webkit-playsinline="true"
    playsinline="true"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://ds.serving-sys.com/BurstingRes/Site-2500/Type-16/1ff26f6a-aa27-4b30-a264-df2173c79623.mp4"
    autoplay=""></video>

So is by-passing Chrome v66's autoplay blocker really as easy as just adding the webkit-playsinline="true", playsinline="true", and autoplay="" attributes to the <video> element? Are there any negative consequences to this?

Orfurd answered 19/4, 2018 at 21:44 Comment(3)
I think playsinline is an iOS thing.Dalmatian
@everyone: How is youtube able to bypass the "no userinteraction" rule?Connelley
This link may helpful developer.chrome.com/blog/autoplayConjugation
E
260

To make the autoplay on html 5 elements work after the chrome 66 update you just need to add the muted property to the video element.

So your current video HTML

<video
    title="Advertisement"
    webkit-playsinline="true"
    playsinline="true"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    autoplay=""></video>

Just needs muted="muted"

<video
    title="Advertisement"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    autoplay="true"
    muted="muted"></video>

I believe the chrome 66 update is trying to stop tabs creating random noise on the users tabs. That's why the muted property make the autoplay work again.

Exhibition answered 7/6, 2018 at 13:24 Comment(9)
Is there a way to enable audio right after the video starts playing? Removing the mute attribute or setting volume attribute doesn't help.Mousey
On MacOs Chrome Version 74.0.3729.131 both snippets give black screenLynnell
@KamilKiełczewski The video was showing a black screen because the src was invalid. I have updated the snippet src so the video auto plays.Exhibition
I had to do muted="true" insteadAdaptation
it's better to set muted=true OR muted=falsePerkoff
@Perkoff I would say do muted="muted" or muted="true" Both work for me.Exhibition
Note that MDN has an excellent page dedicated to autoplay (developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide): why it might be blocked by the browser, how to avoid being blocked, alternative ways to autoplay, how to apply a policy, best practicesLouis
You can also just write muted works at least for me.Abridge
I have this problem with <audio> element, how can I solve it ?Azikiwe
P
78

For me (in Angular project) this code helped:

In HTML you should add autoplay muted

In JS/TS

playVideo() {
    const media = this.videoplayer.nativeElement;
    media.muted = true; // without this line it's not working although I have "muted" in HTML
    media.play();
}
Pontine answered 21/3, 2019 at 15:21 Comment(8)
Absolutely true and unbelievable, even with Ng8, latest Angular version. Angular simply doesn't care about what's going on component's HTML template!Dyan
And, with the new Angular's way of using @ViewChild() you need to set sttatic option to true: @ViewChild('videoPlayer', {static: true}) videoplayer: ElementRef; video: HTMLVideoElement; And then: this.video = this.videoplayer.nativeElement; @ ngOnInit()Dyan
This was my issue, muted in HTML is completely ignored and I had to force it by JS. + 1M to your answer after days searchingAbortifacient
Wow, can't believe I actually needed the javascript-side muting for Angular SSR post-load views. This whole time, I thought the HTML was the problem.Macron
This is only correct answer! Thank you, helped me a lot.Unbroken
This is the elegant solution that worked for me.Rewarding
This helped me get a video playing that wouldn't autoplay in a modal in Vue, thank you!!Feeze
Awesome!! i take more time solve this problem and your answer is correct. unbelievable answer thanks lots!!!!Curdle
R
28

Try to use mousemove event listener

var audio = document.createElement("AUDIO")
document.body.appendChild(audio);
audio.src = "./audio/rain.m4a"

document.body.addEventListener("mousemove", function () {
    audio.play()
})
Rutharuthann answered 26/1, 2019 at 14:58 Comment(2)
Doesn't work anymore in Chrome (tested against version 100.0.4896.127). Edit: mousemove works after performing a click once.Illusionist
this answer took me on a wild rideHopfinger
A
22

I got this error

Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.

And here's what I did in my Angular Project

Key Point: Don't ever assume a video will play, and don't show a pause button when the video is not actually playing.

You should always look at the Promise returned by the play function to see if it was rejected:

ngOnInit(): void{
    this.ensureVideoPlays();
}

private ensureVideoPlays(): void{
    const video = document.querySelector("video");

    if(!video) return;
    
    const promise = video.play();
    if(promise !== undefined){
        promise.then(() => {
            // Autoplay started
        }).catch(error => {
            // Autoplay was prevented.
            video.muted = true;
            video.play();
        });
    }
}

Source: Autoplay policy

Airman answered 25/6, 2021 at 9:44 Comment(2)
elegant solution, very nice!Storeroom
This is the correct answer as it actually handles the uncaught exception. Yes adding mute fixes it but you should still provide error handling then address playing it or not.Jahdol
D
18

The best solution i found out is to mute the video

HTML

<video loop muted autoplay id="videomain">
  <source src="videoname.mp4" type="video/mp4">
</video>
Deirdredeism answered 17/6, 2018 at 22:0 Comment(0)
D
17

Extend the DOM Element, Handle the Error, and Degrade Gracefully

Below I use the prototype function to wrap the native DOM play function, grab its promise, and then degrade to a play button if the browser throws an exception. This extension addresses the shortcoming of the browser and is plug-n-play in any page with knowledge of the target element(s).

// JavaScript
// Wrap the native DOM audio element play function and handle any autoplay errors
Audio.prototype.play = (function(play) {
return function () {
  var audio = this,
      args = arguments,
      promise = play.apply(audio, args);
  if (promise !== undefined) {
    promise.catch(_ => {
      // Autoplay was prevented. This is optional, but add a button to start playing.
      var el = document.createElement("button");
      el.innerHTML = "Play";
      el.addEventListener("click", function(){play.apply(audio, args);});
      this.parentNode.insertBefore(el, this.nextSibling)
    });
  }
};
})(Audio.prototype.play);

// Try automatically playing our audio via script. This would normally trigger and error.
document.getElementById('MyAudioElement').play()

<!-- HTML -->
<audio id="MyAudioElement" autoplay>
  <source src="https://www.w3schools.com/html/horse.ogg" type="audio/ogg">
  <source src="https://www.w3schools.com/html/horse.mp3" type="audio/mpeg">
  Your browser does not support the audio element.
</audio>
Dobsonfly answered 23/5, 2019 at 16:15 Comment(2)
This is a very clever approach, that does not break any policy (since playback does not start anyways), and prevents to have errors. +1Chamonix
Dito. Preventing errors and any policies was as well my goal. Any sound can wait till user interacts - just great!Contraposition
C
16

Answering the question at hand...
No it's not enough to have these attributes, to be able to autoplay a media with audio you need to have an user-gesture registered on your document.

But, this limitation is very weak: if you did receive this user-gesture on the parent document, and your video got loaded from an iframe, then you could play it...

So take for instance this fiddle, which is only

<video src="myvidwithsound.webm" autoplay=""></video>

At first load, and if you don't click anywhere, it will not run, because we don't have any event registered yet.
But once you click the "Run" button, then the parent document (jsfiddle.net) did receive an user-gesture, and now the video plays, even though it is technically loaded in a different document.

But the following snippet, since it requires you to actually click the Run code snippet button, will autoplay.

<video src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" autoplay=""></video>

This means that your ad was probably able to play because you did provide an user-gesture to the main page.


Now, note that Safari and Mobile Chrome have stricter rules than that, and will require you to actually trigger at least once the play() method programmatically on the <video> or <audio> element from the user-event handler itself.

btn.onclick = e => {
  // mark our MediaElement as user-approved
  vid.play().then(()=>vid.pause());
  // now we can do whatever we want at any time with this MediaElement
  setTimeout(()=> vid.play(), 3000);
};
<button id="btn">play in 3s</button>
<video
  src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" id="vid"></video>

And if you don't need the audio, then simply don't attach it to your media, a video with only a video track is also allowed to autoplay, and will reduce your user's bandwidth usage.

Copperhead answered 20/4, 2018 at 2:0 Comment(2)
@JanTuroň no you can't. .play and .pause methods need to be called from the HTMLMediaElement instance directly, or you need to create a bound copy of the method, e.g vid.play.then(vid.pause.bind(vid)), which is not really easier to read than the simple vid.play.then(()=>vid.pause()).Copperhead
Could you please check if things are still as you said? I am using chrome and nothing works as you said. For fiddle, I had to click inside the Iframe(not on the video) then "run" to play the video. And snippet is not working too.Detrimental
B
10

In my case, I had to do this

 // Initialization in the dom
 // Consider the muted attribute
 <audio id="notification" src="path/to/sound.mp3" muted></audio>


 // in the js code unmute the audio once the event happened
 document.getElementById('notification').muted = false;
 document.getElementById('notification').play();
Barbie answered 23/12, 2019 at 11:12 Comment(1)
Não funciona testei no chrome Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document firstColene
M
10

According to the new browser policy, the user must interact with DOM first before playing the Audio element.

If you want to play the media on page load then you can simply add autoplay property to audio element in HTML like this

<video id="video" src="./music.mp4" autoplay>

or if you don't want to do autoplay then you can handle this using Javascript. Since the autoplay property is set to true, media will be played, we can simply mute the media.

document.getElementById('video').autoplay = true;
document.getElementById('video').muted = true; 

Imp: Now Whenever you play the media don't forget to turn the muted property to false. Like this

document.getElementById('video').muted = false; 
document.getElementById('video').play();

Or you can also show a simple popup where the user will click the allow button in the modal. So he interacts with DOM first, then you don't need anything to do

Mala answered 2/11, 2020 at 8:41 Comment(0)
R
4

I had a similar problem, I need to play the video without muting it. The way i did this, wait for a second then triggered the event by button. Here is my code

if (playVideo == '1') {
    setTimeout(function() {
        $("#watch_video_btn").trigger('click');
    }, 1000);
}
Remaremain answered 14/8, 2021 at 7:30 Comment(1)
Didn't work....Unparliamentary
H
4

In my case it's just a click sound which is automatically invoked at the start (which I don't mind if it's silenced). So I use:

const clickSound = new Audio('click.wav');
clickSound.play().catch(function (error) {
    console.log("Chrome cannot play sound without user interaction first")});

to get rid of the error.

Hyaena answered 9/11, 2022 at 7:22 Comment(0)
O
3

I changed my UI to have the user press a button to load the website (and when the website loads after they click the button, the audio plays)

Since they interact with the DOM, then the audio plays!!!

Odessaodetta answered 7/4, 2022 at 18:38 Comment(2)
Sad story, same here.....Unparliamentary
cool idea JesusFlick
B
2

Chrome needs a user interaction for the video to be autoplayed or played via js (video.play()). But the interaction can be of any kind, in any moment. If you just click random on the page, the video will autoplay. I resolved then, adding a button (only on chrome browsers) that says "enable video autoplay". The button does nothing, but just clicking it, is the required user interaction for any further video.

Bonner answered 9/3, 2019 at 17:45 Comment(0)
N
1

I had some issues playing on Android Phone. After few tries I found out that when Data Saver is on there is no auto play:

There is no autoplay if Data Saver mode is enabled. If Data Saver mode is enabled, autoplay is disabled in Media settings.

Source

Nonchalance answered 21/1, 2019 at 10:58 Comment(0)
A
1

I encountered a similar error with while attempting to play an audio file. At first, it was working, then it stopped working when I started using ChangeDetector's markForCheck method in the same function to trigger a re-render when a promise resolves (I had an issue with view rendering).

When I changed the markForCheck to detectChanges it started working again. I really can't explain what happened, I just thought of dropping this here, perhaps it would help someone.

Alkalosis answered 18/5, 2019 at 22:6 Comment(0)
T
1

You should have added muted attribute inside your videoElement for your code work as expected. Look bellow ..

<video id="IPcamerastream" muted="muted" autoplay src="videoplayback%20(1).mp4" width="960" height="540"></video>

Don' t forget to add a valid video link as source

Trossachs answered 3/6, 2019 at 2:17 Comment(0)
L
0
  1. Open chrome://settings/content/sound
  2. Setting No user gesture is required
  3. Relaunch Chrome
Laurustinus answered 7/5, 2018 at 1:57 Comment(13)
This actually did the trick, i was doing SSR with nextjs... why the down votes tho?Surgy
Autoplay Policy Changes. Click meLaurustinus
It only use for developer to test Chrome autoplay policy behaviour locally. developers.google.com/web/updates/2017/09/…Heatherheatherly
Is there a programmatic way to achieve this? I have automated tests running in headless Chrome that are now failing due to this policy. I've tried passing a few different command line flags via Testem to no avail.Reportage
I found that the command line flag --autoplay-policy=no-user-gesture-required is the programmatic way to achieve this setting.Reportage
This only works for your browser, everybody else will still be affectedVapory
Who is upvoting this answer? This is not superuser.com. A solution for your local machine cannot be an acceptable answer.Olette
That's it the answer. thksPercussion
i guess you could be able to trigger gesture programmatically ? anybody?``Furtherance
This suggestion should be removed as it does not address the original posters issue, and does not address the issue at large for any machine other than your own.Dobsonfly
May be this is not exactly what the OP wanted but this can resolve my issue as in our case the browser is in Kiosk mode and we will be managing the browser - so thanks for this.Erland
@Olette I upvoted because I need to have a raspberry pi autoplay a video in a webview. I can set environment settings like chrome settings once and forget. It works for me. None of the javascript-based approaches did anything. I found this SO post via google first. This answer deserves to be here and upvoted.Gorgerin
@Olette OP didn't specify if he was seeking a general solution or personal one, so technically this answer is absolutely acceptable, and in my case this is what I was searching :)Proudfoot
K
0

There are some programmatic solutions for the issue to bypass the feature.

Some examples would be using Java's Robot or Autohotkey, as an another solution on top of the Chrome layer. But IMO it's not very smart. So my favorite workaround for the issue (although a little tricky) is using chrome.debugger's Input.dispatchMouseEvent API from Chrome Extension API.

var __target = 1857385916; // -- replace here with the tab id you desire

var x = 360 // -- replace here with your desired position to emulate click
var y = 360 // -- here as well
var button = "right"
var clickCount = 1

chrome.debugger.sendCommand({ tabId: __target }, 'Input.dispatchMouseEvent', {
    type: 'mousePressed',
    x: x,
    y: y,
    button: button,
    clickCount: clickCount,
}, () => {
  chrome.debugger.sendCommand({ tabId: __target }, 'Input.dispatchMouseEvent', {
    type: 'mouseReleased',
    x: x,
    y: y,
    button: button,
    clickCount: clickCount,
  })
});

Notes for beginners:

Create a Chrome extension with background.js created as the above script, and manifest.json created with debugger permission enabled of course.

Chrome's menu -> "Manage Extensions" -> "Developer mode" enabled -> "load unpacked" to load the extension, as usual.

You may want to know the tab id for your desired tab to emulate a mouse event on. The following script I made might be helpful for quickly identify id of each tab.

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (changeInfo.status === "complete" && tab.active && tab.url) {
        var obj = {
            tabId: tabId,
            title: tab.title,
            url: tab.url,
        }
        console.log("[(background) tab id logger]", obj, );
    }
});

Add "tabs" permission to the manifest.json, reload the extension, click "background page" to open the background script inspection window, paste the above JavaScript script on the console to run the script. If you don't see any error, reload any tab, you would quickly see the tab id for the tab on the console logged.

Kheda answered 2/7, 2023 at 4:9 Comment(0)
A
-2

Audio Autoplay property does not work in MS Edge

Argyrol answered 20/3, 2022 at 23:7 Comment(0)
F
-8

Type Chrome://flags in the address-bar

Search: Autoplay

Autoplay Policy

Policy used when deciding if audio or video is allowed to autoplay.

– Mac, Windows, Linux, Chrome OS, Android

Set this to "No user gesture is required"

Relaunch Chrome and you don't have to change any code

Fourteen answered 20/4, 2018 at 12:46 Comment(3)
You can't possibly ask each and every user to go an change the settings .Cryometer
This could solve the issue for some people actually (kiosks, private and local websites...), but the flag was removed in Chrome 76. Now the only solution is this answerPhylactery
@Cryometer your comment doesn't make sense. If Chrome is not allowing you to autoplay video/audio without the user having initially requested/allowed it, it's for a good reason! For the simple reason that it is a BAD IDEA to allow that for every user (that would make bad intentioned people to use that to their advantage and play something on page load and that would quickly get annoying for everyone). Then yes if you really want to activate this feature it's only for yourself hence having to go deeper and activate a flag. That guy solution was legit.Proudfoot

© 2022 - 2024 — McMap. All rights reserved.