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.0.1
// @description Bulk delete selected ChatGPT chats by using the normal UI menu
// @author GamerDesigns
// @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 ROW_ATTR = 'data-gd-bulk-row';
let selectMode = false;
let busy = false;
function sleep(ms) {
return 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:#0f172a;color:#fff;border:1px solid rgba(255,255,255,.12);border-radius:16px;padding:14px;box-shadow:0 10px 30px rgba(0,0,0,.35);width:290px;font-family:Arial,sans-serif}
#${PANEL_ID} .title{font-size:18px;font-weight:700;margin:0 0 12px}
#${PANEL_ID} .row{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:10px}
#${PANEL_ID} button{background:#334155;color:#fff;border:1px solid rgba(255,255,255,.15);border-radius:12px;padding:10px 14px;font-size:14px;cursor:pointer}
#${PANEL_ID} button:hover{background:#475569}
#${PANEL_ID} .danger{background:#991b1b}
#${PANEL_ID} .danger:hover{background:#b91c1c}
#${PANEL_ID} .count{font-size:14px;font-weight:700;color:#93c5fd}
#${PANEL_ID} .status{font-size:14px;opacity:.9;line-height:1.35}
.${CHECKBOX_CLASS}{width:16px;height:16px;min-width:16px;accent-color:#3b82f6;cursor:pointer}
.gd-bulk-ui-wrap{display:none;align-items:center;justify-content:center;margin-right:8px}
body.gd-bulk-ui-select .gd-bulk-ui-wrap{display:flex}
body.gd-bulk-ui-select [${ROW_ATTR}="1"]{outline:1px solid rgba(59,130,246,.22);outline-offset:2px;border-radius:10px}
`;
document.head.appendChild(style);
}
function createPanel() {
if (document.getElementById(PANEL_ID)) return;
const panel = document.createElement('div');
panel.id = PANEL_ID;
panel.innerHTML = `
Bulk Delete UI
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-ui-select', selectMode);
panel.querySelector('#gd-toggle').textContent = selectMode ? 'Exit Select' : 'Select Mode';
});
panel.querySelector('#gd-all').addEventListener('click', selectAllVisible);
panel.querySelector('#gd-clear').addEventListener('click', clearSelection);
panel.querySelector('#gd-delete').addEventListener('click', deleteSelected);
document.addEventListener('change', (e) => {
if (e.target && e.target.classList.contains(CHECKBOX_CLASS)) updateCount();
});
}
function setStatus(text) {
const el = document.getElementById('gd-status');
if (el) el.textContent = text;
}
function updateCount() {
const count = document.querySelectorAll(`.${CHECKBOX_CLASS}:checked`).length;
const el = document.getElementById('gd-count');
if (el) el.textContent = `${count} selected`;
}
function getConversationId(href) {
const m = href && href.match(/\/c\/([a-zA-Z0-9-]+)/);
return m ? m[1] : null;
}
function getCandidateLinks() {
return Array.from(document.querySelectorAll('a[href*="/c/"]'));
}
function getRow(anchor) {
let node = anchor;
for (let i = 0; i < 8 && node; i++) {
if (node.parentElement && node.parentElement.querySelector('a[href*="/c/"]')) return node.parentElement;
node = node.parentElement;
}
return anchor.parentElement;
}
function scanChats() {
const links = getCandidateLinks();
let added = 0;
for (const link of links) {
const href = link.getAttribute('href') || '';
const id = getConversationId(href);
if (!id) continue;
const row = getRow(link);
if (!row) continue;
row.setAttribute(ROW_ATTR, '1');
row.dataset.gdConversationId = id;
if (row.querySelector(`.${CHECKBOX_CLASS}`)) continue;
const wrap = document.createElement('div');
wrap.className = 'gd-bulk-ui-wrap';
const cb = document.createElement('input');
cb.type = 'checkbox';
cb.className = CHECKBOX_CLASS;
cb.dataset.conversationId = id;
wrap.appendChild(cb);
row.insertBefore(wrap, row.firstChild);
added++;
}
setStatus(`Scan complete. Added ${added} checkbox(es).`);
updateCount();
}
function selectAllVisible() {
document.querySelectorAll(`.${CHECKBOX_CLASS}`).forEach(cb => cb.checked = true);
updateCount();
}
function clearSelection() {
document.querySelectorAll(`.${CHECKBOX_CLASS}`).forEach(cb => cb.checked = false);
updateCount();
}
function getSelectedIds() {
return Array.from(document.querySelectorAll(`.${CHECKBOX_CLASS}:checked`))
.map(cb => cb.dataset.conversationId)
.filter(Boolean);
}
function getSelectedRows() {
const ids = getSelectedIds();
return ids.map(id => document.querySelector(`[data-gd-conversation-id="${CSS.escape(id)}"]`)).filter(Boolean);
}
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 findMenuButton(row) {
if (!row) return null;
const buttons = Array.from(row.querySelectorAll('button'));
for (const btn of buttons) {
const label = `${btn.getAttribute('aria-label') || ''} ${btn.getAttribute('title') || ''} ${btn.textContent || ''}`.toLowerCase();
if (label.includes('more') || label.includes('menu') || label.includes('options')) return btn;
}
const svgButtons = buttons.filter(isVisible);
if (svgButtons.length) return svgButtons[svgButtons.length - 1];
return null;
}
function findDeleteMenuItem() {
const candidates = Array.from(document.querySelectorAll('button, div[role="menuitem"], [role="menuitem"]'));
for (const el of candidates) {
const text = (el.textContent || '').trim().toLowerCase();
if (text === 'delete' || text.includes('delete chat') || text.includes('delete')) {
if (isVisible(el)) return el;
}
}
return null;
}
function findConfirmDeleteButton() {
const candidates = Array.from(document.querySelectorAll('button'));
for (const btn of candidates) {
const text = (btn.textContent || '').trim().toLowerCase();
if ((text === 'delete' || text === 'delete chat' || text.includes('delete')) && isVisible(btn)) {
return btn;
}
}
return null;
}
async function openRowMenu(row) {
row.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
await sleep(250);
let btn = findMenuButton(row);
if (!btn) {
row.click();
await sleep(250);
btn = findMenuButton(row);
}
if (!btn) throw new Error('Menu button not found');
btn.click();
await sleep(350);
}
async function clickDeleteInMenu() {
const item = findDeleteMenuItem();
if (!item) throw new Error('Delete menu item not found');
item.click();
await sleep(400);
}
async function confirmDelete() {
const btn = findConfirmDeleteButton();
if (!btn) throw new Error('Confirm delete button not found');
btn.click();
await sleep(900);
}
async function deleteRowViaUI(row) {
await openRowMenu(row);
await clickDeleteInMenu();
await confirmDelete();
}
async function deleteSelected() {
if (busy) return;
const rows = getSelectedRows();
if (!rows.length) {
alert('No chats selected.');
return;
}
if (!confirm(`Delete ${rows.length} selected chat(s)? This cannot be undone.`)) return;
busy = true;
let ok = 0;
let fail = 0;
setStatus(`Deleting ${rows.length} chat(s)...`);
for (const row of rows) {
try {
row.scrollIntoView({ behavior: 'auto', block: 'center' });
await sleep(350);
await deleteRowViaUI(row);
row.remove();
ok++;
setStatus(`Deleted ${ok}/${rows.length}`);
} catch (err) {
console.error('Delete failed:', err);
fail++;
setStatus(`Deleted ${ok}/${rows.length}, failed ${fail}`);
}
await sleep(500);
}
busy = false;
updateCount();
setStatus(`Done. Deleted ${ok}, failed ${fail}.`);
}
function init() {
injectStyles();
createPanel();
setStatus('Ready. Open chat history, click Scan Chats, then Select Mode.');
}
init();
})();