Remove all your X (Twitter) bookmarks

Clear your saved posts on X in one go, or only the latest ones. Export them first if you might want them later.

remove-bookmarks.js · 101 linespaste in the DevTools console on x.com
// Responsive Muse · Remove All Bookmarks on X (Twitter) · v1.1 · 2026-10-22
// Removes your bookmarks, newest first: all of them, or only the latest LIMIT. Runs only on
// x.com/i/history (bookmarks). It asks before changing anything, then clicks the same bookmark
// button you would. It makes no network requests of its own and never reads cookies,
// passwords or tokens.
(async () => {
  const TOOL = 'Remove all bookmarks';
  const LIMIT = 0;        // only the latest this many posts (0 = all)
  const DELAY = 1200;     // pause between removals, in milliseconds

  if (!/^(x|twitter)\.com$/.test(location.hostname) || !/^\/i\/(history|bookmarks)\/?$/.test(location.pathname)) {
    alert('Open your bookmarks first (signed in):\nhttps://x.com/i/bookmarks');
    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));
  const idOf = art => ((art.querySelector('a[href*="/status/"] time')?.closest('a')?.getAttribute('href') || '')
    .match(/\/status\/(\d+)/) || [])[1];
  const done = new Set();   // X keeps removed posts on screen, so remember which ones are handled

  // 1. Ask (X loads bookmarks as you scroll, so the total isn't known in advance)
  const scope = LIMIT ? `your latest ${LIMIT} bookmarks` : 'all your bookmarks';
  if (!await panel.ask(`Remove ${scope}?\nThis can't be undone. Export them first if you might want them later.`, LIMIT ? `Remove ${LIMIT}` : 'Remove all')) {
    panel.finish('Cancelled. Nothing was changed.');
    return 0;
  }

  // 2. Remove one by one, scrolling to load more
  let stop = false;
  panel.stoppable(() => { stop = true; });
  window.scrollTo(0, 0);
  await sleep(DELAY);
  let count = 0, idle = 0;
  while (!stop && idle < 4 && !(LIMIT && count >= LIMIT)) {
    const art = [...document.querySelectorAll('article[data-testid="tweet"]')]
      .find(a => a.querySelector('button[data-testid="removeBookmark"]') && !done.has(idOf(a)));
    if (!art) {
      window.scrollBy(0, window.innerHeight * 0.8);
      await sleep(DELAY);
      idle++;
      continue;
    }
    idle = 0;
    done.add(idOf(art));
    art.scrollIntoView({ block: 'center' });
    art.querySelector('button[data-testid="removeBookmark"]').click();
    count++;
    panel.text(`Removing… ${count}${LIMIT ? ` of ${LIMIT}` : ''}`);
    await sleep(DELAY);
  }
  if (!count && !stop) {
    panel.finish('You have no bookmarks to remove.');
    return 0;
  }
  panel.finish(`${stop ? 'Stopped' : 'Done'}: removed ${many(count, 'bookmark')}.\nReload the page to see the result.`);
  return count;
})();

Bookmarklet: drag the middle button to your bookmarks bar, open x.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 x.com itself loading your list.
  • Never touches your login. It doesn't read cookies, passwords, tokens or browser storage.
  • Only runs on x.com. Anywhere else it stops before doing anything.
  • Short and readable. 101 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: fa64c6dfa8321de8…
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 x.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 x.com/i/bookmarks 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, paste it in the console and press Enter. A small box appears on the page: click Remove all to confirm, or Cancel. Keep the tab open until it says “Done”.

Before you clear them

Removed bookmarks can’t be restored in bulk. If you want a copy, use the bookmarks exporter first: it saves them to CSV or Markdown in a few seconds.

FAQ

Isn't there a "clear all" option on X?

Not on the new Saved page. Bookmarks have to be removed one by one, which is what this script does for you.

Should I export them first?

Yes, if you might want them later: use the bookmarks exporter, then clear.

More free tools

Clean up

Export & back up