Building a Twitter bot with Python and Tweepy

Twitter may now be marketed as X, but its APIs still support focused automation projects built in Python. A bot can publish approved updates, surface relevant conversations or answer a limited set of questions. Tweepy provides a readable Python interface, while careful design keeps the account useful and understandable rather than a high-volume reply machine.

Successful projects begin with one measurable job and a clear owner. “Post daily release notes” or “notify the team when a keyword appears” are safer briefs than “engage with everyone.” Give the account a distinctive name, an honest profile and a way to opt out of automated contact. Human review is valuable whenever a post could affect customers, reputation or privacy.

The technical path is straightforward: create a developer application, obtain user-context credentials, install Tweepy in an isolated environment, write small API functions and schedule only necessary actions. SQLite can store tweet IDs and approval records, while structured logs capture failures. This separation allows local tests without sending public messages.

Australian audiences bring practical constraints worth considering early. Most checking happens on a phone during a commute, lunch break or gap between household errands, so mobile-readable posts and predictable timing matter. The project may serve small businesses, community organisations, clubs or independent creators, where transparent automation can distinguish a helpful service from an impersonal nuisance.

Defining the bot’s purpose and identity

Start by describing the trigger, audience and permitted action in plain English. “Every weekday at 8:00 a.m., publish the approved update from the content queue” is testable. “Be active on Twitter” is not. Include an emergency switch, a maximum posting rate and topics the bot must ignore. These boundaries become test assertions and give moderators an immediate way to stop a faulty run.

Give the bot its own account and make its identity visible. The profile image, biography, linked page and naming should explain who operates it and whether replies are automated. A restrained destination such as a simple landing-page example can inform the visual treatment of that public-facing identity without distracting from its main function. Keep sensitive configuration and moderation contacts private.

Creating secure API credentials

Use the current Twitter developer portal to register an application and check which API products and access tiers are available. Tweepy’s Client can authenticate with OAuth 1.0a user-context keys for posting, replying and reading the authenticated account. Search endpoints may also require a bearer token, and access to recent search can depend on the current paid tier or promotional allowance. Verify the live developer terms before designing around an endpoint.

Store keys outside source control. A small .env file is convenient during development, while a hosting secret store is better for production. Add .env, virtual environments and log files to .gitignore, give each environment separate credentials and never print tokens in exceptions.

CONSUMER_KEY=...
CONSUMER_SECRET=...
ACCESS_TOKEN=...
ACCESS_TOKEN_SECRET=...
BEARER_TOKEN=...

Load these values with python-dotenv and pass them to tweepy.Client when the process starts. If a token may have appeared in a public repository or log, revoke and rotate it immediately. Limit account privileges to the minimum needed and restrict configuration access to the people responsible for deployment.

Preparing a repeatable Python environment

Python 3.11 or a supported newer release provides access to current dependencies and security fixes. Create a virtual environment so packages do not alter the operating system, then install pinned versions of Tweepy and the dotenv library:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install tweepy python-dotenv

Keep source, configuration templates, tests and data in separate paths. Functions that construct a post should return plain text, while another layer performs the API call. This keeps content checks independent of Twitter. Include a README with setup steps and token names, but no real secrets. Link previews deserve similar caution: test an approved resource such as a visual design reference and confirm that automated requests to any third-party address are permitted.

Configuration should contain more than credentials. Store the approved time zone, maximum actions per run, account identifier and database path separately. Defaults can make dry-run mode the local choice. A small settings module can validate these values at start-up and stop with a clear message when something is missing, which is easier to diagnose than a traceback deep inside the posting function.

Writing focused posting and reply logic

Tweepy’s client methods map closely to the API. A first version can call get_me(), create one post and capture its identifier so later replies reference the correct tweet. Handle expected exceptions separately from programming errors, and make responses visible in development without exposing credentials.

import os
import tweepy

client = tweepy.Client(
    consumer_key=os.environ["CONSUMER_KEY"],
    consumer_secret=os.environ["CONSUMER_SECRET"],
    access_token=os.environ["ACCESS_TOKEN"],
    access_token_secret=os.environ["ACCESS_TOKEN_SECRET"],
    wait_on_rate_limit=True,
)

account = client.get_me()
created = client.create_tweet(text="Scheduled update: the new guide is live.")
tweet_id = created.data["id"]

client.create_tweet(
    text=f"@{account.data.username} The guide is live for the team.",
    in_reply_to_tweet_id=tweet_id,
)

Production code should treat a missing data attribute as a failed response. Expand this into separate functions for rendering text, selecting approved content, publishing and recording success. Key each database row by content identifier or scheduled slot to prevent duplicates. For mention handling, fetch only required fields, ignore retweets and repeated events, and skip replies that fail the matching rules.

Scheduling and operating the bot

A scheduler should invoke one idempotent command rather than carrying important state inside the cron process. On a Unix server, a cron entry can run every fifteen minutes and call a script that looks for due, approved content:

*/15 * * * * cd /srv/twitter-bot && .venv/bin/python bot.py --run-scheduled >> logs/cron.log 2>&1

A systemd timer offers stronger process supervision and clearer logs. Whichever option is used, the job should acquire a lock so two instances cannot publish the same item, write an audit record and return a non-zero status when an action fails. Keep the scheduler’s timezone explicit and convert from UTC where necessary.

Australian deployment makes time-zone handling especially important. Sydney and Melbourne observe daylight saving, while Brisbane remains on AEST, so a fixed local schedule can shift by an hour twice a year. Convert the intended Australian local time into the scheduler’s timezone for every run instead of hard-coding an offset. Publishing during established mobile-checking periods can improve visibility, but quiet-hour rules should reflect the audience’s location rather than the server’s location.

Rate limits and transient outages need controlled responses. Tweepy can wait for some rate-limit conditions, yet the application still needs exponential backoff for network errors, a retry ceiling and alert thresholds. Send a concise failure summary to the operator, retain the failed job in the queue and avoid publishing a fallback message that could be mistaken for fresh content. Monitor follower counts, reply sentiment and sudden increases in posting volume for signs of misuse.

Testing behaviour and link previews

Test text generation as ordinary Python code by mocking the Tweepy client. Cover empty input, long messages, duplicate content, mentions from blocked accounts and API failures. Then run a controlled end-to-end test with a project-owned account, publish clearly labelled test posts, verify that reply identifiers are correct and delete the test material afterwards. A dry-run mode should show exactly what would be sent without sending it.

For link-preview checks, use only URLs your team controls or has permission to test. An approved resource such as a controlled test destination should be confirmed with its owner before automated requests. Check that cards render as intended, redirects remain within the approved domain and a failed preview never causes the bot to repeat the post. Keep this check separate from posting logic so it can be disabled safely.

Before launch, review the platform’s current rules on automation, duplicate content, unsolicited replies and account safety. Label automated behaviour where required, avoid copying large amounts of third-party text and provide a clear route for complaints. Rate controls should be conservative, particularly when replying to people who did not request contact. A bot earns trust by being predictable and easy to stop; volume alone rarely creates a useful service.

Deploying responsibly in Australia

Package the application for a managed host or small virtual machine, then run it under a restricted operating-system user rather than as root. Separate build and release steps, keep dependencies reproducible and test a rollback before the first scheduled post. Keep a dashboard or status channel recording the last successful run, queue size and any action awaiting human approval.

These operational safeguards are the core recommendations for a dependable deployment:

Australian commercial and privacy obligations may apply beyond Twitter’s terms. The Spam Act 2003 can govern unsolicited commercial electronic messages, including some automated direct messages, making consent, sender identification and a working unsubscribe mechanism important. If the operator is covered by the Privacy Act 1988, the Australian Privacy Principles influence the collection, use, storage and disclosure of personal information. The Australian Consumer Law also matters when bot content promotes claims about products or services. These rules depend on the operator’s activities, so specific advice is important before sending campaigns or processing customer data.

For a local business, community project or sporting club, a well-governed bot can handle repetitive announcements while people concentrate on service and participation. For an individual creator, it can reduce repetitive publishing work without creating an anonymous stream of posts. Clear ownership, measured frequency and accurate disclosure make automation understandable to Australian audiences, while a human owner remains accountable for every action the account takes.

Contact