An influencer quotes you a price based on 200,000 followers. How many of those are people? Fake follower check tools answer with one confident percentage and don't show their working, so you can't tell what's behind it.

You can do your own check with about 60 lines of Python and see exactly why each account was flagged. It reads an account's most recent followers, scores each one for the signs of a throwaway account, and reports the share that look suspicious. We run TwittrAPI, the API this uses. Treat the output as a reason to look closer, and not as a verdict. We explain why below.

What this can and can't tell you

No outside tool knows whether an account is fake. X doesn't publish that, and no field says "bot". All anyone can do is look at public signs and estimate, and that includes paid audit tools.

Real people can look like bots. Someone who joined last week to follow the news has a new account, no bio and no posts. The script will flag them. That's why you should compare results across accounts and not read the number on its own.

Step 1: Get a key and read the followers

Create a key at /start. New accounts get $0.50 of test credit for 7 days.

import os
import time
 
import requests
 
API = "https://api.twittrapi.com"
HEADERS = {"X-API-KEY": os.environ["TWITTRAPI_API_KEY"]}
 
 
def followers(username, limit=2000):
    cursor, seen = None, 0
    while seen < limit:
        params = {"username": username, "count": 100, "format": "simple"}
        if cursor:
            params["cursor"] = cursor
        r = requests.get(f"{API}/user/-1/followers", headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        page = r.json()
        for user in page["data"]:
            seen += 1
            yield user
        if not page["hasNextPage"]:
            return
        cursor = page["nextCursor"]
        time.sleep(0.2)

GET /user/{userId}/followers returns the list newest first. That's important. A sample from the top of the list shows who followed recently, and says little about followers from three years ago.

That's a limit, but also useful. Bought followers tend to arrive in recent batches, so recent followers are where you'd expect to see them, if the purchase was recent. Say which window you checked when you report a result.

Step 2: Score each follower

Each signal adds points. The weights are our own rule of thumb: we didn't train them on labeled data and you should change them to suit your case.

from datetime import datetime, timezone
 
NOW = datetime.now(timezone.utc)
 
 
def score(user):
    reasons = []
    c = user["counts"]
    created = datetime.fromisoformat((user["createdAt"] or "2006-03-21T00:00:00Z").replace("Z", "+00:00"))
    age_days = (NOW - created).days
 
    if "default_profile" in (user["avatarUrl"] or ""):
        reasons.append(("default avatar", 2))
    if not user["description"].strip():
        reasons.append(("no bio", 1))
    if c["tweets"] == 0:
        reasons.append(("never posted", 2))
    elif c["tweets"] < 5:
        reasons.append(("under 5 posts", 1))
    if c["followers"] < 5:
        reasons.append(("under 5 followers", 1))
    if c["following"] > 500 and c["following"] > 20 * max(c["followers"], 1):
        reasons.append(("follows far more than follow back", 2))
    if age_days < 30:
        reasons.append(("account under 30 days old", 2))
 
    return sum(points for _, points in reasons), [name for name, _ in reasons]

The avatar check works because accounts without a picture point to a default_profile image. A single signal means nothing, so we only flag accounts with several. Verified accounts aren't exempt, since a blue check is a paid subscription.

Step 3: Run the fake follower check

from collections import Counter
 
THRESHOLD = 4  # a score of 4 or more counts as suspicious
 
 
def audit(username, limit=2000):
    total, flagged = 0, 0
    why = Counter()
    examples = []
    for user in followers(username, limit):
        total += 1
        points, reasons = score(user)
        if points >= THRESHOLD:
            flagged += 1
            why.update(reasons)
            if len(examples) < 10:
                examples.append((user["username"], points, reasons))
    return {"sampled": total, "flagged": flagged, "why": why, "examples": examples}
 
 
result = audit("someaccount")
share = result["flagged"] / max(result["sampled"], 1)
print(f"{result['flagged']} of {result['sampled']} recent followers look suspicious ({share:.0%})")
for reason, n in result["why"].most_common():
    print(f"  {reason}: {n}")

Open the examples and read a handful of profiles yourself. It takes two minutes, and tells you whether the score is catching the right accounts.

How to read the result

There's no universal "good" number. Every large account collects some low-effort followers without doing anything wrong, and X's own suggestions send new users to big accounts. That's why comparison beats thresholds:

  1. Run the same audit on three to five similar accounts. Same niche and size. If your candidate is at 45% and its peers are at 15%, that says something. If everyone is at 40%, your candidate is normal for that niche.
  2. Run your own account. It's a useful baseline, as you know how you got your followers.
  3. Check the follower growth. A count that climbs in steps with quiet stretches in between deserves a look. You can't get past counts from X, but you can start logging them today.

The second test: engagement against followers

Followers can be bought, and they rarely engage. Compare recent likes and replies with the follower count:

from statistics import median
 
 
def engagement(username, pages=3):
    cursor, tweets = None, []
    for _ in range(pages):
        params = {"username": username, "format": "simple"}
        if cursor:
            params["cursor"] = cursor
        r = requests.get(f"{API}/user/-1/tweets", headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        page = r.json()
        tweets += [t for t in page["data"] if not t["retweetOf"] and not t["isPinned"]]
        if not page["hasNextPage"]:
            break
        cursor = page["nextCursor"]
    if not tweets:
        return None
    followers_now = tweets[0]["author"]["counts"]["followers"]
    likes = median(t["counts"]["likes"] for t in tweets)
    views = median(t["counts"]["views"] or 0 for t in tweets)
    return {
        "followers": followers_now,
        "median_likes": likes,
        "median_views": views,
        "likes_per_1000_followers": round(likes / max(followers_now, 1) * 1000, 2),
    }

We use the median because one viral post would pull an average way off, and we skip reposts because their own like counts come back as 0. Again, compare with peers. The bad sign is a large follower count with a few likes per post, across the board. A post about a niche topic getting little engagement proves nothing.

Together the two tests work better than either one. Odd followers plus weak engagement is a real warning. Odd followers plus strong engagement often means a big account with normal low-quality followers on top of a real audience.

What it costs

Follower pages hold several dozen accounts each, and X decides how many. Each page is one call at $0.0001 on the Standard tier. A 2,000 follower sample takes roughly 20 to 40 calls, so under half a cent, and the engagement test adds 3 calls. You could audit a shortlist of 20 influencers for less than 10 cents.

To audit every follower instead of a sample, use the paging logic from exporting followers to CSV. A 1,000,000 follower account takes many thousands of calls, X may end the list before the full count, and a full export is rarely worth it just for this.

Handle the data with care

A follower list is personal data under the GDPR and similar laws, even when it's public. For this job, you don't need to keep it: save the totals and throw away the rows. Don't publicly call a named person's followers fake based on this alone. The score can't support that claim, and our acceptable use policy rules out harassment.

Frequently asked questions

How can I check if an X account has fake followers?

Sample its recent followers and look for accounts with default avatars, no bio, no posts, very new creation dates and lopsided following ratios. Compare the share with similar accounts, and check likes and views against the follower count.

What percentage of fake followers is normal?

There's no reliable standard, because it depends on the niche and on how each tool defines fake. Treat any single percentage with care and compare it with similar accounts measured the same way.

Can you see fake followers for free?

X has no such feature. The script here costs a fraction of a cent per audit and the $0.50 trial credit covers many runs, so it's close to free.

Do fake followers get removed by X?

X does remove accounts it finds in violation, and a sudden drop in follower count can be a sign of that. It can also simply mean inactive accounts were cleaned out, so a drop on its own proves nothing about the account owner.

Can I tell who bought followers?

Not with certainty. Bad signals can come from purchased followers, from spam accounts following on their own, or from someone else buying followers for the account. These tests can only show that something is worth a closer look.

Sources

TwittrAPI is not affiliated with X Corp. It reads only public data.