-
-
Save antlionguard/000e24bb039e8824fa5c58d6e324c78e to your computer and use it in GitHub Desktop.
| const timer = ms => new Promise(res => setTimeout(res, ms)); | |
| // Unretweet normally | |
| const unretweetTweet = async (tweet) => { | |
| await tweet.querySelector('[data-testid="unretweet"]').click(); | |
| await timer(250); | |
| await document.querySelector('[data-testid="unretweetConfirm"]').click(); | |
| console.log('****// Unretweeted Successfully //****') | |
| } | |
| // Sometimes twitter shows your retweet but green retweet button is invisible and therefore you need to retweet again for make unreweet. This function is for that. | |
| const unretweetUnretweetedTweet = async (tweet) => { | |
| await tweet.querySelector('[data-testid="retweet"]').click(); | |
| await timer(250); | |
| await document.querySelector('[data-testid="retweetConfirm"]').click(); | |
| console.log('****// Retweeted Successfully //****') | |
| await timer(250); | |
| unretweetTweet(tweet); | |
| } | |
| setInterval(async () => | |
| { | |
| // Get all tweets | |
| const retweetedTweetList = document.querySelectorAll('[data-testid="socialContext"]'); | |
| console.log('****// Retweeted Tweet List Collected //****') | |
| for (const retweet of retweetedTweetList) { | |
| const tweetWrapper = retweet.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement; | |
| tweetWrapper.scrollIntoView(); | |
| const isRetweeted = tweetWrapper.querySelector('[data-testid="unretweet"]'); | |
| if (isRetweeted) { | |
| console.log('****// Green Retweet Button Found - Starting "unretweetTweet" process //****') | |
| await unretweetTweet(tweetWrapper); | |
| } else { | |
| console.log('****// Green Retweet Button Not Found - Starting "unretweetUnretweetedTweet" process //****') | |
| await unretweetUnretweetedTweet(tweetWrapper); | |
| } | |
| await timer(2000); | |
| } | |
| console.log('****// List Completed //****') | |
| console.log('****// Scrolling //****') | |
| console.log(' ') | |
| console.log(' ') | |
| console.log(' ') | |
| console.log(' ') | |
| console.log(' ') | |
| console.log(' ') | |
| console.log(' ') | |
| console.log(' ') | |
| await window.scrollTo(0, document.body.scrollHeight); | |
| }, 60000); |
The above code should be simplified to the following. I'm using this to remove unwanted retweets but not retweets my own tweets.
setInterval(
function() {
document.querySelector('[data-testid="unretweet"]').click()
document.querySelector('[data-testid="unretweetConfirm"]').click()
},
500
)Reference: https://gist.github.com/martgil/ddd7da50712105777029bbacb5123265
as of 2025 this script does not work.
I have updated it to use button instead of div for unretweet test id as following and confirmed it works:
const timer = ms => new Promise(res => setTimeout(res, ms));
const unretweetTweet = async (tweet) => {
try {
await tweet.querySelector('button[data-testid="unretweet"]').click();
await timer(250);
await document.querySelector('div[data-testid="unretweetConfirm"]').click();
console.log('// Unretweeted Successfully //');
} catch (error) {
console.error('Error during unretweet:', error);
}
};
const unretweetUnretweetedTweet = async (tweet) => {
try {
await tweet.querySelector('div[data-testid="retweet"]').click();
await timer(250);
await document.querySelector('div[data-testid="retweetConfirm"]').click();
console.log('// Retweeted Successfully //');
await timer(250);
unretweetTweet(tweet);
} catch (error) {
console.error('Error during unretweetUnretweetedTweet:', error);
}
};
const processTweets = async () => {
const retweetedTweetList = document.querySelectorAll('span[data-testid="socialContext"]');
console.log('// Retweeted Tweet List Collected //');
for (const retweet of retweetedTweetList) {
const tweetWrapper = retweet.closest('[data-testid="tweet"]');
tweetWrapper.scrollIntoView();
const isRetweeted = tweetWrapper.querySelector('button[data-testid="unretweet"]');
if (isRetweeted) {
console.log('****// Green Retweet Button Found - Starting "unretweetTweet" process //****');
await unretweetTweet(tweetWrapper);
} else {
console.log('****// Green Retweet Button Not Found - Starting "unretweetUnretweetedTweet" process //****');
await unretweetUnretweetedTweet(tweetWrapper);
}
await timer(2000);
}
console.log('// List Completed //');
console.log('// Scrolling //');
console.log(' ');
console.log(' ');
console.log(' ');
console.log(' ');
console.log(' ');
console.log(' ');
console.log(' ');
console.log(' ');
window.scrollTo(0, document.body.scrollHeight);
// Call processTweets again using requestAnimationFrame to keep the loop going
requestAnimationFrame(processTweets);
};
// Start the process initially
processTweets();
2025 may 16th, it still works. the updated command of my above, it works perfectly
as of 28th July I can confirm it is still working
Bo thanig
as of 2025 this script does not work.
I have updated it to use button instead of div for unretweet test id as following and confirmed it works:
const timer = ms => new Promise(res => setTimeout(res, ms));
const unretweetTweet = async (tweet) => { try { await tweet.querySelector('button[data-testid="unretweet"]').click(); await timer(250); await document.querySelector('div[data-testid="unretweetConfirm"]').click(); console.log('// Unretweeted Successfully //'); } catch (error) { console.error('Error during unretweet:', error); } };
const unretweetUnretweetedTweet = async (tweet) => { try { await tweet.querySelector('div[data-testid="retweet"]').click(); await timer(250); await document.querySelector('div[data-testid="retweetConfirm"]').click(); console.log('// Retweeted Successfully //'); await timer(250); unretweetTweet(tweet); } catch (error) { console.error('Error during unretweetUnretweetedTweet:', error); } };
const processTweets = async () => { const retweetedTweetList = document.querySelectorAll('span[data-testid="socialContext"]'); console.log('// Retweeted Tweet List Collected //');
for (const retweet of retweetedTweetList) { const tweetWrapper = retweet.closest('[data-testid="tweet"]'); tweetWrapper.scrollIntoView();
const isRetweeted = tweetWrapper.querySelector('button[data-testid="unretweet"]'); if (isRetweeted) { console.log('****// Green Retweet Button Found - Starting "unretweetTweet" process //****'); await unretweetTweet(tweetWrapper); } else { console.log('****// Green Retweet Button Not Found - Starting "unretweetUnretweetedTweet" process //****'); await unretweetUnretweetedTweet(tweetWrapper); } await timer(2000);} console.log('// List Completed //'); console.log('// Scrolling //'); console.log(' '); console.log(' '); console.log(' '); console.log(' '); console.log(' '); console.log(' '); console.log(' '); console.log(' '); window.scrollTo(0, document.body.scrollHeight);
// Call processTweets again using requestAnimationFrame to keep the loop going requestAnimationFrame(processTweets); };
// Start the process initially processTweets();
This worked for me!
re-pasting @JordanWinslow 's script in a code block to fix formatting. works as of 09/2025 :)
const timer = (ms) => new Promise((res) => setTimeout(res, ms));
const unretweetTweet = async (tweet) => {
try {
await tweet.querySelector('button[data-testid="unretweet"]').click();
await timer(250);
await document.querySelector('div[data-testid="unretweetConfirm"]').click();
console.log("// Unretweeted Successfully //");
} catch (error) {
console.error("Error during unretweet:", error);
}
};
const unretweetUnretweetedTweet = async (tweet) => {
try {
await tweet.querySelector('div[data-testid="retweet"]').click();
await timer(250);
await document.querySelector('div[data-testid="retweetConfirm"]').click();
console.log("// Retweeted Successfully //");
await timer(250);
unretweetTweet(tweet);
} catch (error) {
console.error("Error during unretweetUnretweetedTweet:", error);
}
};
const processTweets = async () => {
const retweetedTweetList = document.querySelectorAll(
'span[data-testid="socialContext"]',
);
console.log("// Retweeted Tweet List Collected //");
for (const retweet of retweetedTweetList) {
const tweetWrapper = retweet.closest('[data-testid="tweet"]');
tweetWrapper.scrollIntoView();
const isRetweeted = tweetWrapper.querySelector(
'button[data-testid="unretweet"]',
);
if (isRetweeted) {
console.log(
'****// Green Retweet Button Found - Starting "unretweetTweet" process //****',
);
await unretweetTweet(tweetWrapper);
} else {
console.log(
'****// Green Retweet Button Not Found - Starting "unretweetUnretweetedTweet" process //****',
);
await unretweetUnretweetedTweet(tweetWrapper);
}
await timer(2000);
}
console.log("// List Completed //");
console.log("// Scrolling //");
console.log(" ");
console.log(" ");
console.log(" ");
console.log(" ");
console.log(" ");
console.log(" ");
console.log(" ");
console.log(" ");
window.scrollTo(0, document.body.scrollHeight);
// Call processTweets again using requestAnimationFrame to keep the loop going
requestAnimationFrame(processTweets);
};
// Start the process initially
processTweets();const timer = (ms) => new Promise((res) => setTimeout(res, ms)); const unretweetTweet = async (tweet) => { try { await tweet.querySelector('button[data-testid="unretweet"]').click(); await timer(250); await document.querySelector('div[data-testid="unretweetConfirm"]').click(); console.log("// Unretweeted Successfully //"); } catch (error) { console.error("Error during unretweet:", error); } }; const unretweetUnretweetedTweet = async (tweet) => { try { await tweet.querySelector('div[data-testid="retweet"]').click(); await timer(250); await document.querySelector('div[data-testid="retweetConfirm"]').click(); console.log("// Retweeted Successfully //"); await timer(250); unretweetTweet(tweet); } catch (error) { console.error("Error during unretweetUnretweetedTweet:", error); } }; const processTweets = async () => { const retweetedTweetList = document.querySelectorAll( 'span[data-testid="socialContext"]', ); console.log("// Retweeted Tweet List Collected //"); for (const retweet of retweetedTweetList) { const tweetWrapper = retweet.closest('[data-testid="tweet"]'); tweetWrapper.scrollIntoView(); const isRetweeted = tweetWrapper.querySelector( 'button[data-testid="unretweet"]', ); if (isRetweeted) { console.log( '****// Green Retweet Button Found - Starting "unretweetTweet" process //****', ); await unretweetTweet(tweetWrapper); } else { console.log( '****// Green Retweet Button Not Found - Starting "unretweetUnretweetedTweet" process //****', ); await unretweetUnretweetedTweet(tweetWrapper); } await timer(2000); } console.log("// List Completed //"); console.log("// Scrolling //"); console.log(" "); console.log(" "); console.log(" "); console.log(" "); console.log(" "); console.log(" "); console.log(" "); console.log(" "); window.scrollTo(0, document.body.scrollHeight); // Call processTweets again using requestAnimationFrame to keep the loop going requestAnimationFrame(processTweets); }; // Start the process initially processTweets();
still works. thanks
Autonomous version
const timer = ms => new Promise(res => setTimeout(res, ms));
let totalUnretweeted = 0;
let isRunning = true;
// Stop the script by running: isRunning = false; in console
window.stopUnretweet = () => {
isRunning = false;
console.log('// Stopping script... //');
};
const unretweetBatch = async () => {
const retweetedTweetList = document.querySelectorAll('span[data-testid="socialContext"]');
if (retweetedTweetList.length === 0) {
console.log('// No retweets found, scrolling... //');
return 0;
}
let batchCount = 0;
for (const retweet of retweetedTweetList) {
if (!isRunning) break;
const tweetWrapper = retweet.closest('[data-testid="tweet"]');
if (!tweetWrapper) continue;
tweetWrapper.scrollIntoView({ behavior: 'smooth', block: 'center' });
await timer(800);
const unretweetButton = tweetWrapper.querySelector('button[data-testid="unretweet"]');
if (unretweetButton) {
try {
unretweetButton.click();
await timer(500);
const confirmButton = document.querySelector('div[data-testid="unretweetConfirm"]');
if (confirmButton) {
confirmButton.click();
batchCount++;
totalUnretweeted++;
console.log(`✓ Unretweeted #${totalUnretweeted}`);
}
} catch (error) {
console.error('Error:', error);
}
}
await timer(3000); // 3 second delay between unretweets
}
return batchCount;
};
const autoUnretweet = async () => {
console.log('🚀 Starting autonomous unretweet script...');
console.log('
console.log(' ');
while (isRunning) {
const processed = await unretweetBatch();
if (!isRunning) break;
// Scroll down to load more
console.log('📜 Scrolling to load more tweets...');
window.scrollTo(0, document.body.scrollHeight);
// Wait for new tweets to load
await timer(4000);
// If no tweets were processed, wait longer before trying again
if (processed === 0) {
console.log('⏸️ No retweets found. Waiting 10 seconds before checking again...');
await timer(10000);
}
}
console.log(' ');
console.log(✅ Script stopped. Total unretweeted: ${totalUnretweeted});
};
autoUnretweet();
Any way to fix it?