Created
November 13, 2025 14:31
-
-
Save DaniGuardiola/5ff589062b98bacb8c207cc003feb95b to your computer and use it in GitHub Desktop.
Reddit comment deleter/counter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Reddit comment deleter/counter | |
| // run in browser console on old.reddit.com | |
| // -------------- | |
| // configuration - edit these values: | |
| const MODE = "delete"; // "delete" or "count" | |
| const USERNAME = "username"; | |
| const SUBREDDITS = []; // e.g. ['subreddit1', 'subreddit2'] - leave empty for all | |
| // these seem to work well to avoid rate limiting, but can be adjusted if needed | |
| const DELAY_BETWEEN_DELETES_MS = 2000; | |
| const DELAY_BETWEEN_PAGES_MS = 5000; | |
| // -------------- | |
| main(); | |
| let commentsDeleted = 0; | |
| const counts = {}; | |
| async function main() { | |
| console.log(`Starting Reddit comment deleter/counter for user: ${USERNAME}`); | |
| console.log(`Mode: ${MODE}`); | |
| if (SUBREDDITS.length > 0) { | |
| console.log(`Filtering by subreddits: ${SUBREDDITS.join(", ")}`); | |
| } else { | |
| console.log("No subreddit filtering, processing all comments."); | |
| } | |
| await processPage(); | |
| if (MODE === "count") { | |
| console.log("Comment counts by subreddit:"); | |
| for (const [subreddit, count] of Object.entries(counts)) { | |
| console.log(`r/${subreddit}: ${count}`); | |
| } | |
| } | |
| if (MODE === "delete") { | |
| console.log(`Total comments deleted: ${commentsDeleted}`); | |
| } | |
| } | |
| async function processPage(nextUrl) { | |
| console.log( | |
| !nextUrl ? "Processing first page..." : `Processing page: ${nextUrl}` | |
| ); | |
| const { page, modhash, url } = await fetchPage(nextUrl); | |
| const comments = getPageComments({ page, referrer: url }); | |
| for (const comment of comments) { | |
| if (MODE === "delete") { | |
| console.log( | |
| `Deleting comment ${comment.id} in r/${comment.subreddit}...` | |
| ); | |
| await deleteComment({ ...comment, modhash }); | |
| commentsDeleted++; | |
| console.log( | |
| `Deleted comment ${comment.id}! Waiting ${DELAY_BETWEEN_DELETES_MS}ms before next delete` | |
| ); | |
| await sleep(DELAY_BETWEEN_DELETES_MS); | |
| } else if (MODE === "count") { | |
| counts[comment.subreddit] = (counts[comment.subreddit] || 0) + 1; | |
| } | |
| } | |
| console.log( | |
| `Finished processing page, waiting ${DELAY_BETWEEN_PAGES_MS}ms before next page` | |
| ); | |
| await sleep(DELAY_BETWEEN_PAGES_MS); | |
| const nextPageUrl = getNextPageUrl(page); | |
| if (nextPageUrl) { | |
| await processPage(nextPageUrl); | |
| } else { | |
| console.log("That was the last page!"); | |
| } | |
| } | |
| // -------------- | |
| const MODHASH_REGEXP = /"modhash": "(\S+)"/; | |
| const BODY_REGEXP = /<body.*?>([\s\S]*)<\/body>/; | |
| const SCRIPT_REGEXP = /<script[\s\S]*?<\/script>/g; | |
| async function fetchPage(url) { | |
| const resolvedUrl = url ?? `https://old.reddit.com/user/${USERNAME}/overview`; | |
| const result = await fetch(resolvedUrl, { | |
| headers: { | |
| accept: | |
| "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", | |
| "accept-language": "en-US,en;q=0.9,es;q=0.8", | |
| "cache-control": "max-age=0", | |
| priority: "u=0, i", | |
| "sec-ch-ua": | |
| '"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"', | |
| "sec-ch-ua-mobile": "?0", | |
| "sec-ch-ua-platform": '"macOS"', | |
| "sec-fetch-dest": "document", | |
| "sec-fetch-mode": "navigate", | |
| "sec-fetch-site": "none", | |
| "sec-fetch-user": "?1", | |
| "upgrade-insecure-requests": "1", | |
| }, | |
| body: null, | |
| method: "GET", | |
| mode: "cors", | |
| credentials: "include", | |
| }); | |
| const text = await result.text(); | |
| const modhash = text.match(MODHASH_REGEXP)[1]; | |
| const bodyContents = text.match(BODY_REGEXP)[1]; | |
| const bodyContentsWithoutScripts = bodyContents.replace(SCRIPT_REGEXP, ""); | |
| const dummyBody = document.createElement("div"); | |
| dummyBody.innerHTML = bodyContentsWithoutScripts; | |
| return { page: dummyBody, modhash, url: resolvedUrl }; | |
| } | |
| async function deleteComment({ referrer, id, user, modhash }) { | |
| return fetch("https://old.reddit.com/api/del", { | |
| headers: { | |
| accept: "application/json, text/javascript, */*; q=0.01", | |
| "accept-language": "en-US,en;q=0.9,es;q=0.8", | |
| "content-type": "application/x-www-form-urlencoded; charset=UTF-8", | |
| priority: "u=1, i", | |
| "sec-ch-ua": | |
| '"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"', | |
| "sec-ch-ua-mobile": "?0", | |
| "sec-ch-ua-platform": '"macOS"', | |
| "sec-fetch-dest": "empty", | |
| "sec-fetch-mode": "cors", | |
| "sec-fetch-site": "same-origin", | |
| "x-requested-with": "XMLHttpRequest", | |
| }, | |
| referrer, | |
| body: `id=${id}&executed=deleted&r=u_${user}&uh=${modhash}&renderstyle=html`, | |
| method: "POST", | |
| mode: "cors", | |
| credentials: "include", | |
| }); | |
| } | |
| function getPageComments({ page, referrer }) { | |
| return [...page.querySelectorAll('[data-type="comment"]')] | |
| .map((el) => ({ | |
| id: el.getAttribute("data-fullname"), | |
| user: el.getAttribute("data-author"), | |
| subreddit: el.getAttribute("data-subreddit"), | |
| referrer, | |
| })) | |
| .filter((comment) => { | |
| if (comment.user !== USERNAME) return false; | |
| if (SUBREDDITS.length === 0) return true; | |
| return SUBREDDITS.includes(comment.subreddit); | |
| }); | |
| } | |
| function getNextPageUrl(page) { | |
| return page.querySelector(".next-button a")?.href; | |
| } | |
| async function sleep(ms) { | |
| return new Promise((resolve) => setTimeout(resolve, ms)); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment