How to determine if user interacted with document to start video?
Asked Answered
M

4

10

I encounter an error trying to autoplay video in Chrome, which says: DOMException: play() failed because the user didn't interact with the document first.

There is a solution for that for 'normal' pages:

var promise = document.querySelector('video').play();
if (promise !== undefined) {
  promise.then(_ => {
    // Autoplay started!
  }).catch(error => {
    // Autoplay was prevented.
    // Show a "Play" button so that user can start playback.
  });
}

But I play video using Phaser framework Video object, which doesn't return promise, so I need to determine it user has interacted with the page before trying to play video. Is there any solution for that?

Metalinguistic answered 13/11, 2018 at 12:2 Comment(6)
Have you tried setting play on page load?Newsboy
@Newsboy Page could be loaded in some other tab, so that user don't interact with it even as it loadsMetalinguistic
Maybe it's ok to handle tab changes, and dispatch event at this moment?Trollop
@DmitrySamoylov I think it will need at least focus. Unless you can simulate a user action on the page that would trigger autoplay, like for example sending a click event.Newsboy
It's surely because your video has sound, due to new policy, Chrome blocks videos that autoplay with sound : developers.google.com/web/updates/2017/09/…Admonition
But there are websites such as Tiktok.com which plays video directly on chrome.Owing
D
3

I'm not satisfied with the responses to this kind of question so here's my take / solution. Keep in mind this uses React but can also be done natively.

(1) Add event listeners

  const [userInteracted, setUserInteracted] = useState(false)

  useEffect(() => {
    const handleInteraction = (event) => { setUserInteracted(true); console.log(`Event log for: ${event}`); }
  
    document.addEventListener('click', handleInteraction, true)
    document.addEventListener('scroll', handleInteraction, true)
  
    return () => {
      document.removeEventListener('click', handleInteraction('click'))
      document.removeEventListener('scroll', handleInteraction('scroll'))
    }
  }, [])

(2) Use native browser detection object

  if (navigator.userActivation.hasBeenActive) { doSomething() }

I personally use this on a div which plays audio when hovered over:

const App = () => {
  const [userInteracted, setUserInteracted] = useState(false)
  const audioRef = useRef(new Audio(BirdSinging))

  const playAudio = () => { if (audioRef.current && userInteracted && navigator.userActivation.hasBeenActive) audioRef.current.play() }

  const stopAudio = () => {
    if (audioRef.current && userInteracted) {
      audioRef.current.pause()
      audioRef.current.currentTime = 0
    }
  }

  // avoids play() failed because the user didn't interact with the document first
  useEffect(() => {
    const handleInteraction = (thing) => { setUserInteracted(true); console.log(thing); }
  
    document.addEventListener('click', handleInteraction, true)
    document.addEventListener('scroll', handleInteraction, true)
  
    return () => {
      document.removeEventListener('click', handleInteraction('clik'))
      document.removeEventListener('scroll', handleInteraction('scr'))
    }
  }, [])

  useEffect(() => {
    return () => {
      audioRef.current.pause()
    }
  }, [])

  return (
    <div className="logo" onMouseEnter={playAudio} onMouseLeave={stopAudio}>
      <img src={Logo} alt="Logo" />
    </div>
  )
}
Dogleg answered 18/9, 2023 at 8:39 Comment(0)
F
2

Look for user interaction with the window

var interacted = false;
function fun(){
   interacted = true;
   $(window).unbind("scroll");
   $(window).unbind("click");
   play();
}
$(window).bind("scroll click", fun);
function play(){
     if(interacted){
        //play audio or video
     }
}
Faustina answered 28/9, 2020 at 12:27 Comment(0)
S
0

window.onFocus

You can use this method to call an event when the tab is focused using JavaScript.

window.onFocus = function(){
playVideo(); //A dummy function
}

mousemove

You can check mouse movement.

document.addEventListener('mousemove', playVideo);

keydown

You can check if user has pressed a key

document.addEventListener('keydown', playVideo);

I think, these events must be enough to check if user has interacted with your site and call a method.

Shayshaya answered 18/9, 2023 at 8:56 Comment(0)
H
0

        // Set a flag if the user has interacted because the video can't play before
        useEffect(() => {
          interactionListeners()
        }, [])

        function interactionListeners(){
          window.addEventListener("click", setInteractedFunction)
          window.addEventListener("scroll", setInteractedFunction)
        }
        function removeInteractionListeners(){
          window.removeEventListener("click", setInteractedFunction)
          window.removeEventListener("scroll", setInteractedFunction)
        }
        function setInteractedFunction(){
          console.log("setting interacted")
          if(!interacted)
            dispatcher(setInteracted(true))
          removeInteractionListeners()
        }

Hereditary answered 21/10, 2023 at 15:17 Comment(1)
You can pass a third parameter to addEventListener(), an object with some flags like once, so after a first interaction the listener is going to be removed.Ameliaamelie

© 2022 - 2024 — McMap. All rights reserved.