Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Troubleshooting Automated DMs with Python’s Twikit Package – Avoiding the “Looks Automated” Error (Code 226) #247

Open
desktop69 opened this issue Oct 31, 2024 · 10 comments

Comments

@desktop69
Copy link

Hello everyone! 👋

I’m currently working on a Twitter bot using Python and the Twikit package. The goal is to target specific users and send them a direct message (DM) only if there’s no prior DM history with them.

Here’s the core problem: occasionally, I get the following error when trying to send DMs:
Error sending DM to <User id="01010101">: status: 403, message: "{"errors":[{"code":226,"message":"This request looks like it might be automated. To protect our users from spam and other malicious activity, we can't complete this action right now. Please try again later."}]}"

I’ve tried adding various delays and even appended random characters to the end of each message to make it look more “human.” However, the error still occurs frequently enough to interrupt the bot’s workflow.

Code Context
Below is the main code segment of my bot (simplified for readability)

`import asyncio
import random
import string

async def main():
# Code to initialize and authenticate client
messages_sent = 0

for user_id in users_target:
    print("********************************")
    print("Message sent so far:", messages_sent)
    
    # Generate a message with random characters at the end
    textmessage = f"{base_message}{random.choice(string.ascii_lowercase)}.{random.choice(string.ascii_uppercase)}"
    
    # Random delay between 10 and 15 seconds
    random_delay = random.randint(10, 15)
    print(f"Delay before checking DM history: {random_delay} seconds")
    await asyncio.sleep(random_delay)

    # Check DM history
    print("User screen name:", user_id.screen_name, "User ID:", user_id.id)
    has_dm = await has_dm_history(client, user_id)
    print("Has DM history:", has_dm)
    
    if not has_dm:
        try:
            # Delay before sending DM
            random_delay_before_dm = random.randint(7, 15)
            print(f"Delay before sending DM: {random_delay_before_dm} seconds")
            await asyncio.sleep(random_delay_before_dm)
            
            # Send the DM
            await client.send_dm(user_id.id, textmessage)
            messages_sent += 1
            print(f"DM sent to user: {user_id}")

            # Delay after each message
            random_delay_afrmsg = random.randint(35, 40)
            print(f"Delay after sending message: {random_delay_afrmsg} seconds")
            await asyncio.sleep(random_delay_afrmsg)

            # Longer delay after every 12 messages
            if messages_sent % 12 == 0:
                print("Sent 12 messages, waiting for 10 minutes.")
                await countdown_sleep(DELAY_BETWEEN_12_MSGS)

        except Exception as e:
            print(f"Error sending DM to {user_id}: {e}")
            # Delay after error
            random_delay_on_error = random.randint(7, 10)
            print(f"Delay after error: {random_delay_on_error} seconds")
            await asyncio.sleep(random_delay_on_error)
    
    print("********************************")

`

Strategies I’ve Tried So Far

  • Random Delays: Adding randomized delays between different stages of the DM workflow, as well as a longer delay after every 12 messages to avoid rate-limiting issues.

  • Message Randomization: Adding a random character (both uppercase and lowercase) at the end of each message to make it look less predictable.

The Persistent Issue:

Despite these efforts, I still receive a 403 error with Code 226, suggesting that Twitter’s anti-spam mechanism detects these requests as automated.
Questions for the Community

  • Are there any other effective techniques for bypassing this error?
  • Does anyone have experience working with Twikit and can suggest additional strategies?
  • Is there a way to further randomize the DM process (perhaps a different approach to message randomization)?

Any help or insight would be much appreciated. Thanks in advance for reading, and I’m looking forward to hearing your suggestions!

@ethmtrgt
Copy link

ethmtrgt commented Nov 6, 2024

Hello, do you use proxies? If so, what type of proxies do you use (datacenter, residential etc)?

@shindodkar
Copy link

@desktop69
i'm also getting kinda same errors.

twikit.errors.BadRequest: status: 400, message: "{"errors":[{"code":366,"message":"flow name LoginFlow is currently not accessible"}]}"

@desktop69
Copy link
Author

Hello, do you use proxies? If so, what type of proxies do you use (datacenter, residential etc)?

Hi! Yes, I'm currently working on the proxy setup. I did some research and even spoke with support at Oxylabs, where they recommended regional proxies. However, they're quite expensive—about $100 per month for 8GB of data, which is a bit much for me. I also got advice online to consider using a torrent-based proxy, but I haven’t figured out how to find or integrate this kind of proxy with Twikit yet. If you have any insights on that, I’d really appreciate it. Thanks!

@desktop69
Copy link
Author

@desktop69 i'm also getting kinda same errors.

twikit.errors.BadRequest: status: 400, message: "{"errors":[{"code":366,"message":"flow name LoginFlow is currently not accessible"}]}"

For this type of issue, the Twikit package author is still working on a solution. In the meantime, I found a workaround by bypassing the login feature using a Chrome extension called Cookies Editor. Just log in to your account on the web, then copy and paste the relevant values into an existing cookies file from Twikit. You’ll only need those specific values for it to work.
{"auth_token" "ct0": "guest_id" "guest_id_ads" "guest_id_marketing": "kdt": "personalization_id":""\ value here"" twid}
and good luck

@ethmtrgt
Copy link

ethmtrgt commented Nov 7, 2024

@desktop69; I am trying to figure out what triggers the looks automated error. I was automating twitter for more than three years without any issues then this appeared. I did so many tests recently but I had no no luck unfortunately. Like testing more proxies, spoofing TLS fingerprint etc.

I noticed some static residential proxies don't trigger this error. They might be flagging IPs based on the previous activity. Just my thought, not 100% sure.

And not a solution but when you retry the failed action multiple times with 2-5 second intervals, it might be succeed.

@desktop69
Copy link
Author

@desktop69; I am trying to figure out what triggers the looks automated error. I was automating twitter for more than three years without any issues then this appeared. I did so many tests recently but I had no no luck unfortunately. Like testing more proxies, spoofing TLS fingerprint etc.

I noticed some static residential proxies don't trigger this error. They might be flagging IPs based on the previous activity. Just my thought, not 100% sure.

And not a solution but when you retry the failed action multiple times with 2-5 second intervals, it might be succeed.

Hey there, it's great to connect with someone who's been using Twitter automation for three years! I've just started getting into it over the past month. Would you mind sharing any insights on using proxies and what sources you’re using? I'm really struggling to figure it out.

@DanteKallen
Copy link

@desktop69; I am trying to figure out what triggers the looks automated error. I was automating twitter for more than three years without any issues then this appeared. I did so many tests recently but I had no no luck unfortunately. Like testing more proxies, spoofing TLS fingerprint etc.

I noticed some static residential proxies don't trigger this error. They might be flagging IPs based on the previous activity. Just my thought, not 100% sure.

And not a solution but when you retry the failed action multiple times with 2-5 second intervals, it might be succeed.

Hey bro, did you happen to find the problem yet?

@ethmtrgt
Copy link

@desktop69; I am using static residential proxies from Webshare. I wanted to reply after a few days of testing. So I figured out the problem isn't about the proxy, now I'm 90% sure it's about the x-client-transaction-id parameter in the header and account's spam score. I miss the old twitter before Elon it was the easiest social media to automate 😁.

@DanteKallen Unfortunately.

@desktop69
Copy link
Author

@desktop69; I am using static residential proxies from Webshare. I wanted to reply after a few days of testing. So I figured out the problem isn't about the proxy, now I'm 90% sure it's about the x-client-transaction-id parameter in the header and account's spam score. I miss the old twitter before Elon it was the easiest social media to automate 😁.

@DanteKallen Unfortunately.
Hey there! 😊 Thanks for sharing your experience and insights. I've done some research on this as well, and I found that the x-client-transaction-id doesn't seem to have a direct API call to retrieve it. It appears to be something generated on the frontend. Some folks online have even identified the generation context, which looks something like this:

   function Nn(e) {
        return async(n,t)=>{
            if (!Bn.test(n.host))
                return t(n);
            const a = {
                ...n
            };
            if (e.isTrue("rweb_client_transaction_id_enabled")) {
                const {method: e, path: t} = n;
                try {
                    a.headers["X-Client-Transaction-Id"] = await async function(e, n) {
                        xn = xn || new Promise((e=>{
                            d.e("ondemand.s").then(d.bind(d, 71269)).then((n=>e(n.default())))
                        }
                        ));
                        const t = await xn;
                        return await t(e, n)
                    }(function(e) {
                        return (e || "").split("?")[0].trim()
                    }(t), e)
                } catch (e) {
                    a.headers["X-Client-Transaction-Id"] = btoa(`e:${e}`)
                }
            }
            return t(a)
        }
    }

From https://abs.twimg.com/responsive-web/client-web/main.bfe3e92a.js.

Maybe you can continue from there.

I also inspected the header parameters used by the Twikit package and noticed that this variable is indeed missing. This could be a key factor in the issue. It's frustrating, right? Automating Twitter used to be so much more straightforward pre-Elon! 😅 Anyway, thanks again for testing and sharing your findings—it’s definitely helpful as we try to untangle this! 🚀

@019ec6e2
Copy link

Apparently, twikit already includes this header in the request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants