Creating a Twitter bot in Python using Twitter APIv2 🚀🚀
Tags: tutorial, python, api, twitter
Published: 2022-10-06 19:57:52

When I was migrating [@poet_this](https://twitter.com/poet_this) twitter bot to use the Twitter API v2, I wasn't able to find any good tutorials that do it, atleast none that worked properly. After the bot's success, many people reached out to me asking how they can also create a twitter by themselves! I'm here to help :)

## 🤔 What we're building
Let's create a twitter bot that replies whenever someone mentions the bot. To keep this simple, we'll just reply with the same text but capitalized.

What we wanna do:
(original_uploader): This is a cool tweet
(commenter): @ bot (*mentions the bot)
(bot): THIS IS A COOL TWEET

At the end of this tutorial, I'll also include ways to add more cool features to this, and some ideas for your own cool twitter bot!

## ⚡ Getting started

First of all, you'll need a Twitter developer account. Sign up for one on [Twitter Developer dashboard](https://developer.twitter.com/en/portal/dashboard)

[Here's a step-by-step guide by Twitter](https://developer.twitter.com/en/docs/tutorials/step-by-step-guide-to-making-your-first-request-to-the-twitter-api-v2)



Alright, once we're done with that...

Let's create a new python project! 

## Setting up the project
I recommend working in a virtual environment. Create a new folder, and open the terminal and use this command
```
python -m venv env
```
```
env/Scripts/activate // on windows
source env/bin/activate // on linux
```

Finally we just need to install the dependencies,
```
pip install python-dotenv python-twitter-v2
```

That is the only two dependencies we really need right now. python-dotenv to use environment variables, and python-twitter-v2 to interact with the twitter API!

## 🔐 Authenticating with Twitter

To authenticate with the twitter API with the bot's twitter account, we'll need a few things...
- Consumer key (From developer dashboard)
- Consumer secret (From developer dashboard)
- Access token
- Access token secret

Technically you can also use a bearer token, but let's keep it simple for now.

To get access token and secret (for testing), you can create them in the dashboard here:

![Access token and secret](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sftslsr71fzxi552g7cy.png)

Make sure that you have the Read and Write permissions, we need that for the bot.

(If you want to control another account, for example, a bot account, follow these steps to get the access token/secret for another account - https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens)

Once we have all these tokens, create a file, `.env` and fill it in, in this fashion -
```
CONSUMER_KEY=...
CONSUMER_SECRET=...
ACCESS_TOKEN=...
ACCESS_TOKEN_SECRET=...
```

## 👨🏻‍💻 Let's start with the code now!
Let's break the problem into little pieces...

We want to,
- Authenticate with Twitter API
- Listen for all mentions
- Reply!

Cool, first, let's authenticate
```py
import pytwitter
from os import environ as env
from dotenv import load_dotenv

load_dotenv() # Loads the .env file we created earlier

api = pytwitter.Api(
    consumer_key=env["CONSUMER_KEY"],
    consumer_secret=env["CONSUMER_SECRET"],
    access_token=env["OAUTH_TOKEN"],
    access_secret=env["OAUTH_TOKEN_SECRET"],
)
```

You can check if the bot is properly authenticated by using some endpoint, for example,
```py
print(api.get_user(username="Twitter"))
# Should print Response(data=User(id='783214', name='Twitter', username='Twitter'))
```

Now let's listen for mentions.
There's one thing to keep in mind though - we don't want to reply to ALL mentions. This is because how Twitter works.

Let's say, I make a tweet and someone comments on it
`@DhravyaShah`: Hello world!
`@SomeOtherRandomUser`: Hi Dhravya!

But, instead of just being "Hi Dhravya", it looks like this-
`@DhravyaShah`: Hello world!
`@SomeOtherRandomUser`: @DhravyaShah Hi Dhravya!

Notice the difference? This can be a problem in a twitter bot, where it will reply even to the comments under the bot.
We'll fix this by checking if the text is ONLY mentioning the bot, and nothing else. 

How? Just remove all the mentions and check for an empty string!

```py

last_tweet_id = 0 # Just a variable to keep track of the last tweet we replied to.

if __name__ == "__main__":

    while True:
        try:
            mentions = api.get_mentions(
                user_id=str(BOT_ID), # get bot id from tweeterid.com
                return_json=True,
                since_id=str(last_tweet_id),
                tweet_fields=[
                    "conversation_id",
                    "entities"
                ]
            )
        

            if not isinstance(mentions, dict):
                continue
```

Cool, now we get a constant stream of mentions, well not really. We get all the mentions after `since_id`. 

These mentions actually contain a LOT of data. I wanna keep it short so I won't get into the details, but feel free to `print()` this once and look through all the fields provided!

Now let's check if there's any `data` and it has the `includes` too (`includes` has all the extra entities)

```py

    if not "data" in mentions.keys():
        continue # There's no more tweets
    
    for tweet in mentions["data"]:
        text = tweet["text"]
        reply_to = tweet["id"]

        # If it's not a reply to another tweet
        if not (tweet["conversation_id"] == tweet["id"]):
            if str(tweet["in_reply_to_user_id"]) == str(BOT_ID):
                continue
            
            # Get the parent tweet
            tweet_ = api.get_tweet(return_json=True,tweet_id=tweet["referenced_tweets"][0]["id"])
            text = tweet_["text"]


        # If tweet is a reply, it's in the format "@user @user @bot"
        users = [
                  mention["username"] for mention in tweet["entities"]["mentions"]
        ]
        new_txt = tweet["text"]
        # Remove all mentions in the start
        for user in users:
            new_txt = new_txt.replace(f"@{user}", "")

        new_txt = new_txt.strip()
```

If `new_txt` is "" (empty), that means it's a "direct mention" - just a "@bot" comment. If it's a direct mention, the bot has been explicitly called, which means we can respond.


```py

if (new_txt == ""):
    api.create_tweet(text=text.upper(), reply_in_reply_to_tweet_id = reply_to

```


And finally, let's close the loop and also update the last_tweet_id to the new, last_tweet_id
```py

            if "meta" in mentions.keys():
                if "newest_id" in mentions["meta"].keys():
                    last_tweet_id = mentions["meta"]["newest_id"]

    time.sleep(10)
```

That's basically it! Here's the full code in a [Github gist](https://gist.github.com/Dhravya/0bdc77bbdece07204afad9219f39e7da)

{% embed https://gist.github.com/Dhravya/0bdc77bbdece07204afad9219f39e7da %}

You can add more features to the bot my adding "Keywords", just like how [@poet_this](https://twitter.com/poet_this) works on twitter - The comment "`@poet_this blue 2`" (blue 2 being the keyword) generates that particular style of image.

## Finally...
This was just a quick rundown, but now...
Try making a bot yourself! It's a very fun and rewarding process, and you'll learn a lot through it. 

Thanks for reading!
You can support me by sponsoring me on Github - https://github.com/sponsors/Dhravya
You can follow me on Twitter - https://twitter.com/dhravyashah