Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Script to remove all videos from Youtube Watch Later playlist

UPDATED 3.12.2020

The old version of youtube with "disable_polymer" is not working anymore, so the script also stopped working.

Thanks to JanTheDeveloper we have a new working script. Big up!

I just changed the '//span[contains(text(),"Watch later")]', to '//span[contains(text(),"Remove from")]', and it should work for any playlist, not just the watch later one. (thanks to hudsonite for the tip)

setInterval(function () {
  document.querySelector('#primary button[aria-label="Action menu"]').click();
  var things = document.evaluate(
    '//span[contains(text(),"Remove from")]',
    document,
    null,
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
    null
  );
  for (var i = 0; i < things.snapshotLength; i++) {
    things.snapshotItem(i).click();
  }
}, 1000);

I moved the old working code to another gist

@janilowski
Copy link

janilowski commented Aug 31, 2021

Excellent!!! Thanks a ton @JanTheDeveloper. Using this together with Google Takeout to export and clear my Watch Later playlist.

I'm likely to put this into a simple browse extension for my own private use. Wouldn't mind sharing that in a repo publicly, but only with permission from Jan

Sorry for the response time, changed accounts and didn't notice so many people are using the script 😀
If you still want to use my script in your extension that is completely fine, just post it under a libre license like GPL or MIT.

@Psicrow
Copy link

Psicrow commented Sep 27, 2021

Worked 27.09.2021
i just make changes becouse my youtube is in pt-br

setInterval(function () {
  document.querySelector('#primary button[aria-label="Menu de ações"]').click();
  var things = document.evaluate(
    '//span[contains(text(),"Remover de")]',
    document,
    null,
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
    null
  );
  for (var i = 0; i < things.snapshotLength; i++) {
    things.snapshotItem(i).click();
  }
}, 100);

@Acendro
Copy link

Acendro commented Sep 29, 2021

I just came across this thread and wanted to share my approach:

It works on any playlist and is language independent plus only threshold % watched videos get removed.
Also added the option to delete all videos and wrapped it into a tampermonkey file.

https://gist.github.com/Acendro/098f82e014a21ea18cad25af77d0bcff

@bryancasler
Copy link

bryancasler commented Oct 7, 2021

Just discovered a native way to remove ALL watched videos!

I had 5,000 videos in my watch later playlist and it took about 10 seconds before it was down to 1,675 videos; I refreshed the page after 10 seconds in excitement. When I tested it again with only a handful of watched videos it did it within a few seconds and no manual refresh was necessary.

  • Go here on desktop: https://www.youtube.com/playlist?list=WL
  • Click the three horizontal dots under "Watch later" and next to the "Shuffle Play" icon
  • Click "Remove watched videos"
  • Click "Remove" on the popup to confirm their removal

@jzisser9
Copy link

jzisser9 commented Oct 7, 2021

Hi Bryan,

Thanks for your response, however two problems with this approach:

  1. Its availability is inconsistent. It's available in the browser on desktop, and sometimes on mobile, but not always - either that or they took the feature down there.
  2. It only removes videos you've already watched. This thread is about removing all videos from the WL playlist.

@LucasPlacentino
Copy link

LucasPlacentino commented Oct 16, 2021

@blackmailer75 This worked on 2021.10.16 for deleting all of my remaining 400 "Unavailable" or "Deleted" videos from my Watch Later playlist. Thank you!

Unfortunately, this way don't work in my case. After clearing all "normal" videos from WH list I use following script to delete Deleted and Private videos: setInterval(function() { document.querySelector('#primary button[class="style-scope yt-icon-button"]').click(); var things = document.evaluate('//span[contains(text(),"Remove from")]',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var i = 0; i < things.snapshotLength; i++) { things.snapshotItem(i).click(); } }, 1000);

@bryancasler
Copy link

bryancasler commented Oct 19, 2021

@jzisser9 I only have one phone to test, but it has shown up 100% of the time on the mobile Youtube app, not sure about the Youtube web app. And yes, you're right it only removes watched videos but still, could be a HUGE time saver before running any of these scripts.

@sabafr001
Copy link

sabafr001 commented Oct 19, 2021

Works well! :)

me too it works

@Kshatriyaprithviraj
Copy link

Kshatriyaprithviraj commented Nov 2, 2021

Yeah, the script above works but there's also a better idea which is https://myaccount.google.com/u/2/youtubeoptions?rapt=AEjHL4O3TGX89Dxo2QJFPCy3eel_5Ocuh2jpX-mltnYqkpd3HWW4ugu4KWoVdr8ji5JMNJLQF5J3f5-Gh410ePHn9xvxtjL3FQ and all of your youtube playlists, history & liked videos ever will be deleted.

@ibrag8998
Copy link

ibrag8998 commented Nov 4, 2021

Thanks! Worked for me, but for ~200 videos, now yt says "this function is temporary unavailable".

@Amit-pl
Copy link

Amit-pl commented Nov 17, 2021

Thank you, it works great, Good job, Andrei !

@DShip91
Copy link

DShip91 commented Feb 15, 2022

Is there a version of the script that only removes unavailable and deleted videos?

@youurayy
Copy link

youurayy commented Mar 6, 2022

This worked for me. Make sure to leave that Chrome tab open on the foreground, even if not active Chrome window. When the list is massive, sometimes close & open of a new tab is needed.

setInterval(() => {
  document.querySelector('#primary button[aria-label="Action menu"]').click();
  document.evaluate('//span[contains(text(),"Remove from")]', document, null, 
   XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0).click();
}, 500);

@FarisPalayi
Copy link

FarisPalayi commented Mar 8, 2022

Thanks for this script man. Saved me a lot of time. :)

@TakshPSingh
Copy link

TakshPSingh commented Mar 10, 2022

Does anyone have any guesses for what youtube's rate limit is? I have to wait for a few minutes after every ~300 videos that I delete.

@sthompson-celerity
Copy link

sthompson-celerity commented Mar 21, 2022

This will only work while you are watching the playlist:
you need to change the value of howManyToDelete to decide how many of the videos you want to delete

howManyToDelete = 5;
loopValue = 0;
new Promise((resolve1, reject) => {
  const loop = function () {
    if (++loopValue > howManyToDelete) {
      resolve1();
    } else {
      document.querySelector('#secondary button[aria-label="Action menu"]').click();
      new Promise((resolve) => setTimeout(() => resolve(), 200))
        .then(() => {
          document.querySelector('ytd-menu-service-item-renderer[aria-selected="false"]').click();
        })
        .then(new Promise((resolve) => setTimeout(() => resolve(), 200)))
        .then(loop)
        .catch((err) => console.log(err));
    }
  };
  loop();
});

@SarahLearnsGrows
Copy link

SarahLearnsGrows commented Mar 29, 2022

Thank you, this is working for me at the moment! —SLG

@handictra
Copy link

handictra commented Mar 31, 2022

Works perfect for me
Just suited to german

setInterval(function () {
// Changed "Action menu" to "Aktionsmenü" (DE)
  	document.querySelector('#primary button[aria-label="Aktionsmenü"]').click();
  	var things = document.evaluate(
// ... as well as "Remove from" to "Aus"
    '//span[contains(text(),"Aus")]',
    document,
    null,
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
    null
  );
  for (var i = 0; i < things.snapshotLength; i++) {
    things.snapshotItem(i).click();
  }
},` 1000);

@DewasSquid
Copy link

DewasSquid commented Apr 4, 2022

For all the french here, use this :
setInterval(function () { document.querySelector('#primary button[aria-label="Menu d\'actions"]').click(); var things = document.evaluate( '//span[contains(text(),"Supprimer de")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < things.snapshotLength; i++) { things.snapshotItem(i).click(); } }, 1000);

@othyn
Copy link

othyn commented May 3, 2022

It's insane to me that in 2022 this is still the only way to clear YouTube's Watch Later, and with much pain involved because you hit their stupid rate limit after 200 requests.

I have a Pi Hole and other blockers so YouTube can't tell when a video is 'watched'.

I have around 3,000 videos to clear. It always takes hours as it gets this way every few months.

@jzisser9
Copy link

jzisser9 commented May 3, 2022

It's insane to me that in 2022 this is still the only way to clear YouTube's Watch Later, and with much pain involved because you hit their stupid rate limit after 200 requests.

I have a Pi Hole and other blockers so YouTube can't tell when a video is 'watched'.

I have around 3,000 videos to clear. It always takes hours as it gets this way every few months.

Me too. I'm starting to wonder if this can be done through API calls too.

@othyn
Copy link

othyn commented May 3, 2022

Checking the official YouTube API docs, it does seem possible. I'm yet to go through their official examples repo, but by the looks of it you could use the playlistitems list endpoint to grab all the video ID's in the playlist, then loop through them and send a delete request using the playlistitems delete endpoint.

The only limitation, and its a massive one, is that you are limited to 10,000 'units' per day, with playlist deletions costing 50 per request meaning you'd blow through the quota in just 200 video deletions, which is insane and according to YouTube is 'an amount sufficient for the majority of our API users'. In order to get more, they have to audit your project:

The YouTube Data API uses a quota system to ensure that developers use the service as intended and do not create API clients that unfairly reduce service quality or limit access for others.

Projects that enable the YouTube Data API have a default quota allocation of 10,000 units per day, an amount sufficient for the majority of our API users. You can see your quota usage on the Quotas page in the API Console.

If you would like to request additional quota beyond the default allocation, you must first complete an audit to show that your project is in compliance with the YouTube API Services Terms of Service. This gives YouTube visibility into the intended use cases of large projects and ensures that YouTube's API services are being used in a manner that is free from abuse. Visit this link for additional details on complying with YouTube’s Developer Policies.

I remember all this going down with 3rd party YouTube apps on the various mobile app stores, one by one slowly getting shutdown to force everyone to use the native apps and clients, with much more reduced functionality and rife with petty design (UX and software) decisions.

YouTube really, really needs a competitor.

@jzisser9
Copy link

jzisser9 commented May 3, 2022

@othyn seriously, it beggars belief that such a simple function takes this much work to accomplish, with strings attached. For each video on this specific playlist, remove it.

@othyn
Copy link

othyn commented May 3, 2022

👍

@awelch83
Copy link

awelch83 commented May 3, 2022

@AwareWulf
Copy link

AwareWulf commented May 12, 2022

For anyone from Czech Republic, you can use this modified function from a few comments above.

setInterval(() => {
  document.querySelector('#primary button[aria-label="Nabídka akcí"]').click();
  document.evaluate('//span[contains(text(),"Odstranit ze seznamu")]', document, null, 
   XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0).click();
}, 500);

@ibakirov
Copy link

ibakirov commented May 22, 2022

@AwareWulf Thanks for sharing 👍

@Arcadi-fr
Copy link

Arcadi-fr commented Jun 2, 2022

For all the french here, use this :
setInterval(function () { document.querySelector('#primary button[aria-label="Menu d\'actions"]').click(); var things = document.evaluate( '//span[contains(text(),"Supprimer de")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < things.snapshotLength; i++) { things.snapshotItem(i).click(); } }, 1000);

Merci beaucoup @DewasSquid ! Fonctionne au 02 juin 2022

@georgedonnelly
Copy link

georgedonnelly commented Jun 11, 2022

This works great, thank you.

@M123-dev
Copy link

M123-dev commented Jun 28, 2022

For everyone using a different language you have to update:

1: aria-label="HERE"

and

2: '//span[contains(text(),"HERE")]',


The second one is just the content of the "Remove from playlist button", press on the 3 dots and copy the text. Just some words is okay, e.g "Remove from" is totally fine.


Number 1 is a bit more tricky, to find it you have to inspect the 3 dots button (right click => inspect or something simillar)
It looks like this:
(Make sure to inspect the button not the icon, just inspect a bit on the side from the three dots.)

<button id="button" class="style-scope yt-icon-button" aria-label="Aktionsmenü"><yt-icon class="style-scope ytd-menu-renderer"</button>

From there you have to use the content of the aria-label

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