Hi all,

Calls to the 2/users/:id/liked_tweets endpoint returns IDs for tweets that are are not ‘liked’ by the user that the bearer token represents.

This seems to be part of a larger issue. Tweets that are not liked also show up in the web UI of the user. In other words the web UI lists Tweets that the user has not liked.

Using the API call DELETE to endpoint 2/users/:id/likes/:tweet_id does not clear the liked state.

Liking and unliking the Tweet does not clear the liked state.

The end result is there are Tweets that can not be removed from the user’s list of liked Tweets through the API.

I have attached an example from my own time line. The Tweet ID of the example in the screen shot is 1449917605918253057. I can only attach two images because I am a new user of the forum


This stuff is usually some eventual consistency issues - i’ve noticed likes sometimes disappear like that too.

Hi @IgorBrigadir, I thought that too but these ‘ghost-likes’ (I can’t think what else to call likes I can’t remove from my twitter timeline) have persisted for over a week now.

The Tweet IDs show up again and again in the response to the API v2 endpoint.

Thanks,
rdp

1 Like

I found this older post on the forum that indicates that unliking a Tweet through the API that is past (older?) the 3,200 most recent Tweet you liked might not work?

@jessicagarson is there any update on being able to interact with these older tweets through the API?

Thanks,
rdp

1 Like

After a while (no idea about the duration), I noticed many times the like state disappear on a tweet I liked a long time ago, same for retweets. And funny enough, on the retweet case, I was able to retweet it again, and I appeared twice in the retweets list endpoint (in v1.1 ; haven’t tested yet if I would appear twice in v2 listings).

That being said, I managed to find your like via the liking_users endpoint, 36th result in the 12th page (with max_results=100), or directly accessible there in only one request:
https://api.twitter.com/2/tweets/1449917605918253057/liking_users?max_results=1&pagination_token=7140dibdnow9c7btw480xowjooxgcyt2e31b0e82ezb5g
Among 2286 public likes I could retrieve, your like was listed in the 1023th position. I am not yet able to give you an approximate timestamp of when it was done.

I’m not saying that you (owner of the account) liked the tweet before, but if you are sure you never liked it before, even via a mistap on a touch screen, it may have been liked maliciously through tokens with write+ permissions. I’ve already witnessed it with the RoundYearFun app, they were regularly making people follow accounts they never heard of before. Twitter took down their successive apps relentlessly, but they were very persistent & motivated, managing to reborn many times.

But I have to agree that having the like permanently listed in your likes list without being able to unlike it later is regretful; especially during those times where a past opinion &/or activity could get someone cancelled, sometimes without even considering any public apology that could be made to address the concerns. Note: this is not representative nor the entirety of my opinion on cancel culture, just a glimpse at this specific case that could occur to anyone, possibly without their knowledge if done maliciously as I described in the previous paragraph.

2 Likes

Thanks for taking a look. And thanks for pointing out where I can clarify the context.

In my case, the tweets that can’t be removed from the list of liked tweets were all manually (ie through the app/web site, not API) liked.

The status of a tweet being liked by a user doesn’t seem to be a simple binary. For example in the web UI these un-deletable ghost-likes are in my timeline as liked don’t not have the ‘heart’ indicator toggled ‘on’. It makes sense given the scale of Twitter that the status of a like is more complex than just a list of IDs in some DB.

However, the subtle interactions of the complex backend and the API still aren’t clear in the documentation.

Again, thanks for taking a look. I appreciate it.

rdp

1 Like

Thanks for reaching out. @notpickard, I was just catching up on this thread and wondered if you had an example of a Tweet you were seeing liked that wasn’t captured via the endpoint? Was this an older Tweet?

I’m also interested in getting your feedback on improving our documentation moving forward.

Thanks again!
Jessica

1 Like

Hi @jessicagarson,

Thank you for taking the time to circle back around.

I’ve attempted to document an example of a “ghost-like” that I can’t remove from the timeline. I’ve included as much supporting information as I can think of but please let me know if there is more I can provide.

As a bit of app background in case it is helpful, the registered twitter app is a Native App. My Python code is using a slightly modified version of pytwitter-2 to mediate API access. It is using OAuth2 for authenticating a user context. The OAuth2 authentication is requesting the following scopes.

"tweet.read", "tweet.write", "users.read", "tweet.read", "users.read", "like.write", "like.read", "follows.read", "follows.write", "offline.access"

The API requests I am making all return 200 status codes. My modified pytwitter-2 takes care of refreshing access tokens that expire and pausing when rate limits get hit.

