Tutorial: Creating a Twitter (X) Bot using Python
Published at Oct 6, 2024
During my last semester at university, I found myself overwhelmed by the workload and the feeling that time was standing still. To cope, I decided to create a simple X bot that would remind me of the semester’s progress by tweeting the percentage of time that had passed. I’ll walk you through building your own X bot using Python and the X API, complete with scheduling and image generation.
This tutorial is up-to-date as of
October 2024February 2025May 2025 using the new X API. If you are reading this in the future, please check the official documentation for any changes.
Here is an example tweet from the bot:
🔴 ODTÜ'de 2024-2025 bahar dönemi ilerlemesi: %100
— odtü dönem ilerlemesi (@OdtuSemesterBot) May 30, 2025
Finallerde başarılar! pic.twitter.com/L6cYeAGE30
I know most of my audience doesn’t speak Turkish, but the tweet simply says that the semester has progressed by 100%.
You can reach the source code of the project from my github repository.
Structure
Features
- Post a tweet autonomously.
- Schedule the bot to tweet at a specific time, you can also set the interval.
- Create a beautiful progress graph that shows the progress of the semester.
- Completely free to deploy and use.
Getting Started
First, you need to create an X account for your bot. Then, you need to sign-in to the X Developer Portal and create a new project. After creating a project, you need to create an app and get the API keys.
Now, copy all of these keys and paste them into a .env
file in the root directory of your project. Here is an example of the .env
file:
API_KEY=YOUR_API_KEY
API_KEY_SECRET=YOUR_API_KEY_SECRET
BEARER_TOKEN=YOUR_BEARER
ACCESS_TOKEN=YOUR_ACCESS_TOKEN
ACCESS_TOKEN_SECRET=YOUR_ACCESS_TOKEN_SECRET
Hint: Notice that we ignore the
.env
file in the.gitignore
file so that we don’t share our keys with the public.
Requirements
First, you can find the required libraries in the requirements.txt
file. You can install them by running:
pip install -r requirements.txt
I will explain why we need each required library:
tweepy
: Tweepy is an easy-to-use Python library for accessing the X API.python-dotenv
: Reads the key-value pair from.env
file and adds them to the environment variable.matplotlib
: We use these libraries to create the graph that shows the progress of the semester.
Writing the Bot
- We set up basic logging to see the logs of the bot:
# Setup basic logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
- Then, I have a function that calculates how many seconds have passed since the beginning of the semester and how many seconds are left until the end of the semester. Then I calculate the percentage of the semester that has passed. Pretty simple, right?
def calculate_percentage(start_date, end_date):
now = datetime.now()
if now < start_date:
return 0
elif now.date() == (end_date - timedelta(days=1)).date():
return 100
total_seconds = (end_date - start_date).total_seconds()
elapsed_seconds = (now - start_date).total_seconds()
percentage = round((elapsed_seconds / total_seconds) * 100, 2)
return int(percentage) if percentage.is_integer() else percentage
The progress graph is created using
matplotlib
library and saved to a PNG file. (Check the source code for details.)I have two functions that connect to the X API and post the progress image on X:
def connect_twitter() -> tuple:
"""
Connect to the Twitter API using Tweepy and environment variables.
Returns:
tuple: A tuple containing the Twitter client and API instances.
"""
load_dotenv()
tweepy_auth = tweepy.OAuth1UserHandler(
os.getenv("API_KEY"),
os.getenv("API_KEY_SECRET"),
os.getenv("ACCESS_TOKEN"),
os.getenv("ACCESS_TOKEN_SECRET"),
)
api = tweepy.API(tweepy_auth)
client = tweepy.Client(
os.getenv("BEARER_TOKEN"),
os.getenv("API_KEY"),
os.getenv("API_KEY_SECRET"),
os.getenv("ACCESS_TOKEN"),
os.getenv("ACCESS_TOKEN_SECRET"),
)
logging.info("Connected to Twitter API")
return client, api
def post_photo():
"""
Generate and post a progress image on Twitter with the remaining days and progress.
"""
client, api = connect_twitter()
remaining_days = (END_DATE - datetime.now()).days
percentage = calculate_percentage(START_DATE, END_DATE)
img_path = create_progress_image(percentage)
text = f"🔴 ODTÜ'de 2024-2025 bahar dönemi ilerlemesi: %{percentage}"
media = api.media_upload(filename=img_path)
client.create_tweet(text=text, media_ids=[media.media_id])
logging.info("Successfully posted progress image on Twitter")
- Finally, I have a main section that handles how the bot runs, and it includes a simple CLI interface.
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Post semester progress on Twitter or view percentage."
)
parser.add_argument(
"--percentage-only",
action="store_true",
help="Only show the current percentage and exit.",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Run everything except actually posting to Twitter.",
)
args = parser.parse_args()
percentage = calculate_percentage(START_DATE, END_DATE)
if args.percentage_only:
print(f"Current progress: %{percentage}")
else:
client, api = connect_twitter()
logging.info(f"Dry run: {args.dry_run}")
remaining_days = (END_DATE - datetime.now()).days
img_path = create_progress_image(percentage)
text = f"🔴 ODTÜ'de 2024-2025 bahar dönemi ilerlemesi: %{percentage}"
if args.dry_run:
logging.info(
"Dry run mode: Image would be posted with the following content:"
)
logging.info(f"Text: {text}")
logging.info(f"Image path: {img_path}")
else:
media = api.media_upload(filename=img_path)
client.create_tweet(text=text, media_ids=[media.media_id])
logging.info("Successfully posted progress image on Twitter")
This block allows you to use the script from the command line with two optional arguments:
--percentage-only
: Prints the current progress percentage and exits. Useful for debugging or using the percentage elsewhere.
python main.py --percentage-only
--dry-run
: Runs the full process (calculating, generating image, preparing the tweet) but does not post anything to X. It logs what it would post instead.
python main.py --dry-run
- If you run the script without any arguments, it will calculate the percentage, create the image, and tweet it directly:
python main.py
Deployment
I deployed the function using GitHub Actions. The bot runs daily and posts the progress image on X. You will first need to secrets we use to the Github:
- Go to your Github Repository.
- Go to settings.
- Go to secrets and variables, select actions.
- Click “New Repository Secret” for each of the environment variables.
Then add the “daily_twitter_post” yaml file to ./.github/workflows Here is the daily_twitter_post.yml file:
name: Daily Twitter Post
on:
schedule:
- cron: "0 15 * * *" # Runs daily at 18:00 in Turkiye time
workflow_dispatch: # Allows manual triggering
jobs:
post_tweet:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run script
env:
API_KEY: ${{ secrets.API_KEY }}
API_KEY_SECRET: ${{ secrets.API_KEY_SECRET }}
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
ACCESS_TOKEN_SECRET: ${{ secrets.ACCESS_TOKEN_SECRET }}
BEARER_TOKEN: ${{ secrets.BEARER_TOKEN }}
run: python main.py
Once the workflow is set up:
- Automatic schedule: The bot tweets every day at the time you specify in the
cron
line.- Want a different schedule? Change the cron expression to run hourly, weekly, monthly—whatever you need.
- Manual trigger: Open your repository’s Actions tab and click Run workflow to post on demand.
Conclusion
This project is just the beginning. You can extend the bot to post about other events or even integrate it with other APIs. I encourage you to explore different ways to make this bot more interactive. Have fun experimenting, and feel free to reach out with any questions or feedback!