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 22.11.2022

It's been two years since the last update, so here's the updated working script as per the comments below.

Thanks to BryanHaley for this.

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.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();
    }
}, 500);

Non-english users will need to change "Action menu" and "Remove from" to what YouTube uses for their localization.

@mimi1597
Copy link

mimi1597 commented Nov 9, 2022

this code worked....:)

@Alpakash
Copy link

Alpakash commented Nov 19, 2022

Thanks worked like a charm! Had to translate the aria-label and text for dutch:

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

@BryanHaley
Copy link

BryanHaley commented Nov 21, 2022

Here's my take on this

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.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();
    }
}, 500);

Working as of 11/21/2022. Just let it run in the background. Non-english users will need to change "Action menu" and "Remove from" to what YouTube uses for their localization.

@jumiller-cotiviti
Copy link

jumiller-cotiviti commented Nov 30, 2022

If you need it to clear hidden videos this is the tweak to do that (I had like 200) - click options menu and show hidden videos then run this

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#button > yt-icon').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();
    }
}, 500);

@kangdaeki
Copy link

This is a lifesaver for me. Thanks.

@drementer
Copy link

drementer commented Jan 12, 2023

Türkler için

setInterval(() => {
  document.querySelector('#primary button[aria-label="İşlem menüsü"]').click();
  document
    .evaluate(
      '//span[contains(text(),"Daha sonra")]',
      document,
      null,
      XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
      null
    )
    .snapshotItem(0)
    .click();
}, 100);

Hızlandırılmış hali

setInterval(() => {
  document.querySelector('#primary button[aria-label="İşlem menüsü"]').click();
  document
    .evaluate(
      '//span[contains(text(),"Daha sonra")]',
      document,
      null,
      XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
      null
    )
    .snapshotItem(0)
    .click();
}, 50);

@MShrimp4
Copy link

Korean version, if someone needs it
한국어 환경에서 유튜브 나중에 볼 동영상 전부 지우기

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#primary button[aria-label="작업 메뉴"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"에서 삭제")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 500);

@LisichkinVlad
Copy link

LisichkinVlad commented Feb 12, 2023

Russian version

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#primary button[aria-label="Меню действий"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"Удалить из плейлиста")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++)
    {
        things.snapshotItem(i).click();
    }
}, 500);

@niklas-a
Copy link

Swedish version:


setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#primary button[aria-label="Åtgärdsmeny"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"Ta bort från")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 500);

@colejd
Copy link

colejd commented Mar 2, 2023

YouTube appears to rate limit you after 200ish deletions in a short time - so while the deletions appear to work on the UI side, the videos aren't actually removed from the playlist. Absolutely infuriating.

Here's a modified version of the script that deletes 200 at a time, waiting 5 minutes between each batch to avoid doing any deletions that, uh, don't actually delete. With a 5000-video playlist, this should take 167ish minutes to run. Just put it on overnight or something.

function deleteVideoFromWatchLater() {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];
    video.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();
    }
}

async function deleteWatchLater() {
  // Fiddle with these if you'd like
  let batchSize = 200; // Number to delete at once before waiting
  let waitBetweenBatchesInMilliseconds = 1000 * 60 * 5; // 5 minutes
  let waitBetweenDeletionsInMilliseconds = 500; // Half a second

  let totalWaitTime = ((5000 / batchSize) * (waitBetweenBatchesInMilliseconds / 1000 / 60)) + (5000 * (waitBetweenDeletionsInMilliseconds / 1000 / 60))
  console.log(`Deletion will take around ${totalWaitTime.toFixed(0)} minutes to run if the playlist is full.`);

  let count = 0;
  while (true) {
    await new Promise(resolve => setTimeout(resolve, waitBetweenDeletionsInMilliseconds));
    deleteVideoFromWatchLater();
    count++;

    if (count % batchSize === 0 && count !== 0) {
      console.log('Waiting for 5 minutes...');
      await new Promise(resolve => setTimeout(waitBetweenBatchesInMilliseconds));
    }
  }
}

deleteWatchLater();

The batch sizes and wait times are guesses, but they worked for me. You may need to run this more than once if any rate limiting happens - just reload the page and run the script again.

@papiforcex
Copy link

papiforcex commented Mar 25, 2023

There's the french version:

To launch it:

const watchLaterCleaner = setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.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();
    }
}, 500);

To stop it (if you want to):

clearInterval(watchLaterCleaner);

@nataliepjlin
Copy link

works well! thanks a lot

@drkbzx
Copy link

drkbzx commented Apr 12, 2023

It works like a charm! TIP: Disable display images on your browser settings, it runs smoother!

@HaBiX02
Copy link

HaBiX02 commented Apr 23, 2023

For Spanish from Spain users the code is:

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#primary button[aria-label="Menú de acciones"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"Quitar de")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 500);

It is awesome to finally see my list in a manageable size, thank you!

@PETROUNKNOWN
Copy link

Nice

@Adham380
Copy link

Adham380 commented May 5, 2023

I made a version that allows one to remove only watched videos or all.
Simply change the <= 10 with your preferred progress bar (how much of the video you watched) threshold.

var counter = 0;
setInterval(function () {
    let video = document.getElementsByTagName('ytd-playlist-video-renderer')[counter];
    let progress = "0";
    console.log(video.querySelector('#video-title').innerText)
    if(video.querySelector('#progress') !== null && video.querySelector('#progress') !== undefined){
    progress = video.querySelector('#progress').style.getPropertyValue("width")
    console.log(progress)
    } else {
    console.log("not deleted");
    counter++;
    return;
    }
    video.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
    );

if(parseInt(progress.substring(0, progress.length -1)) >= 50){
    console.log("deleted")
    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
    } else {
    console.log("not deleted")
    counter++;
    }
}, 800);



@AndersMoberg
Copy link

This thread was a good reference when I need similar functionality (many thanks!), so I implemented it into a web extension. But my code was a little bare, and private extensions doesn't seem to be a thing, so just recently I converted it into a Userscript.

https://gist.github.com/AndersMoberg/0a9f996a49d7b3a9e9c01065ce29abf4

If you have a Userscript manager, press the Raw button and you should get the dialogue for installing it.
It only works with Swedish interface for now, but feel free to request your language if you'd like I can put it in.

Again, many thanks for this Gist and comment section

@deleonjenmar0
Copy link

Still works, thanks!

@fwookerton
Copy link

It's giving off a "Uncaught TypeError: video.querySelector(...) is null" error and not actually doing anything.

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