Clear YouTube Watch Later in one click

YouTube makes you remove Watch Later videos one by one. This free script removes all of them, or only the ones you’ve watched, right in your browser. No extension, no sign-up.

clear-watch-later.js · 134 linespaste in the DevTools console on www.youtube.com
// Responsive Muse · Clear YouTube Watch Later · v1.1 · 2026-10-22
// Removes videos from your Watch Later list: all of them, or only the ones you've watched.
// Runs only on youtube.com/playlist?list=WL. It counts first and asks before removing anything,
// then clicks the same "Remove from Watch later" menu you would. It makes no network requests
// of its own and never reads cookies, passwords or tokens.
(async () => {
  const TOOL = 'Clear Watch Later';
  const MODE = 'all';     // 'all' or 'watched' (videos you've watched at least 90%)
  const LIMIT = 0;        // stop after this many videos (0 = no limit)
  const DELAY = 600;      // pause between actions, in milliseconds

  if (location.hostname !== 'www.youtube.com' || new URLSearchParams(location.search).get('list') !== 'WL') {
    alert('Open your Watch Later list first (signed in):\nhttps://www.youtube.com/playlist?list=WL');
    return;
  }
  // A small box on the page shows progress and asks before changing anything,
  // so you never need to read or edit the console.
  const many = (n, word) => `${n} ${word}${n === 1 ? '' : 's'}`;   // 1 video, 2 videos
  const panel = (() => {
    const box = document.createElement('div');
    box.style.cssText = 'position:fixed;right:16px;bottom:16px;z-index:2147483647;width:340px;max-width:calc(100vw - 32px);' +
      'background:#111318;color:#e6e8ee;font:14px/1.5 system-ui,sans-serif;border-radius:12px;padding:16px;' +
      'box-shadow:0 8px 30px rgba(0,0,0,.4);text-align:left';
    const head = document.createElement('strong');
    head.textContent = TOOL;
    const msg = document.createElement('p');
    msg.style.cssText = 'margin:8px 0 12px;white-space:pre-line';
    const row = document.createElement('div');
    row.style.cssText = 'display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end';
    box.append(head, msg, row);
    document.body.append(box);
    const button = (label, primary, onClick) => {
      const b = document.createElement('button');
      b.textContent = label;
      b.style.cssText = 'font:600 14px system-ui,sans-serif;padding:8px 14px;border-radius:8px;cursor:pointer;' +
        (primary ? 'background:#0f766e;color:#fff;border:1px solid #0f766e' : 'background:none;color:#e6e8ee;border:1px solid #3a3f4b');
      b.onclick = onClick;
      row.append(b);
    };
    return {
      text(t) { msg.textContent = t; },
      ask(t, yes) {
        msg.textContent = t;
        row.replaceChildren();
        return new Promise(r => {
          button('Cancel', false, () => { row.replaceChildren(); r(false); });
          button(yes, true, () => { row.replaceChildren(); r(true); });
        });
      },
      stoppable(onStop) { row.replaceChildren(); button('Stop', false, onStop); },
      actions(t, list) {
        msg.textContent = t;
        row.replaceChildren();
        list.forEach(([label, primary, run]) => button(label, primary, run));
      },
      finish(t) { this.actions(t, [['Close', true, () => box.remove()]]); },
      close() { box.remove(); },
    };
  })();
  const sleep = ms => new Promise(r => setTimeout(r, ms));
  // Wait until something shows up on screen (menus can take a moment to open)
  const visible = e => e.getClientRects().length > 0;
  const waitFor = async (find, ms = 4000) => {
    for (let t = 0; t < ms; t += 150) {
      const hit = find();
      if (hit) return hit;
      await sleep(150);
    }
    return null;
  };
  // "Remove from Watch later" in English, Spanish, Portuguese, French, German and Italian
  const REMOVE = /remove from watch later|quitar de ver más tarde|remover de assistir mais tarde|retirer de .*à regarder plus tard|aus .*später ansehen.* entfernen|rimuovi da guarda più tardi/i;
  const rows = () => [...document.querySelectorAll('ytd-playlist-video-renderer, yt-lockup-view-model')]
    .filter(el => el.querySelector('a[href*="/watch?v="][href*="index="]'));
  const watched = el => {
    const bar = [...el.querySelectorAll('#progress, [class*="ResumePlayback"], [class*="rogress"]')].find(b => b.style.width);
    return bar ? parseFloat(bar.style.width) >= 90 : false;
  };
  const targets = () => rows().filter(el => MODE === 'all' || watched(el));

  // 1. Load the whole list
  let last = -1, idle = 0;
  while (idle < 3) {
    window.scrollTo(0, document.documentElement.scrollHeight);
    await sleep(1200);
    const n = rows().length;
    idle = n === last ? idle + 1 : 0;
    last = n;
    panel.text(`Loading your Watch Later list… ${n} videos`);
  }
  const total = LIMIT ? Math.min(LIMIT, targets().length) : targets().length;
  if (!total) {
    panel.finish(MODE === 'watched' ? 'There are no watched videos to remove.' : 'Your Watch Later list is empty.');
    return 0;
  }

  // 2. Ask
  const what = MODE === 'watched' ? 'watched videos' : 'videos';
  if (!await panel.ask(`Remove ${total} ${what.replace(/s$/, total === 1 ? '' : 's')} from Watch Later?\nThis can't be undone.`, `Remove ${total}`)) {
    panel.finish('Cancelled. Nothing was changed.');
    return 0;
  }

  // 3. Remove them one by one. YouTube's new layout keeps removed rows on screen,
  //    so remember which videos are done.
  let stop = false;
  panel.stoppable(() => { stop = true; });
  const videoId = el => new URL(el.querySelector('a[href*="/watch?v="]').href).searchParams.get('v');
  const done = new Set();
  let removed = 0;
  while (!stop && removed < total) {
    const el = targets().find(r => !done.has(videoId(r)));
    if (!el) break;
    done.add(videoId(el));
    el.scrollIntoView({ block: 'center' });
    el.querySelector('button[aria-label="Action menu"], button[aria-label="More actions"]').click();
    const item = await waitFor(() => [...document.querySelectorAll('ytd-menu-service-item-renderer, yt-list-item-view-model')]
      .find(i => visible(i) && REMOVE.test(i.textContent)));
    if (!item) {
      panel.finish(`Removed ${removed}, then could not find "Remove from Watch later" in the menu.\nSwitch YouTube to English and try again.`);
      return removed;
    }
    item.click();
    // Wait for the menu to close, so the next video doesn't reuse this menu
    await waitFor(() => ![...document.querySelectorAll('ytd-menu-service-item-renderer, yt-list-item-view-model')]
      .some(i => visible(i) && REMOVE.test(i.textContent)) || null);
    removed++;
    panel.text(`Removing… ${removed} of ${total}`);
    await sleep(DELAY);
  }
  panel.finish(`${stop ? 'Stopped' : 'Done'}: removed ${removed} of ${many(total, 'video')}.\nReload the page to see the result.`);
  return removed;
})();

Bookmarklet: drag the middle button to your bookmarks bar, open www.youtube.com and click the bookmark. It runs the same script with the options above.

Why it's safe to runAutomated check passed Oct 22, 2026 · tested on a real account Oct 22, 2026
  • Sends nothing anywhere. No fetch, XHR or external scripts. The only network activity is www.youtube.com itself loading your list.
  • Never touches your login. It doesn't read cookies, passwords, tokens or browser storage.
  • Only runs on www.youtube.com. Anywhere else it stops before doing anything.
  • Short and readable. 134 commented lines, not minified or obfuscated.
  • Asks before it changes anything. A box on the page shows what it found and waits for your OK. You can stop it at any time.
  • Same code for everyone. SHA-256 of the default version: 5937c19705a7b473…
Verify it yourself in 30 seconds
  1. Read it: every line is above, with comments.
  2. Search the code for fetch, XMLHttpRequest, cookie, localStorage or eval. None of them appear.
  3. Open the Network tab before running it: you'll only see requests to www.youtube.com.

Good to know: this can't be undone in bulk. The script always shows the count and asks before it starts. Leave the tab open until the box says "Done".

Did it work for you?

How to use it

  1. Open youtube.com/playlist?list=WL while signed in.
  2. Open the console: F12 or Ctrl+Shift+J (Cmd+Option+J on Mac). If Chrome asks, type allow pasting and press Enter.
  3. Copy the script above, paste it in the console and press Enter. A small box shows how many videos it found: click Remove to confirm, or Cancel.
  4. Keep the tab open until the box says “Done”. You can stop it at any time.

Why is there no “clear all” button?

Watch Later is a private system playlist. YouTube’s menu only offers “Remove watched videos”, and online playlist tools can’t see the list at all because it’s private. The script works because it runs in your own signed-in tab and clicks the same “Remove from Watch later” menu you would, at a human pace.

Want a copy first? Export your Watch Later list to CSV before you clear it.

FAQ

Is there a "clear all" button on YouTube?

No. YouTube only offers "Remove watched videos" in the Watch Later menu. To remove everything you have to delete videos one by one, which is what this script does for you.

Can I undo it?

No. Removed videos can't be restored in bulk. Export your Watch Later list first if you might want it back.

Does it work on the YouTube app?

No. It needs a desktop browser: Chrome, Edge, Firefox, Brave or Safari.

More YouTube tools