DEV Community

mike
mike

Posted on

I Built an Instagram Bot Cleaner in Python Here's the Architecture

https://github.com/Saqlvation/instapurge
https://www.youtube.com/watch?v=5vW7f2HbNiA

TL;DR
I built InstaPurge, a Python-based Instagram bot cleaner that identifies and removes fake followers, inactive accounts, and bot-driven interactions from your Instagram profile. This post breaks down the full architecture, design decisions, and lessons learned.
The Problem
Instagram is flooded with bots. Over time, your follower count becomes a vanity metric — inflated by fake accounts, engagement pods, and inactive users. Worse, these bots can drag down your engagement rate, which the algorithm uses to decide how widely to distribute your content.
I wanted a tool that could:
Detect bot accounts and inactive followers
Analyze engagement patterns to find low-quality connections
Clean them out safely, without triggering Instagram's rate limits or anti-automation systems
Log everything so you know exactly what was removed and why
High-Level Architecture
plain
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ CLI / Web UI │────▶│ Core Controller │────▶│ Instagram API │
│ (User Input) │ │ (Orchestration) │ │ (Data Source) │
└─────────────────┘ └──────────────────┘ └─────────────────┘


┌──────────────────┐
│ Analysis Engine │
│ (Bot Detection) │
└──────────────────┘


┌──────────────────┐
│ Action Queue │
│ (Rate-Limited │
│ Execution) │
└──────────────────┘


┌──────────────────┐
│ SQLite / JSON │
│ (Audit Logging) │
└──────────────────┘
Layer 1: The Instagram Bridge
The biggest challenge with Instagram automation is not getting banned. Instagram aggressively detects and blocks automation tools. Here's how I approached it:
Authentication Strategy
Session-based login using instaloader or selenium to mimic real browser behavior
Cookie persistence so you don't re-authenticate every run (a major red flag for IG)
2FA handling with manual fallback — because breaking into your own account shouldn't be automatic
Data Collection
Instead of scraping (which violates ToS and gets you blocked), I use Instagram's private API endpoints through a library like instaloader or instagrapi. This gives structured access to:
Follower/following lists
Post metadata (likes, comments, timestamps)
User profiles (bio, follower count, post count, profile picture)
Python

Simplified data fetcher

class InstagramBridge:
def init(self, session_file: str):
self.loader = instaloader.Instaloader()
self.loader.load_session_from_file(session_file)

def get_followers(self, username: str) -> Iterator[Profile]:
    profile = instaloader.Profile.from_username(self.loader.context, username)
    return profile.get_followers()

def get_following(self, username: str) -> Iterator[Profile]:
    profile = instaloader.Profile.from_username(self.loader.context, username)
    return profile.get_followers()
Enter fullscreen mode Exit fullscreen mode

Layer 2: The Bot Detection Engine
This is where the magic happens. A "bot" isn't just one thing — it's a spectrum. I built a scoring system that weighs multiple signals:
Signal 1: Profile Heuristics
Fogli di calcolo
Signal Weight Why It Matters
No profile picture High Bots rarely upload custom photos
Default bio / no bio Medium Minimal effort = minimal human
Follower-to-following ratio < 0.1 High Following thousands, followed by few = spam pattern
Account age < 30 days Medium Fresh accounts are often throwaways
Username has random digits Low john_doe_2847 screams automation
Signal 2: Engagement Patterns
No likes on your posts — if they never interact, why are they following you?
Generic comments — "Nice pic!" or emojis-only on every post
Comment timing — posted at inhumanly consistent intervals (every 47 minutes)
Signal 3: Network Analysis
Mutual connections — bots often cluster; if 10 of your followers all follow the same 500 spam accounts, they're likely part of a botnet
Graph clustering using simple connected-component analysis
The Scoring Algorithm
Python
class BotScorer:
def init(self, weights: dict):
self.weights = weights

def score(self, user: UserProfile, interactions: List[Interaction]) -> float:
    score = 0.0

    # Profile heuristics
    if not user.has_profile_pic:
        score += self.weights['no_pic']
    if user.followers / max(user.following, 1) < 0.1:
        score += self.weights['low_ratio']
    if user.account_age_days < 30:
        score += self.weights['new_account']

    # Engagement heuristics
    if not interactions:
        score += self.weights['no_interaction']
    elif self._is_generic_comment_pattern(interactions):
        score += self.weights['generic_comments']

    return min(score, 1.0)  # Cap at 1.0

