Twitch Viewbot Detector
This utility monitors a Twitch channel to detect potential viewbotting. It calculates the Engagement Rate by comparing the number of active chat messages against the concurrent viewer count. A very high viewer count with disproportionately low chat activity is a common indicator of viewbotting.
Modules Used:
twitchio: To connect to Twitch Chat and the Twitch API.- python-dotenv: To manage credentials.
- argparse: To handle command-line arguments.
Prerequisites
- Twitch Developer Account: Register an application on the Twitch Developer Console.
- Credentials: Get your Client ID and Client Secret.
- Chat Token: Generate an OAuth token for chat (e.g., using a token generator tool).
Installation
pip install twitchio python-dotenv
Setup
Create a .env file:
TMI_TOKEN=oauth:your_chat_token
CLIENT_ID=your_client_id
CLIENT_SECRET=your_client_secret
The Code
Save this as twitch_monitor.py.
import os
import asyncio
import argparse
import time
from twitchio.ext import commands
from dotenv import load_dotenv
load_dotenv()
class ViewbotDetector(commands.Bot):
def __init__(self, target_channel):
super().__init__(
token=os.environ['TMI_TOKEN'],
client_id=os.environ['CLIENT_ID'],
client_secret=os.environ['CLIENT_SECRET'],
prefix='!',
initial_channels=[target_channel]
)
self.target_channel = target_channel
self.message_count = 0
self.monitoring = True
async def event_ready(self):
print(f"Logged in as | {self.nick}")
print(f"Monitoring channel: {self.target_channel}")
print("-" * 60)
print(f"{'Time':<10} | {'Viewers':<10} | {'Chats/min':<10} | {'Engagement %':<15}")
print("-" * 60)
# Start the background monitoring task
self.loop.create_task(self.monitor_loop())
async def event_message(self, message):
if message.echo:
return
self.message_count += 1
async def monitor_loop(self):
# Wait for bot to be fully ready
await self.wait_for_ready()
while self.monitoring:
# Wait 60 seconds to gather chat stats
await asyncio.sleep(60)
try:
# Fetch stream info from API
streams = await self.fetch_streams(user_logins=[self.target_channel])
if not streams:
print(f"[{time.strftime('%H:%M')}] Channel is offline.")
# Reset count and wait
self.message_count = 0
continue
stream = streams[0]
viewers = stream.viewer_count
chats = self.message_count
# Calculate Engagement
engagement = 0.0
if viewers > 0:
engagement = (chats / viewers) * 100
timestamp = time.strftime("%H:%M")
print(f"{timestamp:<10} | {viewers:<10} | {chats:<10} | {engagement:.2f}%")
# Heuristic Check
# Normal engagement varies, but < 0.5% with high viewers is suspicious
if viewers > 100 and engagement < 0.5:
print(f" [!] Suspiciously low activity for {viewers} viewers.")
# Reset message count for next cycle
self.message_count = 0
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Twitch Viewbot Detector")
parser.add_argument("channel", help="Target Twitch Channel Name")
args = parser.parse_args()
# Ensure required env vars exist
if not all(k in os.environ for k in ['TMI_TOKEN', 'CLIENT_ID', 'CLIENT_SECRET']):
print("Error: Missing credentials in .env file.")
exit(1)
bot = ViewbotDetector(args.channel)
bot.run()
Usage
python twitch_monitor.py ninja
Note: Engagement rates vary by content type (e.g., esports tournaments often have lower chat/viewer ratios than interactive streamers). Use this as a heuristic, not definitive proof.