1
Use Google Chrome
This script works best in Google Chrome. If you do not already have Chrome installed, download it first.
Download Google ChromeA lightweight browser script by GamerDesigns that lets you select and delete multiple chats at once.
Follow these steps in order. This was written to be as easy as possible, even if you have never used a browser script before.
You need Google Chrome, the Tampermonkey extension, and a normal ChatGPT account logged in through the website.
This script works best in Google Chrome. If you do not already have Chrome installed, download it first.
Download Google ChromeOpen the Chrome Web Store page below, then click Add to Chrome.
Install TampermonkeyPress CTRL + S on your keyboard, or click File → Save.
// ==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();
})();