ChatGPT Bulk Delete Script

A lightweight browser script by GamerDesigns that lets you select and delete multiple chats at once.

Install Guide

How to install this script

Follow these steps in order. This was written to be as easy as possible, even if you have never used a browser script before.

Before you start

You need Google Chrome, the Tampermonkey extension, and a normal ChatGPT account logged in through the website.

1

Use Google Chrome

This script works best in Google Chrome. If you do not already have Chrome installed, download it first.

Download Google Chrome
2

Install Tampermonkey

Open the Chrome Web Store page below, then click Add to Chrome.

Install Tampermonkey
3

Create a new script

  • Click the Tampermonkey icon in the top right of Chrome
  • Click Create a new script
4

Paste the script

  • Delete everything in the editor
  • Click Copy Script on this page
  • Paste it into Tampermonkey
5

Save the script

Press CTRL + S on your keyboard, or click File → Save.

6

Open ChatGPT

Once the script is saved, open ChatGPT in your browser.

Open ChatGPT
7

Use the tool

Click Scan Chats Click Select Mode Pick the chats you want Click Delete Selected
Important: Test the script on 1 or 2 chats first before trying to delete a bigger batch.
ChatGPT Bulk Delete Script Author: GamerDesigns
// ==UserScript==
// @name         ChatGPT Bulk Delete UI Click
// @namespace    gamerdesigns.chatgpt.bulkdelete.uiclick
// @version      1.2.0
// @description  Bulk delete selected ChatGPT chats by using the normal ChatGPT UI
// @match        https://chatgpt.com/*
// @match        https://chat.openai.com/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function () {
  'use strict';

  const PANEL_ID = 'gd-bulk-ui-panel';
  const STYLE_ID = 'gd-bulk-ui-style';
  const CHECKBOX_CLASS = 'gd-bulk-ui-checkbox';
  const LINK_ATTR = 'data-gd-chat-link';

  let selectMode = false;
  let busy = false;
  let stopRequested = false;

  const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

  function injectStyles() {
    if (document.getElementById(STYLE_ID)) return;

    const style = document.createElement('style');
    style.id = STYLE_ID;
    style.textContent = `
      #${PANEL_ID}{position:fixed;right:16px;bottom:16px;z-index:999999;background:#111827;color:#fff;border:1px solid rgba(255,255,255,.14);border-radius:16px;padding:14px;box-shadow:0 12px 35px rgba(0,0,0,.4);width:300px;font-family:Arial,sans-serif}
      #${PANEL_ID} .title{font-size:17px;font-weight:800;margin:0 0 10px}
      #${PANEL_ID} .row{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:9px}
      #${PANEL_ID} button{background:#374151;color:#fff;border:1px solid rgba(255,255,255,.16);border-radius:10px;padding:9px 11px;font-size:13px;cursor:pointer}
      #${PANEL_ID} button:hover{background:#4b5563}
      #${PANEL_ID} .danger{background:#991b1b}
      #${PANEL_ID} .danger:hover{background:#b91c1c}
      #${PANEL_ID} .stop{background:#7c2d12}
      #${PANEL_ID} .count{font-size:14px;font-weight:700;color:#93c5fd}
      #${PANEL_ID} .status{font-size:13px;opacity:.9;line-height:1.35}
      .gd-bulk-box-wrap{display:none!important;align-items:center;margin-right:8px;flex:0 0 auto}
      body.gd-bulk-select .gd-bulk-box-wrap{display:inline-flex!important}
      .${CHECKBOX_CLASS}{width:17px;height:17px;accent-color:#3b82f6;cursor:pointer}
      body.gd-bulk-select a[${LINK_ATTR}="1"]{outline:1px solid rgba(59,130,246,.35);outline-offset:2px;border-radius:8px}
    `;
    document.head.appendChild(style);
  }

  function createPanel() {
    if (document.getElementById(PANEL_ID)) return;

    const panel = document.createElement('div');
    panel.id = PANEL_ID;
    panel.innerHTML = `
      
ChatGPT Bulk Delete
0 selected
Ready.
`; document.body.appendChild(panel); panel.querySelector('#gd-scan').addEventListener('click', scanChats); panel.querySelector('#gd-toggle').addEventListener('click', () => { selectMode = !selectMode; document.body.classList.toggle('gd-bulk-select', selectMode); panel.querySelector('#gd-toggle').textContent = selectMode ? 'Exit Select' : 'Select Mode'; scanChats(); }); panel.querySelector('#gd-all').addEventListener('click', selectAllVisible); panel.querySelector('#gd-clear').addEventListener('click', clearSelection); panel.querySelector('#gd-delete').addEventListener('click', deleteSelected); panel.querySelector('#gd-stop').addEventListener('click', () => { stopRequested = true; setStatus('Stopping after current chat...'); }); document.addEventListener('change', e => { if (e.target.classList.contains(CHECKBOX_CLASS)) updateCount(); }); } function setStatus(text) { document.getElementById('gd-status').textContent = text; } function updateCount() { const count = document.querySelectorAll(`.${CHECKBOX_CLASS}:checked`).length; document.getElementById('gd-count').textContent = `${count} selected`; } function getConversationId(href) { const match = href && href.match(/\/c\/([a-zA-Z0-9-]+)/); return match ? match[1] : null; } function getChatLinks() { return Array.from(document.querySelectorAll('a[href*="/c/"]')).filter(a => { const href = a.getAttribute('href') || ''; return getConversationId(href); }); } function scanChats() { const links = getChatLinks(); let added = 0; links.forEach(link => { const id = getConversationId(link.getAttribute('href') || ''); if (!id) return; link.setAttribute(LINK_ATTR, '1'); link.dataset.gdConversationId = id; if (link.querySelector(`.${CHECKBOX_CLASS}`)) return; const wrap = document.createElement('span'); wrap.className = 'gd-bulk-box-wrap'; const cb = document.createElement('input'); cb.type = 'checkbox'; cb.className = CHECKBOX_CLASS; cb.dataset.conversationId = id; cb.addEventListener('click', e => { e.stopPropagation(); }); wrap.appendChild(cb); link.prepend(wrap); added++; }); setStatus(`Scan complete. Added ${added} checkbox(es).`); updateCount(); } function selectAllVisible() { scanChats(); document.querySelectorAll(`.${CHECKBOX_CLASS}`).forEach(cb => cb.checked = true); updateCount(); } function clearSelection() { document.querySelectorAll(`.${CHECKBOX_CLASS}`).forEach(cb => cb.checked = false); updateCount(); } function isVisible(el) { if (!el) return false; const rect = el.getBoundingClientRect(); const style = window.getComputedStyle(el); return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0; } function textOf(el) { return `${el.getAttribute('aria-label') || ''} ${el.getAttribute('title') || ''} ${el.textContent || ''}`.toLowerCase(); } function getSelectedLinks() { return Array.from(document.querySelectorAll(`.${CHECKBOX_CLASS}:checked`)) .map(cb => cb.closest('a[href*="/c/"]')) .filter(Boolean); } async function openChatMenu(link) { link.scrollIntoView({ block: 'center' }); await sleep(400); link.dispatchEvent(new MouseEvent('mouseover', { bubbles: true })); link.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true })); await sleep(500); let parent = link; for (let i = 0; i < 8 && parent; i++) { const buttons = Array.from(parent.querySelectorAll('button')).filter(isVisible); const menuBtn = buttons.find(btn => { const text = textOf(btn); return text.includes('more') || text.includes('options') || text.includes('menu'); }) || buttons[buttons.length - 1]; if (menuBtn) { menuBtn.click(); await sleep(600); return; } parent = parent.parentElement; } throw new Error('Menu button not found'); } function findDeleteMenuItem() { return Array.from(document.querySelectorAll('button, [role="menuitem"], div[role="menuitem"]')) .filter(isVisible) .find(el => { const text = textOf(el).trim(); return text === 'delete' || text.includes('delete chat') || text.includes('delete conversation'); }); } function findConfirmDeleteButton() { const buttons = Array.from(document.querySelectorAll('button')).filter(isVisible); return buttons.reverse().find(btn => { const text = textOf(btn).trim(); return text === 'delete' || text === 'delete chat' || text.includes('delete'); }); } async function deleteOne(link) { await openChatMenu(link); const deleteItem = findDeleteMenuItem(); if (!deleteItem) throw new Error('Delete menu item not found'); deleteItem.click(); await sleep(700); const confirmBtn = findConfirmDeleteButton(); if (!confirmBtn) throw new Error('Confirm delete button not found'); confirmBtn.click(); await sleep(1300); } async function deleteSelected() { if (busy) return; const links = getSelectedLinks(); if (!links.length) { alert('No chats selected.'); return; } if (!confirm(`Delete ${links.length} selected chat(s)? This cannot be undone.`)) return; busy = true; stopRequested = false; let ok = 0; let fail = 0; setStatus(`Deleting ${links.length} chat(s)...`); for (const link of links) { if (stopRequested) break; try { await deleteOne(link); ok++; setStatus(`Deleted ${ok}/${links.length}. Failed ${fail}.`); } catch (err) { console.error(err); fail++; setStatus(`Deleted ${ok}/${links.length}. Failed ${fail}.`); } await sleep(900); } busy = false; scanChats(); updateCount(); setStatus(stopRequested ? `Stopped. Deleted ${ok}, failed ${fail}.` : `Done. Deleted ${ok}, failed ${fail}.`); } function init() { injectStyles(); createPanel(); setStatus('Ready. Click Select Mode first, then Scan Chats.'); } init(); })();