The app I am running is supposed to go through an authenticated user’s timeline an unlike all of liked the Tweets.

The app worked fine for my (I have been using this with my account) most recent Tweets. Recent tweets were unliked as expected.

However at some point the api call to get all liked tweets started returning IDs that when deleted through the API would not be removed from my line. The tweets still show up in the web UI list of liked tweets, I am still listed in the users of that liked the tweet BUT the heart emoji is empty.

Subsequent runs of my script continue to return the IDs of the ghost-likes.

I tagged you after finding the note about tweets greater that 3200 having some odd interactions with the API. Anecdotally that seemed to be consistent with my script working (tweets correctly unliked) for the most recent but then no longer being effective.

The API documentation doesn’t note this the 3200 limitation, if that is the cause.

(Thanks for reading through all of that table-setting)

Here is an example,

Tweet ID: 1488909815388811266
My twitter ID: 934627337701920768

Here is the Tweet in my likes list. Note the empty heart emoji

Here is a screen shot with the tweet ID in the URL

This is the logging output of my script. I highlighted the tweet id 1488909815388811266. It is in the list of liked IDs as well as in the API call to DELETE. The DELETE API call returns status code 200

Screen Shot 2022-02-02 at 3.22.34 PM

Here is the output of a second run of the script (you can see the time codes on the left). Tweet 1488909815388811266 is returned again, after the DELETE in the list of likes

So that is the problem I am seeing.

As a side note, tweet 1488909815388811266 and it’s other ghost-likes have persisted for over 2 weeks. I’ve been tinkering but that is always the first in the list. I am mentioning this as the persistence does not seem to be cleared up after some time has passed. In other words, to me, it doesn’t indicate that the DELETE was acknowledged but hasn’t been processed because of some batching or similar process.

Tweet 1488909815388811266 is just an example. All of the tweets in my likes list at the moment seem to have this problem.

If I like a tweet “now” and run my script, the newly like tweet is un-liked as expected. So this behavior seems only apply to tweets after some threshold.

Anyway, thanks again for circling back.

rdp

2 Likes

Thanks for this! I’m going to talk to the team and explore what might be happening here. I’m not sure if this is related to the 3200 issue, but I’ll let you know if that’s the case. Since that post is older, I’m not 100% sure that’s still an issue, but I’ll explore that as well.

1 Like

Thank you, any information clarifying the unexpected behavior would be helpful to me.

Just for a bit more context the ghost-like happens on relatively recent tweets as well. Here is an example from Dec 2021, ID 1468326525883846663. It’s in my likes, but not “hearted” and can’t be deleted from the timeline through the API.

I had not noticed that the tweet in my previous example was over 2 years old. I just happened to be the one at the top of the list.

Thanks again,
rdp

Hi @notpickard,

I talked to some folks internally. Likely if you manually like the Tweet on the timeline by clicking the heart, then remove the like by clicking the heart, it will remove the like. So you are correct that this is related to the 3200 Tweets issues you noticed. We’re going to consider documenting this further and see if there is another solution as well.

Thanks for bringing this to our attention.

1 Like

I see. Thank you for the follow up.

I will try liking and unliking through the API.

It’s my opinion that adding the 3200 threshold to the documentation would be helpful. With out knowing about that threshold it seems there is a bug somewhere.

Thanks again,
rdp

Liking and unliking seems to be working. Thank you for the idea @jessicagarson and team.

A couple of stray observations;

  • The endpoint rate limits work as I hoped but wasn’t entirely clear from documentation. Specifically, the call POST /2/users/:id/likes and DELETE /2/users/:id/likes/:tweet_id are not using the same limit counters. I can make 50 POST and 50 DELETE before getting the 429. This is what I was hoping for, but wasn’t 100% sure would be the case because the paths of the endpoints are so similar. Anyway, I’m glad for that.

  • The POST and DELETE calls do each count towards the monthly Tweet Cap Usage. Liking the tweet and then unliking counts as 2 “units”. In my case this is fine because 2 million is way above my current needs. Still I was not entirely sure from documentation if since it was 2 calls on the same tweet ID if that would be one “unit” or two from the total cap.

(before the unlike script runs)

(after the script runs. Only 50 tweets were unliked due to rate limit but it counted as 100 tweet accessed)

Hopefully this will be helpful if someone comes up against the 3200 threshold.

Thanks again for the idea,
rdp

2 Likes

Thanks for this! We’ll explore making further changes to our documentation based on these observations.

2 Likes