A little script to clean up old Claude chats
As I’m using Claude quite often, I’m frequently accumulating a history of Claude chats. And although I tend to keep matters of the heart to myself, I’m just not comfortable with any service indefinitely storing stuff about me. Especially since with a history of chats, even if they’re mostly discussing technical topics, you can likely paint a pretty accurate picture of a person’s personal and professional life.
If you’re like me, where you are using Claude, but don’t want it to remember everything about you forever, here’s a nice script for you (that Claude wrote for me, actually 🙂).
You can copy it, paste it in the developer console when you’re on claude.ai , and it’ll automatically remove all chats older than the specified range for you. The calls are quite slow so it can take a while.
Note: never just copy and paste stuff from the internet into your browser’s console. This is actually called a “ClickFix attack” and quite common. Before you run any script, make sure to actually understand what it does.
You can find the latest version of the script on GitHub (feel free to help improve it!): https://github.com/rubengommers/ai-chats-cleanup/blob/main/claude.js
async function cleanupOldChats(maxAgeDays = 14, dryRun = false) {
const BATCH_SIZE = 30;
const BATCH_DELAY_MS = 500;
// Step 1: Get org ID
let orgId;
try {
const orgResp = await fetch("https://claude.ai/api/organizations", {
credentials: "include",
});
if (!orgResp.ok) throw new Error(`Failed to fetch orgs: ${orgResp.status}`);
const orgs = await orgResp.json();
orgId = orgs[0]?.uuid;
if (!orgId) throw new Error("No organization found");
} catch (e) {
console.error("❌ Could not determine org ID. Are you logged into claude.ai?", e);
return;
}
// Step 2: Fetch all conversations
let conversations;
try {
const convResp = await fetch(
`https://claude.ai/api/organizations/${orgId}/chat_conversations`,
{ credentials: "include" }
);
if (!convResp.ok) throw new Error(`Failed to fetch conversations: ${convResp.status}`);
conversations = await convResp.json();
} catch (e) {
console.error("❌ Could not fetch conversations.", e);
return;
}
if (!Array.isArray(conversations) || conversations.length === 0) {
console.log("✅ No conversations found.");
return;
}
// Step 3: Filter by age
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - maxAgeDays);
const oldChats = conversations.filter((c) => {
const lastActivity = new Date(c.updated_at || c.created_at);
return lastActivity < cutoffDate;
});
console.log(
`📊 Found ${conversations.length} total conversations, ${oldChats.length} older than ${maxAgeDays} days (cutoff: ${cutoffDate.toISOString().slice(0, 10)})`
);
if (oldChats.length === 0) {
console.log("✅ Nothing to delete.");
return;
}
// Show preview of what will be deleted
console.table(
oldChats.map((c) => ({
name: (c.name || "Untitled").slice(0, 60),
updated: (c.updated_at || c.created_at || "").slice(0, 10),
}))
);
if (dryRun) {
console.log(`🔍 Dry run complete. ${oldChats.length} chats would be deleted.`);
return;
}
// Step 4: Confirm
const proceed = confirm(
`⚠️ This will permanently delete ${oldChats.length} conversations older than ${maxAgeDays} days.\n\nContinue?`
);
if (!proceed) {
console.log("Aborted.");
return;
}
// Step 5: Batch delete
const uuids = oldChats.map((c) => c.uuid);
let deletedCount = 0;
let failedCount = 0;
for (let i = 0; i < uuids.length; i += BATCH_SIZE) {
const batch = uuids.slice(i, i + BATCH_SIZE);
const batchNum = Math.floor(i / BATCH_SIZE) + 1;
const totalBatches = Math.ceil(uuids.length / BATCH_SIZE);
try {
const resp = await fetch(
`https://claude.ai/api/organizations/${orgId}/chat_conversations/delete_many`,
{
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ conversation_uuids: batch }),
}
);
if (resp.ok) {
deletedCount += batch.length;
console.log(
`🗑️ Batch ${batchNum}/${totalBatches}: deleted ${batch.length} chats (${deletedCount}/${uuids.length} total)`
);
} else {
// Fallback: delete one by one
console.warn(
`⚠️ Batch ${batchNum} failed (${resp.status}), falling back to individual deletes...`
);
for (const uuid of batch) {
try {
const r = await fetch(
`https://claude.ai/api/organizations/${orgId}/chat_conversations/${uuid}`,
{ method: "DELETE", credentials: "include" }
);
if (r.ok) {
deletedCount++;
} else {
failedCount++;
}
} catch {
failedCount++;
}
// Small delay between individual deletes
await new Promise((r) => setTimeout(r, 300));
}
console.log(` ↳ Individual fallback done. Running total: ${deletedCount} deleted, ${failedCount} failed`);
}
} catch (e) {
failedCount += batch.length;
console.error(`❌ Batch ${batchNum} error:`, e);
}
// Rate limit between batches
if (i + BATCH_SIZE < uuids.length) {
await new Promise((r) => setTimeout(r, BATCH_DELAY_MS));
}
}
console.log(`\n✅ Done! Deleted: ${deletedCount}, Failed: ${failedCount}`);
if (deletedCount > 0) {
console.log("💡 Refresh the page to see the updated sidebar.");
}
}
cleanupOldChats(14);