Common Spam Patterns on X and How to Filter Them#
Spam on X isn't subtle. Most spam accounts share a handful of obvious traits — new account, no followers, no bio, and a flood of replies under popular tweets. The problem is X doesn't give you any tools to filter based on these signals.
Twitter Filter does. We maintain a subscription rule called Spam Reply Bot that catches the most common spam patterns. This post explains what it detects and why.
Quick start: subscribe#
The fastest way to get spam filtering is to subscribe to the rule — it updates automatically as new patterns emerge:
Open the link with Twitter Filter installed — it will prompt you to subscribe. Below is what the rule catches and how each sub-condition works.
Understanding spam signals#
No single trait makes an account spam. Plenty of real people have zero followers or no bio. What makes spam obvious is the combination: a brand-new account with no followers, no bio, and hundreds of reply tweets is almost certainly not a real person.
The Spam Reply Bot rule stacks multiple signals together and uses || (OR) to combine seven sub-conditions. A tweet is flagged if it matches any one of them.
1. Brand-new low-activity accounts#
tweet.is_reply
&& days_since(user.created_at) < 30
&& user.statuses_count < 5
&& user.followers < 2
Catches accounts less than a month old that have barely tweeted and have no followers. These are freshly created throwaway accounts — real new users typically don't start by replying under popular tweets with fewer than 5 posts to their name.
2. Undetermined-language reply floods#
tweet.is_reply
&& tweet.lang == "und"
&& user.followers < 2
&& user.statuses_count > 20
&& days_since(user.created_at) < 60
X assigns lang: "und" (undetermined) when a tweet's text doesn't contain enough recognizable language — common with link-only replies, emoji-only replies, or garbled text. Combined with a new high-volume account and no followers, this is a strong spam signal.
3. No-bio reply bots#
tweet.is_reply
&& user.followers < 2
&& len(user.description) == 0
&& days_since(user.created_at) < 90
&& user.statuses_count > 10
The classic spam profile: no bio, no followers, less than 3 months old, but already posting replies. The statuses_count > 10 threshold prevents false positives on legitimate new users who simply haven't filled out their profile yet.
4. Emoji and symbol-only replies#
tweet.is_reply
&& !(tweet.text matches '[a-zA-Z0-9一-鿿-ヿ]')
&& len(tweet.text) > 0
&& user.followers < 2
&& days_since(user.created_at) < 90
The regex [a-zA-Z0-9一-鿿-ヿ] matches Latin letters, digits, CJK characters, and Japanese kana. If a reply contains none of these — just emojis, arrows, or other symbols — and the account is new with no followers, it's almost certainly spam or engagement farming.
5. Telegram link promotion#
tweet.is_reply
&& user.followers < 10
&& user.description contains "t.me/"
Spam accounts promoting Telegram groups or channels often put the link directly in their bio. This catches low-follower accounts with t.me/ links in their description. The follower threshold is slightly higher (< 10) since some of these accounts buy a few followers to look legitimate.
6. Zero-width character spam#
tweet.is_reply
&& user.followers < 10
&& tweet.text matches '[\u200B\u2060\uFEFF\u00AD\u034F\u180E]'
Some spam tweets embed invisible Unicode characters (zero-width spaces, word joiners, soft hyphens) to evade text-based filters or detection. Normal users don't type these characters. This catches replies from low-follower accounts that contain any of these invisible codepoints.
7. Chinese-language zero-width character spam#
tweet.is_reply
&& user.followers < 10
&& tweet.lang == "zh"
&& tweet.text matches '[\u200B\u200C\u2060\uFEFF\u00AD]'
A more targeted variant of the above, specifically for Chinese-language replies. Chinese spam bots frequently use zero-width characters to break up keywords and avoid detection. This condition narrows the scope to zh-language tweets to reduce false positives in other languages.
The full rule#
All seven conditions combined into a single rule:
tweet.is_reply && days_since(user.created_at) < 30 && user.statuses_count < 5 && user.followers < 2
|| tweet.is_reply && tweet.lang == "und" && user.followers < 2 && user.statuses_count > 20 && days_since(user.created_at) < 60
|| tweet.is_reply && user.followers < 2 && len(user.description) == 0 && days_since(user.created_at) < 90 && user.statuses_count > 10
|| tweet.is_reply && !(tweet.text matches "[a-zA-Z0-9一-鿿-ヿ]") && len(tweet.text) > 0 && user.followers < 2 && days_since(user.created_at) < 90
|| tweet.is_reply && user.followers < 10 && user.description contains "t.me/"
|| tweet.is_reply && user.followers < 10 && tweet.text matches "[\u200B\u2060\uFEFF\u00AD\u034F\u180E]"
|| tweet.is_reply && user.followers < 10 && tweet.lang == "zh" && tweet.text matches "[\u200B\u200C\u2060\uFEFF\u00AD]"
How to use#
Recommended: Subscribe to Spam Reply Bot — you'll get updates automatically as new spam patterns are added.
Manual: Copy the full rule above, open Twitter Filter's Rules tab, click Import, paste and confirm. Note that manual imports won't receive future updates.
Matched tweets get a visual indicator so you can see exactly what's being caught. Once you've confirmed the rule isn't catching real users you want to see, you can adjust the action to hide them entirely.
Don't have the extension yet? Install Twitter Filter from the extension page.