def classify(self, score: float) -> str:
    if score >= 0.8: return 'bot'
    if score >= 0.5: return 'suspicious'
    return 'human'
Enter fullscreen mode Exit fullscreen mode

Layer 3: The Action Queue & Rate Limiter
Instagram's rate limits are aggressive and undocumented. Through trial and error, I found these safe thresholds:
Fogli di calcolo
Action Safe Limit Cooldown
Unfollow ~150/day 20-60s between actions
Profile fetch ~200/hour 2-5s between requests
Like/Comment ~100/day Randomized delays
I implemented a token-bucket rate limiter with jitter to make traffic look organic:
Python
import random
import time
from dataclasses import dataclass
from collections import deque

@dataclass
class RateLimiter:
max_actions: int # per window
window_seconds: int
min_delay: float
max_delay: float

def __post_init__(self):
    self.actions = deque()

def wait_and_execute(self, action: callable):
    self._enforce_rate()
    delay = random.uniform(self.min_delay, self.max_delay)
    time.sleep(delay)
    action()
    self.actions.append(time.time())

def _enforce_rate(self):
    now = time.time()
    # Remove actions outside the window
    while self.actions and now - self.actions[0] > self.window_seconds:
        self.actions.popleft()

    if len(self.actions) >= self.max_actions:
        sleep_time = self.window_seconds - (now - self.actions[0])
        if sleep_time > 0:
            time.sleep(sleep_time + random.uniform(5, 15))
Enter fullscreen mode Exit fullscreen mode

Layer 4: Audit & Safety
Every action is logged to a local SQLite database with a full snapshot of the decision:
Python
@dataclass
class RemovalRecord:
timestamp: datetime
username: str
bot_score: float
signals_triggered: List[str]
action_taken: str # 'unfollowed', 'flagged', 'skipped'
session_id: str
This serves two purposes:
Undo capability — if you accidentally purge a real friend, you have the data to reverse it
Pattern analysis — over time, you can tune your scoring weights based on false positives
The CLI Experience
I kept the interface minimal but informative using rich for terminal UI:
plain
┌─────────────────────────────────────────┐
│ InstaPurge v1.0.0 │
│ ───────────────── │
│ │
│ [1] Scan followers │
│ [2] Review flagged accounts │
│ [3] Execute cleanup (dry-run) │
│ [4] Execute cleanup (live) │
│ [5] View audit log │
│ [q] Quit │
│ │
└─────────────────────────────────────────┘
The dry-run mode is critical — it shows you exactly what would happen without making any API calls.
Key Design Decisions

  1. Why not use the official Instagram API? The Basic Display API doesn't expose follower lists or allow unfollow actions. The Graph API is for business accounts only. Private API libraries are the only viable path for personal account management.
  2. Why SQLite over a cloud database? Privacy. Your follower list and bot scores shouldn't leave your machine. Local-first architecture keeps everything under your control.
  3. Why Python? instaloader and instagrapi are mature Python libraries rich makes beautiful CLI interfaces trivial pandas + scikit-learn make signal analysis and clustering easy if you want to level up to ML-based detection later What I Learned Rate limits are the real enemy. You can build the smartest bot detector in the world, but if you hit Instagram's rate limit, you're locked out for 24-48 hours. Patience wins. False positives hurt. I initially set thresholds too aggressively and nearly unfollowed a few real friends. The scoring system needs a "review queue" for edge cases. Instagram changes fast. The private API shifts frequently. I abstracted the bridge layer so I can swap libraries without touching the core logic. Future Improvements ML-based detection: Train a classifier on labeled bot/human accounts using profile features Web dashboard: A React frontend for non-technical users Scheduled runs: Cron-based daily scans with email reports Cross-platform: Package as a standalone executable with PyInstaller Try It Out bash git clone https://github.com/Saqlvation/instapurge.git cd instapurge python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install -r requirements.txt python -m instapurge --help ⚠️ Disclaimer: This tool is for educational purposes and personal account management. Use responsibly and at your own risk. Instagram's Terms of Service prohibit certain automated actions. Questions? Thoughts? Drop a comment below — I'd love to hear how you'd approach bot detection differently, or if you've built something similar!

Top comments (0)