If you're working with Tweepy to stream tweets from the Twitter (now X) API and encounter AttributeError: module 'tweepy' has no attribute 'StreamListener', it means your code is using a deprecated class that no longer exists in modern versions of Tweepy.
In this guide, we'll explain why this error occurs, show the old code that causes it, and walk you through the exact migration steps to fix it using Tweepy's current streaming API.
Why Does This Error Occur?
The StreamListener class was part of Tweepy's original streaming implementation, which relied on Twitter API v1.1. Starting with Tweepy 4.0, the library underwent significant changes to align with Twitter API v2:
tweepy.StreamListenerwas removed entirely.tweepy.Stream(which used OAuth 1.0a) was replaced bytweepy.StreamingClient(which uses a Bearer Token).- The filtering mechanism changed from passing parameters to
filter()to using stream rules managed server-side.
If you run old code that references StreamListener with Tweepy 4.x or later, you'll see:
AttributeError: module 'tweepy' has no attribute 'StreamListener'The Old Code That Causes the Error
Here's a typical example of the deprecated streaming pattern:
import tweepy
class MyStreamListener(tweepy.StreamListener): # ❌ StreamListener no longer exists
def on_status(self, status):
print(status.text)
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
listener = MyStreamListener()
stream = tweepy.Stream(auth=auth, listener=listener)
stream.filter(track=['python'])Output:
AttributeError: module 'tweepy' has no attribute 'StreamListener'How to Fix It: Migrating to StreamingClient
The modern replacement uses tweepy.StreamingClient with a Bearer Token for authentication and tweepy.StreamRule for defining what tweets to track.
Step 1: Update Tweepy
First, make sure you have the latest version of Tweepy installed:
pip install --upgrade tweepyVerify the installed version:
import tweepy
print(tweepy.__version__) # Should be 4.x or laterStep 2: Rewrite Your Streaming Code
✅ Correct: Updated code using StreamingClient:
import tweepy
class MyStream(tweepy.StreamingClient):
def on_tweet(self, tweet):
print(tweet.text)
def on_error(self, status_code):
if status_code == 429:
print("Rate limited. Disconnecting...")
return False # Returning False disconnects the stream
print(f"Error: {status_code}")
bearer_token = "YOUR_BEARER_TOKEN"
stream = MyStream(bearer_token)
stream.add_rules(tweepy.StreamRule("python"))
stream.filter()Key Differences Between Old and New API
| Feature | Old API (StreamListener) |
New API (StreamingClient) |
|---|---|---|
| Class to inherit | tweepy.StreamListener |
tweepy.StreamingClient |
| Authentication | OAuth 1.0a (OAuthHandler) |
Bearer Token |
| Twitter API version | v1.1 | v2 |
| Tweet callback method | on_status(self, status) |
on_tweet(self, tweet) |
| Filtering | stream.filter(track=['...']) |
stream.add_rules(StreamRule('...')) |
| Tweet text access | status.text |
tweet.text |
Managing Stream Rules
One important difference with the new API is that stream rules are persistent on the server. This means rules you add remain active even after your script stops. You should manage them carefully.
Adding Rules
stream.add_rules(tweepy.StreamRule("python"))
stream.add_rules(tweepy.StreamRule("machine learning"))Viewing Existing Rules
rules = stream.get_rules()
print(rules)Deleting Rules Before Adding New Ones
To avoid accumulating old rules, clear them before adding new ones:
existing_rules = stream.get_rules()
if existing_rules.data:
rule_ids = [rule.id for rule in existing_rules.data]
stream.delete_rules(rule_ids)
print(f"Deleted {len(rule_ids)} existing rules.")
stream.add_rules(tweepy.StreamRule("python programming"))Complete Working Example
Here's a full, production-ready example with proper error handling and rule management:
import tweepy
class TweetStreamer(tweepy.StreamingClient):
def __init__(self, bearer_token, max_tweets=10):
super().__init__(bearer_token)
self.tweet_count = 0
self.max_tweets = max_tweets
def on_tweet(self, tweet):
self.tweet_count += 1
print(f"[{self.tweet_count}] {tweet.text[:100]}")
if self.tweet_count >= self.max_tweets:
print("Reached max tweets. Disconnecting.")
self.disconnect()
def on_error(self, status_code):
print(f"Stream error: {status_code}")
if status_code == 429:
return False # Disconnect on rate limit
def on_connection_error(self):
print("Connection error. Reconnecting...")
def main():
bearer_token = "YOUR_BEARER_TOKEN"
stream = TweetStreamer(bearer_token, max_tweets=20)
existing_rules = stream.get_rules()
if existing_rules.data:
stream.delete_rules([rule.id for rule in existing_rules.data])
stream.add_rules(tweepy.StreamRule("python"))
print("Starting stream...")
stream.filter(tweet_fields=["created_at", "author_id"])
if __name__ == "__main__":
main()Sample Output:
Starting stream...
[1] RT @dev_community: Check out this awesome Python tutorial for beginners...
[2] Just deployed my first Python web app using Flask! #python #webdev...
[3] Python 3.13 brings some amazing performance improvements...
...
[20] Learning Python has been the best decision of my career...
Reached max tweets. Disconnecting.Troubleshooting
Still Getting Errors After Updating Tweepy?
If updating doesn't resolve the issue, try a clean reinstall:
pip uninstall tweepy
pip install tweepyError: 403 Forbidden When Starting the Stream
This usually means your Twitter Developer account doesn't have the required access level. Twitter API v2 filtered stream requires at least Basic access. Check your access level in the Developer Portal.
Error: tweepy.errors.TooManyRequests
You've hit the rate limit. Wait a few minutes before restarting the stream, or reduce the number of rules.
Conclusion
The AttributeError: module 'tweepy' has no attribute 'StreamListener' error occurs because StreamListener was removed in Tweepy 4.0 as part of the migration from Twitter API v1.1 to v2. To fix it, replace tweepy.StreamListener with tweepy.StreamingClient, switch from OAuth 1.0a to a Bearer Token, and use StreamRule objects instead of passing track parameters directly to filter(). Always refer to the official Tweepy documentation for the latest API details, as Twitter's platform continues to evolve.