Skip to content

Instantly share code, notes, and snippets.

@aymericbeaumet
Last active September 29, 2024 19:47
Show Gist options
  • Save aymericbeaumet/d1d6799a1b765c3c8bc0b675b1a1547d to your computer and use it in GitHub Desktop.
Save aymericbeaumet/d1d6799a1b765c3c8bc0b675b1a1547d to your computer and use it in GitHub Desktop.
[Recipe] Delete all your likes/favorites from Twitter

Ever wanted to delete all your likes/favorites from Twitter but only found broken/expensive tools? You are in the right place.

  1. Go to: https://twitter.com/{username}/likes
  2. Open the console and run the following JavaScript code:
setInterval(() => {
  for (const d of document.querySelectorAll('div[data-testid="unlike"]')) {
    d.click()
  }
  window.scrollTo(0, document.body.scrollHeight)
}, 1000)
@ranjanquiet
Copy link

none of the code on this page are working.

@verma-rajatk
Copy link

Great job! It works as of Mar 17 2023. Many Thanks.

@ianathompson
Copy link

I am aware that this is turning into the programmer's version of playing Stairway to Heaven.

But here's mine

  • rather than estimating a scroll offset, it simply uses focus() to scroll the next item into view
  • has a backoff every 50 unlikes to prevent HTTP 429: Too Many Requests
function nextUnlike() {
  return document.querySelector('[data-testid="unlike"]')
}

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function removeAll() {
  let count = 0
  let next = nextUnlike()
  while (next) {
    next.focus()
    next.click()
    console.log(`Unliked ${++count} tweets`)
    await wait(count % 50 === 0 ? 30000 : 2000)
    next = nextUnlike()
  }
  console.log('Out of unlikes, count =', count)
}

removeAll() 

At time of writing this is printing Unliked 1506 tweets

This works wonderfully. Thank you @jbreckmckye

@limeraiin
Copy link

I am aware that this is turning into the programmer's version of playing Stairway to Heaven.
But here's mine

  • rather than estimating a scroll offset, it simply uses focus() to scroll the next item into view
  • has a backoff every 50 unlikes to prevent HTTP 429: Too Many Requests
function nextUnlike() {
  return document.querySelector('[data-testid="unlike"]')
}

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function removeAll() {
  let count = 0
  let next = nextUnlike()
  while (next) {
    next.focus()
    next.click()
    console.log(`Unliked ${++count} tweets`)
    await wait(count % 50 === 0 ? 30000 : 2000)
    next = nextUnlike()
  }
  console.log('Out of unlikes, count =', count)
}

removeAll() 

At time of writing this is printing Unliked 1506 tweets

This works wonderfully. Thank you @jbreckmckye

It is not working either

main.2b1c61fa.js:1 POST https://twitter.com/i/api/graphql/ZYKSe-w7KEslx3JhSIk5LA/UnfavoriteTweet 429

it logs "x tweets removed" but in reality nothing changes.

@jbreckmckye
Copy link

jbreckmckye commented Apr 2, 2023

@limeraiin You may need to increase the timeout. Wait a day or so as well, so you aren't on any LB blacklists.

I think sometimes it takes a little while for the API to fully reconcile updates.

It's also possible twitter are clamping down further on rate issues due to problems on their platform. It's a bit inexact.

@danielraffel
Copy link

Any idea how to unretweet a tweet If you’re blocked? I read this...
https://medium.com/@SeloSlav/how-to-unretweet-a-tweet-if-youre-blocked-9b4c294f4b3f
And have the tweetID...possible to modify one of the above scripts and use the ID and unretweet it in the console?

@nicoh88
Copy link

nicoh88 commented Apr 18, 2023

Hello, can the script be tapped so that only likes older than 30 days are removed? Would be great!

And maybe the whole thing for retweets too?

Thanks

@GitJuankof
Copy link

Funcionó hasta cierto punto, porque, al igual que otros, me apacen likes invisibles que no se dejaron borrar. ¡Muchas gracias!

@sunnycs121
Copy link

sunnycs121 commented May 17, 2023

I thought it was working until i refreshed the likes page, all likes were there and now I cannot even unlike manually. I f i try to manually unlike any post it automatically likes it again. Long story short now my likes are permanent forever. 👎

@asontemn
Copy link

Thanks!

@paul3xl
Copy link

paul3xl commented Jun 9, 2023

I thought it was working until i refreshed the likes page, all likes were there and now I cannot even unlike manually. I f i try to manually unlike any post it automatically likes it again. Long story short now my likes are permanent forever. 👎

