Skip to content

Instantly share code, notes, and snippets.

@sidneys
Last active April 16, 2026 04:02
Show Gist options
  • Select an option

  • Save sidneys/02a9025ae1f23aefe1f4ea02e78b0ac8 to your computer and use it in GitHub Desktop.

Select an option

Save sidneys/02a9025ae1f23aefe1f4ea02e78b0ac8 to your computer and use it in GitHub Desktop.
Userscript | YouTube: Stop Automatic Video Playback
// ==UserScript==
// @name YouTube: Stop Automatic Video Playback
// @namespace org.sidneys.userscripts
// @homepage https://gist.githubusercontent.com/sidneys/02a9025ae1f23aefe1f4ea02e78b0ac8/raw/
// @version 4.7.3
// @description Stop automatic video playback everywhere. Works on first page load & after navigating.
// @author sidneys
// @icon https://www.youtube.com/favicon.ico
// @noframes
// @match http*://www.youtube.com/*
// @require https://greasyfork.org/scripts/38888-greasemonkey-color-log/code/Greasemonkey%20%7C%20Color%20Log.js
// @run-at document-start
// ==/UserScript==
/**
* ESLint
* @global
*/
/* global Debug */
Debug = false
/**
* Applicable URL paths
* @default
* @constant
*/
const urlPathList = [
'/channel',
'/watch'
]
/**
* YouTube API Player States
* @constant
* @enum
*/
const PLAYERSTATE = {
'-1': 'UNSTARTED',
0: 'ENDED',
1: 'PLAYING',
2: 'PAUSED',
3: 'BUFFERING',
5: 'CUED'
}
/**
* Generate a method name for an event name using the DOM convention ("on" + Event Name)
* @param {String} eventName - Event name (e.g. 'Click')
* @returns {String} - Method name (e.g. 'onclick')
*/
let getHandlerMethodNameForEventName = eventName => `on${eventName.toLowerCase()}`
/**
* Lookup the first <video> Element
* @returns {Element} - <video> Element
*/
let getVideoElement = () => document.querySelector('video')
/**
* Lookup YouTube Video Player through the DOM
* @returns {Object} - YouTube Video Player
*/
let getYoutubePlayer = () => {
console.debug('getYoutubePlayer')
// Lookup Player element
const playerElement = document.querySelector('ytd-player')
// Return the property containing the Player API
return playerElement && playerElement.player_
}
/**
* Stop playback on YouTube via the Player API
* @param {Object} youtubePlayer - YouTube Video Player API
*/
let stopYoutubePlayerPlayback = (youtubePlayer) => {
console.debug('stopYoutubePlayerPlayback')
// Get YouTube Video element
const videoElement = getVideoElement()
// Playback event types to watch
const eventTypeList = [ 'play', 'playing', 'timeupdate' ]
// Iterate playback event types
eventTypeList.forEach((eventType, eventTypeIndex) => {
// Playback "Stopper" method, each playback event
let eventHandler = () => {
console.debug(`videoElement#${eventType}`)
// Remove all "Stopper" event handlers by deleting <video>#onplay, <video>#onplaying, <video>#ontimeupdate
eventTypeList.forEach((eventType) => {
const handlerMethodName = getHandlerMethodNameForEventName(eventType)
delete videoElement[handlerMethodName]
videoElement[handlerMethodName] = null
// DEBUG
console.debug('videoElement', 'removing event handler method:', handlerMethodName)
})
// Lookup YouTube Player state
const playerState = youtubePlayer.getPlayerState()
// Stop video (if it is not already paused)
if (youtubePlayer.getPlayerState() !== 2) {
youtubePlayer.pauseVideo()
// Status
console.info('Stopped automatic video playback', 'during the', PLAYERSTATE[playerState], 'phase')
// DEBUG
console.debug('stopYoutubePlayerPlayback', 'eventType:', eventType, 'playerState:', `${playerState} (${PLAYERSTATE[playerState]})`)
}
}
// Add event handler to video element
const handlerMethodName = getHandlerMethodNameForEventName(eventType)
videoElement[handlerMethodName] = eventHandler
})
}
/**
* Init
*/
let init = () => {
console.info('init')
// Verify URL path
if (!urlPathList.some(urlPath => window.location.pathname.startsWith(urlPath))) { return }
// Initiate lookup loop
let requestId
let lookup = () => {
// Lookup YouTube Player
const youtubePlayer = getYoutubePlayer()
// Is 1. the Player API available, 2. the Player ready?
if (!youtubePlayer || (youtubePlayer && !youtubePlayer.isReady())) {
// DEBUG
console.debug('❌ YouTube Player API unavailable or Player not ready yet.')
// Skip loop
requestId = window.requestAnimationFrame(lookup)
return
}
// Stop Playback
stopYoutubePlayerPlayback(youtubePlayer)
// DEBUG
console.debug('✅ YouTube Player API available and Player ready.')
// End loop
window.cancelAnimationFrame(requestId)
}
// Initiate loop
requestId = window.requestAnimationFrame(lookup)
}
/**
* Handle in-page navigation (modern YouTube)
* @listens window:Event#yt-navigate-finish
*/
window.addEventListener('yt-navigate-finish', () => {
console.debug('window#yt-navigate-finish')
init()
})
@huyz
Copy link
Copy Markdown

huyz commented Oct 8, 2024

Thanks, works as of 2024-10-07!

@photonstarz
Copy link
Copy Markdown

do you by any chance have a version that doesn't automatically pause the video every time? It does that on mine for some reason.

@DBGx64
Copy link
Copy Markdown

DBGx64 commented Feb 15, 2026

it doesn't block autoplay current video on chrome

@huyz
Copy link
Copy Markdown

huyz commented Feb 20, 2026

Still seems to work for me

@Klinoklaz
Copy link
Copy Markdown

Klinoklaz commented Apr 15, 2026

This doesn't seem to block autoplay in playlists, remove the pp param from url sometimes works, but breaks after any action (pause/resume, etc.). Probably gotta disable ended, progress, resize, waiting event listeners too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment