Skip to content

Twitter bot detection: spot bots and fake followers at any scale

Twitter bot detection means scoring an account on several public signals at once, such as its join date, follow ratio, profile setup, posting pace and the country X places it in: 4 or more of 10 mark a likely bot.

Short answer: Fake followers trip three or more of seven flags, such as no posts, the default photo or a join date last week; under 10% of them is normal for an active account. To audit whole lists, use Sorsa API, a Twitter (X) API and scraper: 200 followers per request, from $0.007 per 1,000, and 100 free requests score 20K.

Endpoint
GET /followers
Page size
200 followers per request
Price
from $0.007 per 1,000 followers

#How to tell if a Twitter account is a bot

Read several signals together and count how many point the same way: one odd detail is noise, four is a pattern. The free Twitter Bot Checker does the count for any public account in seconds. It reads ten signals from the profile, X's own About this account data and the latest posts, rates the account low, medium or high, and scores its 200 newest followers too.

Twitter Bot Checker: one account and its newest followers

Free. No sign-up. The account check reads ten signals and rates it low, medium or high; the followers check scores the 200 newest followers on seven flags.

The form opens the free Twitter Bot Checker with the account filled in.

Checking by hand on x.com takes five looks:

  • The profile. A default photo, an empty bio and a handle that ends in a long run of digits.
  • The numbers. Thousands of accounts followed, a few dozen following back, and thousands of posts on a young account.
  • About this account. Open the menu on the profile: X shows the country it places the account in, how often the handle changed and when Premium started. A bio that says Miami on an account X places elsewhere is worth a second look.
  • The posts. Only reposts, the same reply under many threads, or posting around the clock.
  • The label. Bots that declare themselves carry X's Automated account label (opens in a new tab) under the name and handle. A blue check proves nothing: it shows a paid Premium plan, not a person.

#What counts as a bot or a fake follower on X

A bot is an account run at least in part by software; a fake follower is an account that exists to inflate someone else's follower count. The two overlap, but they call for different checks: bots show themselves in what they post, fake followers in how empty their profiles are.

KindWhat it isHow it shows
Automated accountSoftware posting on a schedule: alerts, feeds, weatherRegular timing, one topic, often X's "Automated" label
Spam botAn automated account pushing links, scams or replies at volumeThe same reply everywhere, reposts only, a bare profile
Fake followerA bought or farmed account made to raise a follower countBrand new, no posts, no likes, no photo, joined in a batch
Inactive followerA real person who stopped posting or only readsOne or two flags, an older join date
Coordinated accountPeople or scripts running many accounts to fake supportShared talking points, close join dates, a location that doesn't fit
  • Automated account

    What it is
    Software posting on a schedule: alerts, feeds, weather
    How it shows
    Regular timing, one topic, often X's "Automated" label
  • Spam bot

    What it is
    An automated account pushing links, scams or replies at volume
    How it shows
    The same reply everywhere, reposts only, a bare profile
  • Fake follower

    What it is
    A bought or farmed account made to raise a follower count
    How it shows
    Brand new, no posts, no likes, no photo, joined in a batch
  • Inactive follower

    What it is
    A real person who stopped posting or only reads
    How it shows
    One or two flags, an older join date
  • Coordinated account

    What it is
    People or scripts running many accounts to fake support
    How it shows
    Shared talking points, close join dates, a location that doesn't fit

X's Authenticity policy (opens in a new tab) bans paying anyone to inflate follows, likes or views, and bans follow churn. Inactive followers break no rule, so a good audit keeps them apart from fakes.

#The signals that give a bot away

Ten signals from three public places separate most bots from people: the profile, X's About this account panel and the account's latest posts. Each signal counts only next to others, and the table says who else trips it.

The profile GET /info-batch 100 accounts per request 1 Profile setup 2 Following vs followers 3 Age vs audience 4 Posting pace About this account GET /about X's own record of the account 5 Where it's based 6 Username changes 7 Premium timing Shown on every public profile on x.com The latest posts POST /user-tweets 20 posts per request 8 Posting hours 9 Content mix 10 AI labels Signals worth a look on one account 0 or 1: low Real people trip one 2 or 3: medium Look at the flagged signals 4 or more: high Likely a bot or a fake
Ten signals, three sources. Two or three worth a look make an account suspect; four or more make it likely.
SignalWhere you see itWorth a look whenWho else trips it
Profile setupProfileTwo of three: the default photo, an empty bio, a handle ending in six or more digitsPeople who never set up a profile
Following vs followersProfileFollows 1,000+ and fewer than 1 in 20 follow backNew accounts, news readers
Age vs audienceProfileUnder six months old with 10K+ followersSomeone who went viral
Posting paceProfile50+ posts a day on average since joiningNewsrooms, live-tweeters
Where it's basedAbout this accountX's country differs from the bio's location or the App Store regionTravellers, VPN users, expats
Username changesAbout this accountThree or more, or one in the last 90 days on 10K+ followersRebrands
Premium timingAbout this accountPremium bought within a week of joiningCreators who joined to post long videos
Posting hoursLatest postsThe busiest seven hours fall at night in every country the account claimsNight shifts, scheduling tools
Content mixLatest posts80%+ reposts, 90%+ replies, or a link in 90%+ of its own postsCurators, link feeds
AI labelsLatest postsHalf or more of the latest posts labeled "Made with AI"Artists who disclose AI work
  • Profile setup

    Where you see it
    Profile
    Worth a look when
    Two of three: the default photo, an empty bio, a handle ending in six or more digits
    Who else trips it
    People who never set up a profile
  • Following vs followers

    Where you see it
    Profile
    Worth a look when
    Follows 1,000+ and fewer than 1 in 20 follow back
    Who else trips it
    New accounts, news readers
  • Age vs audience

    Where you see it
    Profile
    Worth a look when
    Under six months old with 10K+ followers
    Who else trips it
    Someone who went viral
  • Posting pace

    Where you see it
    Profile
    Worth a look when
    50+ posts a day on average since joining
    Who else trips it
    Newsrooms, live-tweeters
  • Where it's based

    Where you see it
    About this account
    Worth a look when
    X's country differs from the bio's location or the App Store region
    Who else trips it
    Travellers, VPN users, expats
  • Username changes

    Where you see it
    About this account
    Worth a look when
    Three or more, or one in the last 90 days on 10K+ followers
    Who else trips it
    Rebrands
  • Premium timing

    Where you see it
    About this account
    Worth a look when
    Premium bought within a week of joining
    Who else trips it
    Creators who joined to post long videos
  • Posting hours

    Where you see it
    Latest posts
    Worth a look when
    The busiest seven hours fall at night in every country the account claims
    Who else trips it
    Night shifts, scheduling tools
  • Content mix

    Where you see it
    Latest posts
    Worth a look when
    80%+ reposts, 90%+ replies, or a link in 90%+ of its own posts
    Who else trips it
    Curators, link feeds
  • AI labels

    Where you see it
    Latest posts
    Worth a look when
    Half or more of the latest posts labeled "Made with AI"
    Who else trips it
    Artists who disclose AI work

The three About signals are the ones most guides skip. X shows them on every public profile under About this account: the country it places the account in, how many times the handle changed and when Premium started. For what the country means and where it comes from, read what "Account based in" means on X.

Count the signals worth a look: none or one reads low, two or three medium, four or more high. Those are the same bands the Twitter Bot Checker shows, so a script built from this table and the free tool agree on every account.

#How to find fake followers on any account

Score each follower on seven flags from its own profile, then read the share that looks fake: three flags or more marks a likely fake, two usually an inactive person, one or none a real follower. All seven come from fields that GET /followers returns for every follower:

  • Joined in the last 30 days, from created_at.
  • Follows 1,000+ with fewer than 1 in 20 following back, from followings_count and followers_count.
  • No posts: tweets_count is 0.
  • No likes: favourites_count is 0.
  • The default photo: profile_image_url points to X's default image.
  • An empty bio: description is blank.
  • A name-and-digits handle: username ends in six or more digits.
One follower, as GET /followers returns it @dana_k_2042719983, checked on Nov 2, 2026 FIELD VALUE FLAG created_at 2026-10-24 Flag Joined 9 days ago followings_count 2,140 / 12 / followers_count Flag Follows 1,000+, few follow back tweets_count 0 Flag No posts favourites_count 37 No Has liked posts profile_image_url …/default_profile… Flag The default photo description "Crypto | NFTs | DM…" No Has a bio username …2042719983 Flag Ends in ten digits 5 of 7 flags: looks fake Three or more flags count as fake, two as inactive, one or none as real.
Five of seven flags on one follower. Three are enough to count it as fake; bought followers usually trip four or five.

The share that looks fake is the number to watch, and this is how we read it:

Share that looks fakeWhat it usually means
Under 10%Normal for an active account: bots follow popular accounts to look human
10 to 30%Worth a closer look; compare accounts of the same size in the same niche
Over 30%Bought followers or a bot wave, above all if many joined X in the same weeks
  • Under 10%

    What it usually means
    Normal for an active account: bots follow popular accounts to look human
  • 10 to 30%

    What it usually means
    Worth a closer look; compare accounts of the same size in the same niche
  • Over 30%

    What it usually means
    Bought followers or a bot wave, above all if many joined X in the same weeks

Those bands are our reading of the seven flags, not a rule X publishes. The join dates settle most doubts: X lists followers newest first, and bought followers arrive in one batch, so a purchase shows up as a crowd of brand-new accounts at the top of the list.

When the 200 newest followers joined X An example account, audited on Nov 2, 2026 108 joined more than a year ago: an older, spread-out audience 5 Nov 4 Dec 6 Jan 5 Feb 4 Mar 6 Apr 5 May 3 Jun 4 Jul 5 Aug 4 Sep 41 Oct 2025 2026 41 joined in one month 3 to 6 in every other month
An example audit: 41 of the 200 newest followers joined X in the same month. A spike like that is what a bought batch looks like.

Good to know

Inactive isn't fake. Many real people follow accounts and never post, like or fill in a bio, so they trip two flags. Count them apart: lumping them in with fakes doubles the alarm on accounts with an older, quieter audience.

#Audit every follower with Python

A follower audit pages through an account's whole follower list and scores each profile on the seven flags. For that job, use Sorsa API: GET /followers returns 200 followers per request with every field the flags need, from $0.007 per 1,000, so a 50K-follower account costs from $0.35. Five steps take you from a key to the report.

  1. Get a key. Sign up and copy your API key from the dashboard. The first 100 requests are free.

  2. Request the first page. Send the handle to GET /followers (opens in a new tab) with your key in the ApiKey header. The newest followers come first.

    Terminal
    curl -G "https://api.sorsa.io/v3/followers" \
      -H "ApiKey: YOUR_API_KEY" \
      --data-urlencode "username=gulfcoast_wire_news"
    
    Response200 OK
    {
      "users": [
        {
          "id": "1981374420583055360",
          "username": "dana_k_2042719983",
          "display_name": "Dana K",
          "description": "Crypto | NFTs | DM for promo",
          "location": "",
          "created_at": "2026-10-24T03:12:51Z",
          "followers_count": 12,
          "followings_count": 2140,
          "tweets_count": 0,
          "favourites_count": 37,
          "media_count": 0,
          "profile_image_url": "https://abs.twimg.com/sticky/default_profile_images/default_profile_normal.png",
          "verified": false,
          "protected": false
        },
        {
          "id": "1204958817730289664",
          "username": "harborlight_reads",
          "display_name": "Harborlight Reads",
          "description": "Coastal history, one book at a time.",
          "location": "Mobile, Alabama",
          "created_at": "2019-12-12T15:40:02Z",
          "followers_count": 3871,
          "followings_count": 512,
          "tweets_count": 9420,
          "favourites_count": 18233,
          "media_count": 611,
          "profile_image_url": "https://pbs.twimg.com/profile_images/1204961/h.jpg",
          "verified": false,
          "protected": false
        }
      ],
      "next_cursor": "1849212213712385091"
    }
    
  3. Score each profile. Count the seven flags on every follower and sort it into looks fake, looks inactive or looks real.

  4. Follow the cursor. A cursor is the bookmark each page returns: send next_cursor back as a parameter until a page comes without one, and the list is done.

  5. Run the whole audit. The script below does steps 2 to 4 for any account and prints the three shares, the busiest join month and five examples. Pass max_pages=1 to score only the newest 200, as the free checker does.

    import re
    import time
    from collections import Counter
    from datetime import datetime, timezone
    
    import requests
    
    API = "https://api.sorsa.io/v3"
    HEADERS = {"ApiKey": "YOUR_API_KEY"}
    NOW = datetime.now(timezone.utc)
    
    
    def flags(user):
        """The seven fake-follower flags of one profile."""
        joined = datetime.fromisoformat(user["created_at"].replace("Z", "+00:00"))
        following = user["followings_count"]
        photo = user.get("profile_image_url") or ""
        found = []
        if (NOW - joined).days < 30:
            found.append("joined in the last 30 days")
        if following >= 1000 and user["followers_count"] * 20 < following:
            found.append("follows 1,000+, few follow back")
        if user["tweets_count"] == 0:
            found.append("no posts")
        if user["favourites_count"] == 0:
            found.append("no likes")
        if not photo or "default_profile" in photo:
            found.append("default photo")
        if not (user.get("description") or "").strip():
            found.append("empty bio")
        if re.search(r"\d{6,}$", user["username"]):
            found.append("name-and-digits handle")
        return found
    
    
    def audit(username, max_pages=None):
        """Score every follower of one account, 200 per request."""
        params, pages = {"username": username}, 0
        groups, months, examples = Counter(), Counter(), []
        while True:
            r = requests.get(f"{API}/followers", headers=HEADERS, params=params)
            if r.status_code == 429:  # over 20 requests in one second
                time.sleep(1)
                continue
            r.raise_for_status()
            page = r.json()
            for user in page["users"]:
                found = flags(user)
                n = len(found)
                group = "fake" if n >= 3 else "inactive" if n == 2 else "real"
                groups[group] += 1
                months[user["created_at"][:7]] += 1
                if group == "fake" and len(examples) < 5:
                    examples.append((user["username"], found))
            pages += 1
            cursor = page.get("next_cursor")
            if not cursor or pages == max_pages:
                break
            params["next_cursor"] = cursor
        total = sum(groups.values())
        for group in ("fake", "inactive", "real"):
            print(f"looks {group}: {groups[group]} ({groups[group] / total:.0%})")
        month, count = months.most_common(1)[0]
        print(f"busiest join month: {month}, {count / total:.0%} of followers")
        for handle, found in examples:
            print(f"  @{handle}: {', '.join(found)}")
    
    
    audit("gulfcoast_wire_news")
    

A 401 or 403 means the key is missing, wrong or out of requests; a 429 means more than 20 requests in one second, and the Python script waits a second and retries. One account's pages run one after another, since each needs the cursor before it; audit several accounts side by side at up to 20 requests per second per key. To save the profiles themselves as a file, see how to extract Twitter followers to CSV.

Score a response without writing code

Paste the JSON of any GET /followers page below, from the curl request above or the API playground, and the page scores it in your browser on the same seven flags.

One page holds up to 200 followers. To score more, paste several pages as one JSON array: [page1, page2].

Example: the 200 newest followers of @gulfcoast_wire_news

17% look fake

  • Look fake 34 17%
  • Look inactive 30 15%
  • Look real 136 68%

41 joined X in the last 30 days. Busiest join month: Oct 2026, with 21% of these followers.

Flagged examples

  • @dana_k_2042719983 joined in the last 30 days, follows 1,000+, few follow back, no posts, default photo, name-and-digits handle
  • @mira_lopez_88310274 joined in the last 30 days, no posts, no likes, default photo, empty bio, name-and-digits handle
  • @gainsdaily_alerts_x joined in the last 30 days, follows 1,000+, few follow back, no posts, empty bio
  • @t_ward_4471902366 no posts, no likes, default photo, name-and-digits handle

Scoring runs in your browser; nothing you paste leaves the page.

#Vet a list of accounts in batches of 100

To screen a list of creators, partners or reply accounts, read their profiles 100 at a time through GET /info-batch (opens in a new tab), then add each account's About data from GET /about (opens in a new tab). The script below computes six of the ten signals and prints X's country next to the bio's location for a quick look.

The About half is where the official X API falls short: its user object has a free-text location but no country, no username history and no Premium start date, as its data dictionary (opens in a new tab) shows. Sorsa API's GET /about returns country, username_change_count, last_username_change_at, premium_start_at and the App Store region in source.

Python
from datetime import datetime, timezone

import requests

API = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": "YOUR_API_KEY"}
NOW = datetime.now(timezone.utc)


def when(stamp):
    return datetime.fromisoformat(stamp.replace("Z", "+00:00"))


def profiles(handles):
    """Profiles of up to 100 accounts per request."""
    for i in range(0, len(handles), 100):
        r = requests.get(f"{API}/info-batch", headers=HEADERS,
                         params={"usernames": handles[i:i + 100]})
        r.raise_for_status()
        yield from r.json()["users"]


def about(handle):
    """X's About this account data: country, renames, Premium."""
    r = requests.get(f"{API}/about", headers=HEADERS,
                     params={"username": handle})
    r.raise_for_status()
    return r.json()


def signals(p, a):
    age = max((NOW - when(p["created_at"])).days, 1)
    fans, follows = p["followers_count"], p["followings_count"]
    photo = p.get("profile_image_url") or ""
    setup = [not photo or "default_profile" in photo,
             not (p.get("description") or "").strip(),
             p["username"][-6:].isdigit()]
    renamed = a.get("last_username_change_at")
    premium = a.get("premium_start_at")
    return {
        "profile setup": sum(setup) >= 2,
        "follow ratio": follows >= 1000 and fans * 20 < follows,
        "young, big audience": age < 183 and fans >= 10000,
        "50+ posts a day": p["tweets_count"] / age >= 50,
        "username changes": (a.get("username_change_count") or 0) >= 3
        or (bool(renamed) and (NOW - when(renamed)).days < 90
            and fans >= 10000),
        "Premium in week one": bool(premium)
        and (when(premium) - when(p["created_at"])).days < 7,
    }


for p in profiles(["gulfcoast_wire_news", "harborlight_reads"]):
    a = about(p["username"])
    hits = [name for name, hit in signals(p, a).items() if hit]
    print(f"@{p['username']}: {len(hits)} of 6 {hits}")
    print(f"  X places it in {a.get('country')}; bio: {p.get('location')}")

Each account's About request is independent, so a list runs in parallel: 1,000 accounts take under a minute at 20 requests per second. The other three signals, posting hours, content mix and AI labels, come from POST /user-tweets (opens in a new tab), which returns the latest 20 posts with created_at, replies, reposts, links and the made_with_ai label. Run it on the accounts that already scored two or more, and the deep check stays cheap.

#What a bot audit costs

Checking followers through Sorsa API costs from $0.007 per 1,000, against $10.00 per 1,000 on the official X API, which bills every follower it returns as a $0.010 user read on its pay-per-use price list (opens in a new tab). A 50K-follower account comes to $0.35 instead of $500.

Followers to audit

Official X API

$1,000

for 100K followers

$0.010 per follower

Sorsa API

from$0.70

for 100K followers

from $0.007 per 1,000

1,000x cheaper

Vetting a list of accounts is priced the same way. The profile and About signals of 1,000 accounts cost from $1.41 on Sorsa API, and with the latest 20 posts of each for the behaviour signals, from $2.81. The official X API charges $110.00 for the same 1,000 profiles with 20 posts each, and its user object carries no About data at all.

When you pick a data source for bot detection, five things decide it, and Sorsa API's numbers are these:

  • Price per 1,000: followers from $0.007, profiles from $0.014, failed requests never charged.
  • Fields: the full public profile on every follower, plus X's About this account data that the official X API doesn't carry.
  • Speed: 20 requests per second on every plan, free accounts included.
  • Setup: one API key in a header, with no X developer account, no OAuth and no approval.
  • Your own account: never involved. Sorsa API asks for no X login or cookies, so checking thousands of accounts puts nothing of yours at risk.

#Why the old free bot detectors stopped working

The detectors most guides still name depended on Twitter's free API, and they lost their data when it closed in 2023. Botometer, from Indiana University's Observatory on Social Media, now runs Botometer X in archival mode: its own notes (opens in a new tab) say the scores come from data collected before May 31, 2023, that accounts created since then have no record, and that the model predates generative AI and can't catch AI-driven bots.

Its last live-scoring API endpoints, Botometer v4 and BotometerLite, shut down on November 2, 2026, according to the notice on Botometer Pro's API page (opens in a new tab); only the archival endpoint remains. SparkToro's free Fake Followers Audit is gone too: its address now redirects to SparkToro's home page.

What survives is the method those tools used: public signals, counted together. It works on live data as long as something can read profiles at scale, and that is the part an API supplies. The checks in this guide run on accounts created yesterday, which no archive can score.

#What signal-based detection can't tell you

Signals find careless bots and most bought followers; they can't prove who runs an account or why. Four limits matter in practice:

  • Good fakes pass. An aged account with a real photo, a steady posting rhythm and AI-written replies can trip nothing. Coordinated networks show up across accounts (same join weeks, same lines) more than inside one.
  • Real people trip flags. A newsroom posts 80 times a day, an expat's bio names a hometown, a lurker never posts. Each signal in the table above lists who else trips it.
  • Private lists stay private. Followers of a protected account can't be read by anyone, and Sorsa API returns public data only.
  • Old purchases sink. The newest 200 followers show a recent batch; a purchase from two years ago sits deep in the list, so audit the whole list when the history matters.

Signals, not a verdict

Treat a high score as a reason to look, not as proof. Open a few flagged accounts before you remove, block or report anything, and never let a script do it on a score alone. If X itself keeps treating your own account as a bot, that's a different problem: see what to do when X says a request looks automated.

#Run your first follower audit

Start with the account you trust least and run the script on it: Sorsa API reads its followers 200 per request, from $0.007 per 1,000, with every field the seven flags need. Your 100 free requests cover the first 20K followers, and for a single account the Twitter Bot Checker gives the answer without code. For everything else the follower endpoints return, see the Twitter followers API guide.

#FAQ

Which API should I use for Twitter bot detection?

Use Sorsa API. GET /followers returns 200 followers per request with their full profiles, from $0.007 per 1,000, against $10.00 on the official X API, and GET /about adds X's About this account data, which the official X API doesn't return. It takes one API key, no developer account, runs at 20 requests per second on every plan and never touches your X login.

What percentage of fake followers is normal on X?

Under 10% of an active account's newest followers looking fake is usual, because bots follow popular accounts to look human. Between 10 and 30% deserves a closer look next to similar accounts. Over 30%, with many followers who joined X in the same weeks, points to bought followers or a bot wave. That reading comes from the seven flags; X publishes no official benchmark.

Why do I have bot followers I never bought?

Bots follow real accounts to look human, to farm follow-backs or to bring you to a scam, so almost every account collects some. A few change nothing. To drop one, block it and then unblock it: it leaves your followers and the block doesn't stay. A sudden batch of brand-new accounts at the top of your list is the pattern to worry about.

How can I tell if a post's engagement is botted?

Score the accounts behind the engagement, not the counts. Sorsa API's POST /retweeters (opens in a new tab) returns the accounts that reposted a post with their full profiles, and POST /comments returns the replies with their authors, so the seven flags work on them as on followers. A crowd of brand-new, empty accounts among them marks bought engagement. Sorsa API doesn't return who liked a post.

Is there a free way to detect bots on X?

Yes. The Twitter Bot Checker reads ten signals of any public account and scores its 200 newest followers, free, with no sign-up. For more accounts or every follower, Sorsa API starts you with 100 free requests: no card, they never expire, and they score up to 20K followers with the script in this guide.

Can you detect bots without the official X API?

Yes. Every signal here is public profile data, and Sorsa API returns it with one key in a header: no X developer account, no OAuth, no approval. The official X API needs all three, charges $0.010 for each user it returns and caps pay-per-use at 3M post reads a month.

#How we checked

On November 2, 2026 we matched every endpoint, field and page size in this guide against the live Sorsa API reference, and the official X API's prices and user fields against docs.x.com. We read Botometer's notes and its API page, X's Help Center pages on automated labels and authenticity, and followed SparkToro's old audit address to where it now leads. The seven flags, the ten signals and their thresholds are the ones the free Twitter Bot Checker uses; the accounts in the examples are made up.

By the Sorsa API team. We build and run Sorsa API, the read-only Twitter/X API and scraper, in production since 2022 (formerly TweetScout API) with 6B+ requests served. About Sorsa API

What changed
  • Rewritten from scratch: ten signals with their sources, X's About this account data as signals, the seven-flag follower audit in Python and Node.js, a no-code response scorer, costs per 1,000 against the official X API, and Botometer's November 2026 shutdown.
  • First published.