same :(

@bfontaine
Copy link

bfontaine commented Jul 29, 2023

I thought it was working until i refreshed the likes page, all likes were there and now I cannot even unlike manually. I f i try to manually unlike any post it automatically likes it again. Long story short now my likes are permanent forever. 👎

I have the same issue, but it’s only temporary: it’s because with all these calls you hit the API limits, and you can’t call it anymore for a while. Come back ten minutes later, and you should be able to delete likes again.

@inakicalvo
Copy link

Thanks a lot! This helped me a lot!

@rhodiumtertbutyl
Copy link

Okay, so here is my experience with this. I used it about a week or so ago, and my likes were still there but they did not have the red heart on them. This morning, however, all of my likes were deleted and I only have a handful or so. It takes a bit of time for the API to catch up I think, especially if you have a lot. I had the same issues as people above, although, mine did show up for me. Just could not manually unlike them. Thanks for providing this code, really appreciate it. Sites like tweetdeleter and semiephemeral did not work for likes.

@rhodiumtertbutyl
Copy link

Alright, just kidding. I went back to my original like count with the red hearts blurred out again. Interested to see why it reverted back.

@rhodiumtertbutyl
Copy link

Alright, just kidding. I went back to my original like count with the red hearts blurred out again. Interested to see why it reverted back.

OKAY here is an update: after about a month or so, my likes appeared to go back to normal and I could manually unlike them. HOWEVER, I don't think the code ended up deleting any of them. So if you plan to utilize this, make sure there's a way to only unlike a certain amount that does not fuck with the API. I don't know how to do it but someone in here might.

@chrisheninger
Copy link

image

Checking the network request's response shows rate-limit info.

If you're running the command you'll quickly find out you can only unlike ~500 tweets in a ~15 minute period (as of September 2023)

You'll need to wait for the limit to reset– you can copy/paste the timestamp into https://www.epochconverter.com/ to figure out when it will reset.

@jbreckmckye
Copy link

jbreckmckye commented Sep 18, 2023

Good find @chrisheninger! I guess then any script should take that into account

function nextUnlike() {
  return document.querySelector('[data-testid="unlike"]')
}

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function removeAll() {
  let count = 0
  let next = nextUnlike()
  while (next && count < 500) {
    next.focus()
    next.click()
    console.log(`Unliked ${++count} tweets`)
    await wait(count % 50 === 0 ? 30000 : 2000)
    next = nextUnlike()
  }
  if (next) {
    console.log('Finished early to prevent rate-limiting')
  } else {
    console.log('Finished, count =', count)
  }
}

removeAll() 

@Eggroley
Copy link

Eggroley commented Nov 3, 2023

Anyone have something that works for the old twitter layout? I currently can't see any past likes at all using the new twitter layout. Old one still shows them. Right now I'm using an extension to get the old look.

@xhapless
Copy link

Anyone have something that works for the old twitter layout? I currently can't see any past likes at all using the new twitter layout. Old one still shows them. Right now I'm using an extension to get the old look.

If you are using dimdenGD extension, you can use the below updated code. I just updated the querySelector .

function nextUnlike() {
  return document.querySelector('.tweet-interact-favorite.tweet-interact-favorited')
}

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function removeAll() {
  let count = 0
  let next = nextUnlike()
  while (next && count < 500) {
    next.focus()
    next.click()
    console.log(`Unliked ${++count} tweets`)
    await wait(count % 50 === 0 ? 30000 : 2000)
    next = nextUnlike()
  }
  if (next) {
    console.log('Finished early to prevent rate-limiting')
  } else {
    console.log('Finished, count =', count)
  }
}

removeAll()

@Eggroley
Copy link

Anyone have something that works for the old twitter layout? I currently can't see any past likes at all using the new twitter layout. Old one still shows them. Right now I'm using an extension to get the old look.

If you are using dimdenGD extension, you can use the below updated code. I just updated the querySelector .

function nextUnlike() {
  return document.querySelector('.tweet-interact-favorite.tweet-interact-favorited')
}

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function removeAll() {
  let count = 0
  let next = nextUnlike()
  while (next && count < 500) {
    next.focus()
    next.click()
    console.log(`Unliked ${++count} tweets`)
    await wait(count % 50 === 0 ? 30000 : 2000)
    next = nextUnlike()
  }
  if (next) {
    console.log('Finished early to prevent rate-limiting')
  } else {
    console.log('Finished, count =', count)
  }
}

removeAll()

Thanks! Works well

Unfortunately, now I'm at the point where posts don't even show likes. I have to like and unlike to remove them :/

Twitter is lame

@TheAbdusalam
Copy link

Thank you @aymericbeaumet appreciate it

@schmutzie
Copy link

Anyone have something that works for the old twitter layout? I currently can't see any past likes at all using the new twitter layout. Old one still shows them. Right now I'm using an extension to get the old look.

If you are using dimdenGD extension, you can use the below updated code. I just updated the querySelector .

function nextUnlike() {
  return document.querySelector('.tweet-interact-favorite.tweet-interact-favorited')
}

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function removeAll() {
  let count = 0
  let next = nextUnlike()
  while (next && count < 500) {
    next.focus()
    next.click()
    console.log(`Unliked ${++count} tweets`)
    await wait(count % 50 === 0 ? 30000 : 2000)
    next = nextUnlike()
  }
  if (next) {
    console.log('Finished early to prevent rate-limiting')
  } else {
    console.log('Finished, count =', count)
  }
}

removeAll()

Is there a way to have this first like, and then unlike tweets on the Likes page? The first script here left me with over 121K formerly liked tweets still counted and sitting under the Likes section. Only liking again and then unliking again fully removes them.

@trinlol
Copy link

trinlol commented Jan 1, 2024

Here is a version for likes, but you can specify tweets from a specific user to delete.

setInterval(() => {
  function removePostsByAuthor(authorHandle) {
    let posts = Array.from(document.querySelectorAll('.tweet'));
    posts.forEach(post => {
      let author = post.querySelector('.tweet-header-handle').textContent;
      if (author === authorHandle) {
        let likeButton = post.querySelector('.tweet-button.tweet-interact-favorite.tweet-interact-favorited');
        if (likeButton) {
          likeButton.click();
        }
      }
    });
  }

  // Call the function with the author's handle
  removePostsByAuthor('@USERNAME'); // Case sensitive (must match exactly)
  window.scrollTo(0, document.body.scrollHeight)
}, 1000)

Here is a version for retweets, but you can specify tweets from a specific user to delete.

setInterval(() => {
function removePostsByAuthor(authorHandle) {
  let posts = Array.from(document.querySelectorAll('.tweet'));
  posts.forEach(post => {
    let author = post.querySelector('.tweet-header-handle').textContent;
    if (author === authorHandle) {
      let tweetButton = post.querySelector('.tweet-button.tweet-interact-retweet.tweet-interact-retweeted');
      if (tweetButton) {
        tweetButton.click();
        let retweetMenu = tweetButton.parentElement.querySelector(".tweet-interact-retweet-menu-retweet");
        if (retweetMenu) {
          retweetMenu.click();
        }
      }
    }
  });
}

// Call the function with the author's handle
removePostsByAuthor('@USERNAME'); // Case sensitive (must match exactly)
  window.scrollTo(0, document.body.scrollHeight)
}, 1000)

Probably a better way to do this, but it works.

Must be using the old twitter extension as the above post's OldTwitter - Easier to get element IDs.

@danielwagn3r
Copy link

Made a little modification, which adds a page scroll to load futher likes in case you've got really many of them

function nextUnlike() {
  return document.querySelector('[data-testid="unlike"]');
}

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function removeAll() {
  let count = 0;
  let next = nextUnlike();
  while (next && count < 500) {
    try {
      next.focus();
      next.click();
      console.log(`Unliked ${++count} tweets`);
      await wait(count % 50 === 0 ? 60000 : 10000); // Increased wait times
      next = nextUnlike();
      if (!next && count < 500) {
        window.scrollTo(0, document.body.scrollHeight); // Scroll to the bottom of the page
        await wait(10000); // Increased wait time for more tweets to load
        next = nextUnlike(); // Get the next unlike button
      }
    } catch (error) {
      console.error('An error occurred:', error);
      break;
    }
  }
  if (next) {
    console.log('Finished early to prevent rate-limiting');
  } else {
    console.log('Finished, count =', count);
  }
}

removeAll();

@captainhook
Copy link

Is there a way to have this first like, and then unlike tweets on the Likes page? The first script here left me with over 121K formerly liked tweets still counted and sitting under the Likes section. Only liking again and then unliking again fully removes them.

I'm facing this issue now too. You could possibly run the script to first go and like a few hundred tweets and then after that a script to unlike them again. Or you'd have to create a counter around document.querySelector and loop through that.

@celine1OF1
Copy link

Screenshot 2024-01-10 091055
why arent the rest of my likes showing?

@captainhook
Copy link

Plenty of people above having the same issue with no definitive reasoning. Could be rate limiting, could be free tier limits, could be API bug, could be something else.

@h0jeZvgoxFepBQ2C
Copy link

This works fine for me:

setInterval(() => {
  const d = document.querySelector('div[data-testid="unlike"]')
  if(d) {
    d.click()
  } else {
    window.scrollTo(0, document.body.scrollHeight)
  }
}, 1000)

@Valx01P
Copy link

Valx01P commented Jan 29, 2024

Damn twitter API, these rate limits suck, how am I supposed to delete my socially incriminating twitter history if it only let's me remove 20 likes using a script before it stops letting me, twitter needs to implement an API endpoint to just remove all likes, tweets, retweets, etc. There is no way I'm gonna be able to remove thousands of likes manually lmao

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment