-
-
Save sbolel/a2b2bfde16b3ab185fbc2e2049240abc to your computer and use it in GitHub Desktop.
/** | |
* This script automates the process of deleting your own Instagram comments. | |
* It deletes comments in batches to avoid hitting rate limits or breaking the page. | |
* | |
* WARNING: This function directly manipulates the DOM and depends on the current HTML | |
* structure of Instagram's website to work. If Instagram implements changes to the | |
* activity page layout, structure, or functionality, this script may break or cause | |
* unexpected behavior. Use at your own risk and always review code before running it. | |
* | |
* How to use: | |
* 1. Navigate to the Instagram comments page by going to: | |
* https://www.instagram.com/your_activity/interactions/comments | |
* 2. Open the developer console in your web browser: | |
* - Chrome/Firefox: Press Ctrl+Shift+J (Windows/Linux) or Cmd+Option+J (Mac) | |
* - Safari: Enable the Develop menu in Safari's Advanced preferences, then press Cmd+Option+C | |
* 3. Copy and paste this entire script into the console and press Enter to run it. | |
* | |
* How to navigate to the comments page on instagram.com: | |
* 1. Log in to Instagram on a desktop browser. | |
* 2. Go to your profile by clicking on the profile icon at the bottom right. | |
* 3. Click on "Your Activity" in the menu. | |
* 4. Select "Interactions" and then "Comments". | |
* 5. Follow the usage steps above to run this script. | |
*/ | |
;(async function () { | |
// Constants | |
/** @const {number} - The number of comments to delete in each batch. */ | |
const DELETION_BATCH_SIZE = 3 | |
/** @const {number} - The delay between actions in milliseconds. */ | |
const DELAY_BETWEEN_ACTIONS_MS = 1000 | |
/** @const {number} - The delay between clicking the checkboxes in milliseconds. */ | |
const DELAY_BETWEEN_CHECKBOX_CLICKS_MS = 300 | |
/** @const {number} - The maximum number of retries for waiting operations */ | |
const MAX_RETRIES = 60 | |
/** | |
* Utility function that delays execution for a given amount of time. | |
* @param {number} ms - The milliseconds to delay. | |
* @returns {Promise<void>} A promise that resolves after the specified delay. | |
*/ | |
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) | |
/** | |
* Utility function that waits for an element to appear in the DOM before resolving. | |
* @param {string} selector - The CSS selector of the element to wait for. | |
* @param {number} [timeout=30000] - The maximum time to wait in milliseconds. | |
* @returns {Promise<Element>} A promise that resolves with the found element. | |
* @throws {Error} If the element is not found within the timeout period. | |
*/ | |
const waitForElement = async (selector, timeout = 30000) => { | |
const startTime = Date.now() | |
while (Date.now() - startTime < timeout) { | |
const element = document.querySelector(selector) | |
if (element) return element | |
await delay(100) | |
} | |
throw new Error(`Element with selector "${selector}" not found within ${timeout}ms`) | |
} | |
/** | |
* Utility function that clicks on a given element. | |
* @param {Element} element - The element to click. | |
* @throws {Error} If the element is not found. | |
*/ | |
const clickElement = async (element) => { | |
if (!element) throw new Error('Element not found') | |
element.click() | |
} | |
/** | |
* Waits for the "Select" button to reappear after the page loads more comments | |
* following the deletion of a batch of comments when the "Select" button | |
* is hidden while a spinner indicates that more comments are loading. | |
* @returns {Promise<void>} A promise that resolves when the select button reappears. | |
* @throws {Error} If the select button is not found after maximum retries. | |
*/ | |
const waitForSelectButton = async () => { | |
for (let i = 0; i < MAX_RETRIES; i++) { | |
const buttonCount = document.querySelectorAll('[role="button"]')?.length | |
if (buttonCount > 1) return | |
await delay(1000) | |
} | |
throw new Error('Select button not found after maximum retries') | |
} | |
/** | |
* Deletes the currently selected comments. | |
* @returns {Promise<void>} A promise that resolves when the comments are deleted. | |
*/ | |
const deleteSelectedComments = async () => { | |
try { | |
const deleteButton = await waitForElement('[aria-label="Delete"]') | |
await clickElement(deleteButton) | |
await delay(DELAY_BETWEEN_ACTIONS_MS) | |
const confirmButton = await waitForElement('button[tabindex="0"]') | |
await clickElement(confirmButton) | |
} catch (error) { | |
console.error('Error during comment deletion:', error.message) | |
} | |
} | |
/** | |
* Deletes all user comments by selecting comments in batches. | |
* @returns {Promise<void>} A promise that resolves when all comments are deleted. | |
*/ | |
const deleteActivity = async () => { | |
try { | |
while (true) { | |
const [, selectButton] = document.querySelectorAll('[role="button"]') | |
if (!selectButton) throw new Error('Select button not found') | |
await clickElement(selectButton) | |
await delay(DELAY_BETWEEN_ACTIONS_MS) | |
const checkboxes = document.querySelectorAll('[aria-label="Toggle checkbox"]') | |
if (checkboxes.length === 0) { | |
console.log('No more comments to delete') | |
break | |
} | |
for (let i = 0; i < Math.min(DELETION_BATCH_SIZE, checkboxes.length); i++) { | |
await clickElement(checkboxes[i]) | |
await delay(DELAY_BETWEEN_CHECKBOX_CLICKS_MS) | |
} | |
await delay(DELAY_BETWEEN_ACTIONS_MS) | |
await deleteSelectedComments() | |
await delay(DELAY_BETWEEN_ACTIONS_MS) | |
await waitForSelectButton() | |
await delay(DELAY_BETWEEN_ACTIONS_MS) | |
} | |
} catch (error) { | |
console.error('Error in deleteActivity:', error.message) | |
} | |
} | |
// Start the deletion process | |
try { | |
await deleteActivity() | |
console.log('Activity deletion completed') | |
} catch (error) { | |
console.error('Fatal error:', error.message) | |
} | |
})() |
@gabriellobato1987 your code is by far the most functional, but it simply doesn't ever find the delete button when i use it, it will reset, select the same 40 comments, then hang, then reset, select the same 40 comments, etc etc. is there a line i need to edit?
@Spiderdoom1313 do you have a script but for google chrome, not python required
Written on 13/7/2025
I've used chatgpt to update the code so it can be used at this point in time, it uses selenium so be sure to have selenium installed, run this on python:
import logging import pathlib import platform import random import sys import time from selenium import webdriver from selenium.common.exceptions import NoSuchWindowException, TimeoutException, StaleElementReferenceException from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait # Logging setup logging.basicConfig(format="[%(levelname)s] Instagram Cleaner: %(message)s", level=logging.INFO) # Constants MODE = 1 # 1 = comments, 2 = likes CHECK_EVERY = -1 LIKES_URL = "https://www.instagram.com/your_activity/interactions/likes" COMMENTS_URL = "https://www.instagram.com/your_activity/interactions/comments" AT_ONCE_DELETE = 50 # Maximum items to delete in one go logging.info("Starting script...") try: options = Options() wd = pathlib.Path().absolute() if platform.system() == "Windows": options.add_argument(f"user-data-dir={wd}\\chrome-profile") else: options.add_argument("user-data-dir=chrome-profile") driver = webdriver.Chrome(options=options) logging.info("Chrome browser launched") URL = COMMENTS_URL if MODE == 1 else LIKES_URL driver.get(URL) logging.info(f"Opening page: {URL}") # Wait for user to log in manually while True: if driver.current_url.startswith(URL): logging.info("Login detected") break try: logging.info("Waiting for login (log in from the browser and don't click anything else)...") wait = WebDriverWait(driver, 60) def is_not_now_button_present(driver): try: div = driver.find_element(By.CSS_SELECTOR, "div[role='button']") return div.text in ["Not now", "Plus tard"] except: return False wait.until(is_not_now_button_present) driver.find_element(By.CSS_SELECTOR, "div[role='button']").send_keys(Keys.ENTER) logging.info("Clicked 'Not now'") break except TimeoutException: pass # Main loop while True: is_clicked_select = False while not is_clicked_select: logging.info("Waiting for elements to load...") time.sleep(2) elements = driver.find_elements(By.CSS_SELECTOR, 'span[data-bloks-name="bk.components.Text"]') for el in elements: if el.text in ["Select", "Sélectionner"]: if any(txt.text in ["No results", "Aucun résultat"] for txt in elements): logging.info("No items found. Finished.") driver.quit() sys.exit(0) driver.execute_script("arguments[0].click();", el) logging.info("Clicked 'Select'") is_clicked_select = True break selected_count = 0 attempts = 0 refreshed = False while selected_count == 0: if refreshed: break time.sleep(1) for icon in driver.find_elements(By.CSS_SELECTOR, 'div[data-bloks-name="ig.components.Icon"]'): try: if icon.get_attribute("style").startswith('mask-image: url("https://i.instagram.com/static/images/bloks/icons/generated/circle__outline'): driver.execute_script("arguments[0].click();", icon) selected_count += 1 logging.info(f"Selected item (Total: {selected_count})") if selected_count >= AT_ONCE_DELETE: break except StaleElementReferenceException: continue attempts += 1 if attempts > 10: if CHECK_EVERY == -1: logging.warning("Deletion limit hit. Instagram is temporarily blocking actions.") while True: wait_hours = input("Check again after how many hours? (default: 1) [x]: ") try: wait_hours = float(wait_hours or "1") break except ValueError: pass CHECK_EVERY = int(wait_hours * 3600) logging.info(f"Waiting {wait_hours} hour(s) before retrying.") time.sleep(random.uniform(CHECK_EVERY * 0.9, CHECK_EVERY * 1.1)) logging.info("Refreshing page...") driver.refresh() refreshed = True continue if refreshed: continue # Click Delete/Unlike for span in driver.find_elements(By.CSS_SELECTOR, 'span[data-bloks-name="bk.components.TextSpan"]'): if span.text in (["Delete", "Supprimer"] if MODE == 1 else ["Unlike", "Je n’aime plus"]): time.sleep(1) driver.execute_script("arguments[0].click();", span) logging.info(f"Clicked '{span.text}'") break # Confirm the deletion confirmed = False while not confirmed: time.sleep(1) for btn in driver.find_elements(By.CSS_SELECTOR, 'div[role="dialog"] button'): try: confirmation_text = btn.find_element(By.CSS_SELECTOR, "div").text if confirmation_text in ["Delete", "Unlike", "Supprimer", "Je n’aime plus"]: driver.execute_script("arguments[0].click();", btn) logging.info(f"Confirmed '{confirmation_text}'") confirmed = True break except StaleElementReferenceException: continue except KeyboardInterrupt: logging.info("Script manually interrupted.") driver.quit() sys.exit(0) except NoSuchWindowException: logging.exception("Browser window was closed.") sys.exit(1) except Exception as e: logging.exception("Unexpected error:") try: driver.quit() except: pass sys.exit(1)
works as of this comment's date
As of current, if I run the script it will select the first comment, unselect it then select the next two. It wont find the Delete button element, presumably because it was changed?
Error during comment deletion: Element with selector "button[tabindex="0"]" not found within 30000ms
your code does not work. delete this or fix this quit wasting our time
Button was not found wtf?
try below it works but it selects 20 comments at max and you need to just click on delete then confirmation dialogue comes up and you confirm.
;(async function () {
const DELETION_BATCH_SIZE = 20
const DELAY_BETWEEN_ACTIONS_MS = 3000
const DELAY_BETWEEN_CHECKBOX_CLICKS_MS = 100
const MAX_RETRIES = 100
const delay = ms => new Promise(res => setTimeout(res, ms))
async function slowScrollDown(totalDurationMs = 6000, steps = 6) {
const totalHeight = document.body.scrollHeight
const stepHeight = totalHeight / steps
const stepDelay = totalDurationMs / steps
for (let i = 0; i < steps; i++) {
window.scrollBy(0, stepHeight)
await delay(stepDelay)
}
}
async function clickElement(el) {
if (!el) throw new Error("Element not found")
el.click()
}
async function getSelectButton() {
const elems = [...document.querySelectorAll('[role="button"], span, div')]
return elems.find(el => el.innerText.trim() === "Select") || null
}
async function getDeleteButton() {
const elems = [...document.querySelectorAll("span, div, button")]
return elems.find(el => el.innerText.trim() === "Delete") || null
}
async function handleWrongMessage() {
const msgs = document.querySelectorAll("div, span, p")
for (const msg of msgs) {
if (msg.textContent.toLowerCase().includes("wrong")) {
const buttons = document.querySelectorAll("button")
for (const btn of buttons) {
if (/^(ok)$/i.test(btn.textContent.trim())) {
await clickElement(btn)
await delay(500)
window.scrollTo(0, 0)
break
}
}
break
}
}
}
async function waitForSelectButton() {
for (let i = 0; i < MAX_RETRIES; i++) {
const selectBtn = await getSelectButton()
if (selectBtn) return selectBtn
await delay(1000)
}
throw new Error("Select button not found after retries")
}
async function deleteSelectedComments() {
try {
const deleteButton = await getDeleteButton()
if (!deleteButton) throw new Error("Delete button not found")
await clickElement(deleteButton)
await delay(DELAY_BETWEEN_ACTIONS_MS)
const confirmButton = document.querySelector('button[tabindex="0"]')
if (confirmButton) await clickElement(confirmButton)
window.scrollTo(0, 0)
await handleWrongMessage()
} catch (err) {
console.error("Error during comment deletion:", err.message)
}
}
async function deleteActivity() {
while (true) {
const selectButton = await getSelectButton()
if (!selectButton) throw new Error("Select button not found")
await clickElement(selectButton)
await delay(DELAY_BETWEEN_ACTIONS_MS)
let checkboxes = document.querySelectorAll('[aria-label="Toggle checkbox"]')
let retries = 0
while (checkboxes.length < DELETION_BATCH_SIZE && retries < 10) {
await slowScrollDown(2000, 4)
await delay(2000)
checkboxes = document.querySelectorAll('[aria-label="Toggle checkbox"]')
retries++
}
if (checkboxes.length === 0) {
console.log("✅ No more comments to delete")
return
}
for (let i = 0; i < Math.min(DELETION_BATCH_SIZE, checkboxes.length); i++) {
await clickElement(checkboxes[i])
await delay(DELAY_BETWEEN_CHECKBOX_CLICKS_MS)
}
await delay(DELAY_BETWEEN_ACTIONS_MS)
await deleteSelectedComments()
await delay(DELAY_BETWEEN_ACTIONS_MS)
await waitForSelectButton()
await delay(DELAY_BETWEEN_ACTIONS_MS)
await handleWrongMessage()
}
}
try {
await deleteActivity()
console.log("🎉 Deletion finished")
} catch (err) {
console.error("Fatal error:", err.message)
}
})()
Here is a revised version that also retries upon errors during deletion and is substantially faster. Make sure you set the display language to English for it to work
/**
* This script automates the process of deleting your own Instagram comments.
* It deletes comments in batches to avoid hitting rate limits or breaking the page.
*
* WARNING: This function directly manipulates the DOM and depends on the current HTML
* structure of Instagram's website to work. If Instagram implements changes to the
* activity page layout, structure, or functionality, this script may break or cause
* unexpected behavior. Use at your own risk and always review code before running it.
*
* How to use:
* 1. Navigate to the Instagram comments page by going to:
* https://www.instagram.com/your_activity/interactions/comments
* 2. Open the developer console in your web browser:
* - Chrome/Firefox: Press Ctrl+Shift+J (Windows/Linux) or Cmd+Option+J (Mac)
* - Safari: Enable the Develop menu in Safari's Advanced preferences, then press Cmd+Option+C
* 3. Copy and paste this entire script into the console and press Enter to run it.
*
* How to navigate to the comments page on instagram.com:
* 1. Log in to Instagram on a desktop browser.
* 2. Go to your profile by clicking on the profile icon at the bottom right.
* 3. Click on "Your Activity" in the menu.
* 4. Select "Interactions" and then "Comments".
* 5. Follow the usage steps above to run this script.
*/
(async function () {
// Constants
/** @const {number} - The number of comments to delete in each batch. */
const DELETION_BATCH_SIZE = 20
/** @const {number} - The delay between actions in milliseconds. */
const DELAY_BETWEEN_ACTIONS_MS = 700
/** @const {number} - The delay between clicking the checkboxes in milliseconds. */
const DELAY_BETWEEN_CHECKBOX_CLICKS_MS = 100
/** @const {number} - The maximum number of retries for waiting operations */
const MAX_RETRIES = 60
/**
* Utility function that delays execution for a given amount of time.
* @param {number} ms - The milliseconds to delay.
* @returns {Promise<void>} A promise that resolves after the specified delay.
*/
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
/**
* Utility function that waits for an element to appear in the DOM before resolving.
* @param {string} selector - The CSS selector of the element to wait for.
* @param {number} [timeout=30000] - The maximum time to wait in milliseconds.
* @returns {Promise<Element>} A promise that resolves with the found element.
* @throws {Error} If the element is not found within the timeout period.
*/
const waitForElement = async (tag, selector, timeout = 30000) => {
console.log(`Waiting for ${tag} element with selector "${selector}"...`)
const startTime = Date.now()
while (Date.now() - startTime < timeout) {
const element = Array.from(document.querySelectorAll(tag)).find((el) => el.textContent === selector)
if (element) {
console.log(`Found ${tag} element with selector "${selector}"`)
return element
}
await delay(100)
}
throw new Error(`Element with selector "${selector}" not found within ${timeout}ms`)
}
/**
* Utility function that clicks on a given element.
* @param {Element} element - The element to click.
* @throws {Error} If the element is not found.
*/
const clickElement = async (element) => {
if (!element) throw new Error('Element not found')
element.click()
}
/**
* Deletes the currently selected comments.
* @returns {Promise<void>} A promise that resolves when the comments are deleted.
*/
const deleteSelectedComments = async () => {
try {
const deleteButton = await waitForElement('span', 'Delete')
await clickElement(deleteButton)
await delay(DELAY_BETWEEN_ACTIONS_MS)
const confirmButton = await waitForElement('button', 'Delete')
await clickElement(confirmButton)
await delay(5000)
// Handle Instagram's error dialog
const okButton = await waitForElement('button', 'OK', 10000)
await clickElement(okButton)
console.log('Deleted selected comments')
} catch (error) {
console.error('Error during comment deletion:', error.message)
}
}
/**
* Deletes all user comments by selecting comments in batches.
* @returns {Promise<void>} A promise that resolves when all comments are deleted.
*/
const deleteActivity = async () => {
try {
console.log('Starting deletion process...')
const selectButton = await waitForElement('span', 'Select')
if (!selectButton) throw new Error('Select button not found')
await clickElement(selectButton)
await delay(DELAY_BETWEEN_ACTIONS_MS)
const checkboxes = document.querySelectorAll('[aria-label="Toggle checkbox"]')
if (checkboxes.length === 0) {
console.log('No comments to delete... retrying after delay')
await delay(DELAY_BETWEEN_ACTIONS_MS)
return deleteActivity();
}
for (let i = 0; i < Math.min(DELETION_BATCH_SIZE, checkboxes.length); i++) {
await clickElement(checkboxes[i])
await delay(DELAY_BETWEEN_CHECKBOX_CLICKS_MS)
}
await delay(DELAY_BETWEEN_ACTIONS_MS)
await deleteSelectedComments()
deleteActivity();
} catch (error) {
console.error('Error in deleteActivity:', error.message)
}
}
// Start the deletion process
try {
deleteActivity()
} catch (error) {
console.error('Fatal error:', error.message)
}
})()
(async function () { // Constants /** @const {number} - The number of comments to delete in each batch. */ const DELETION_BATCH_SIZE = 20 /** @const {number} - The delay between actions in milliseconds. */ const DELAY_BETWEEN_ACTIONS_MS = 700 /** @const {number} - The delay between clicking the checkboxes in milliseconds. */ const DELAY_BETWEEN_CHECKBOX_CLICKS_MS = 100 /** @const {number} - The maximum number of retries for waiting operations */ const MAX_RETRIES = 60 /** * Utility function that delays execution for a given amount of time. * @param {number} ms - The milliseconds to delay. * @returns {Promise<void>} A promise that resolves after the specified delay. */ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) /** * Utility function that waits for an element to appear in the DOM before resolving. * @param {string} selector - The CSS selector of the element to wait for. * @param {number} [timeout=30000] - The maximum time to wait in milliseconds. * @returns {Promise<Element>} A promise that resolves with the found element. * @throws {Error} If the element is not found within the timeout period. */ const waitForElement = async (tag, selector, timeout = 30000) => { console.log(`Waiting for ${tag} element with selector "${selector}"...`) const startTime = Date.now() while (Date.now() - startTime < timeout) { const element = Array.from(document.querySelectorAll(tag)).find((el) => el.textContent === selector) if (element) { console.log(`Found ${tag} element with selector "${selector}"`) return element } await delay(100) } throw new Error(`Element with selector "${selector}" not found within ${timeout}ms`) } /** * Utility function that clicks on a given element. * @param {Element} element - The element to click. * @throws {Error} If the element is not found. */ const clickElement = async (element) => { if (!element) throw new Error('Element not found') element.click() } /** * Deletes the currently selected comments. * @returns {Promise<void>} A promise that resolves when the comments are deleted. */ const deleteSelectedComments = async () => { try { const deleteButton = await waitForElement('span', 'Delete') await clickElement(deleteButton) await delay(DELAY_BETWEEN_ACTIONS_MS) const confirmButton = await waitForElement('button', 'Delete') await clickElement(confirmButton) await delay(5000) // Handle Instagram's error dialog const okButton = await waitForElement('button', 'OK', 10000) await clickElement(okButton) console.log('Deleted selected comments') } catch (error) { console.error('Error during comment deletion:', error.message) } } /** * Deletes all user comments by selecting comments in batches. * @returns {Promise<void>} A promise that resolves when all comments are deleted. */ const deleteActivity = async () => { try { console.log('Starting deletion process...') const selectButton = await waitForElement('span', 'Select') if (!selectButton) throw new Error('Select button not found') await clickElement(selectButton) await delay(DELAY_BETWEEN_ACTIONS_MS) const checkboxes = document.querySelectorAll('[aria-label="Toggle checkbox"]') if (checkboxes.length === 0) { console.log('No comments to delete... retrying after delay') await delay(DELAY_BETWEEN_ACTIONS_MS) return deleteActivity(); } for (let i = 0; i < Math.min(DELETION_BATCH_SIZE, checkboxes.length); i++) { await clickElement(checkboxes[i]) await delay(DELAY_BETWEEN_CHECKBOX_CLICKS_MS) } await delay(DELAY_BETWEEN_ACTIONS_MS) await deleteSelectedComments() deleteActivity(); } catch (error) { console.error('Error in deleteActivity:', error.message) } } // Start the deletion process try { deleteActivity() } catch (error) { console.error('Fatal error:', error.message) } })()
This is working so far. Will let you know if it works on one go.
I just used the script from @kimonneuhoff and it worked great with no errors or timeouts. Also by changing "Delete" to "Unlike" it worked for deleting my Like history. I also used the trick of opening two tabs and sorting the second by Oldest First and starting another delete script. That allowed me to delete twice as fast. Thanks everyone who has contributed to keeping this script working!
edit: for those who dont know how to install selenium do the following:
1.Press Win + R, type cmd, then press Enter.
2. Run These Commands One by One:
python --version pip --version pip install selenium
3. Then its done you can run the code above in python with no problem