BotBouncer — Source Code Analysis
Date: 2026-08-12
Purpose: Detailed analysis of BotBouncer’s actual detection logic, based on reading the source code of both the main app (fsvreddit/bot-bouncer) and the evaluation engine (fsvreddit/bot-bouncer-evaluation).
Sources: All claims in this document are from actual source code read from GitHub raw URLs on Aug 12, 2026. No inference from filenames alone.
1. Architecture Overview
BotBouncer is a Reddit Dev Platform app (not a standalone bot). It runs inside Reddit’s infrastructure and responds to platform events (post creation, comment creation, comment edits). It has two repos:
| Repo | Purpose |
|---|---|
fsvreddit/bot-bouncer | Main app — event handling, reporting, banning, post creation, AI summaries |
fsvreddit/bot-bouncer-evaluation | Evaluation engine — all bot detection logic lives here |
How it works at a high level:
1. A subreddit installs BotBouncer from the Dev Platform app directory
2. BotBouncer watches ALL new posts and comments on that subreddit
3. When a new post/comment is created:
a. Check if the author is already classified as "banned" → if yes, ban + remove immediately
b. If unknown, run through ALL evaluators (see §3) to check if the content looks bot-like
c. If an evaluator flags it as a possible bot → auto-submit to r/BotBouncer for evaluation
4. On r/BotBouncer, the account goes through full evaluation:
a. All evaluators run against the user's full history (100 most recent items)
b. If evaluators match AND can auto-ban AND meet content threshold → auto-ban
c. If evaluators match but can't auto-ban → flag for manual review
d. If no evaluators match → needs manual review
5. OpenAI summary is generated for moderators to review (see §5)
6. Once classified as "banned":
a. Account is banned from the reporting subreddit
b. Account is banned from ALL participating subreddits where it has content in the past week
c. A public "Overview for <username>" post is created on r/BotBouncer
2. Two Detection Modes
Mode 1: Reactive (Human-Triggered)
A subreddit moderator or user manually reports an account:
| Step | What Happens | Source File |
|---|---|---|
| 1 | Mod clicks “Report to /r/BotBouncer” on a comment/post | handleReportUser.ts |
| 2 | Form asks: “Why is this a bot?” (optional context) + “Show publicly?” + “Notify me?” | handleReportUser.ts:reportFormDefinition |
| 3 | Submission is queued | externalSubmissions.ts:addExternalSubmissionFromClientSub |
| 4 | Post is created on r/BotBouncer with the reporter’s context | postCreation.ts |
| 5 | Full evaluation runs (all evaluators against user’s history) | handleControlSubAccountEvaluation.ts:evaluateUserAccount |
| 6 | If evaluators auto-ban → flair set to “Banned” | handleControlSubAccountEvaluation.ts:handleControlSubAccountEvaluation |
| 7 | If no auto-ban match → “Needs manual review” + OpenAI summary generated | createAISummary.ts:generateOpenAISummary |
Key detail from handleReportUser.ts: The reporting user can add context text. This context is shown publicly on the BotBouncer post if they choose “Show publicly” (default: true). This is exactly what we saw in our BotBouncer reports — the reporter wrote “asking a question and not directly answering the post.”
Mode 2: Proactive (Automated Bot Hunting)
BotBouncer actively scans known karma-farming subreddits for new accounts:
| Step | What Happens | Source File |
|---|---|---|
| 1 | Scheduled job runs periodically | karmaFarmingSubsCheck.ts:evaluateKarmaFarmingSubs |
| 2 | Fetches the 100 newest posts from each karma-farming sub | karmaFarmingSubsCheck.ts:getAccountsFromSub |
| 3 | Extracts unique authors from those posts | karmaFarmingSubsCheck.ts:getDistinctAccounts |
| 4 | Filters out accounts already known to BotBouncer | karmaFarmingSubsCheck.ts:queueKarmaFarmingSubs |
| 5 | Queues unknown accounts for evaluation | karmaFarmingSubsCheck.ts:queueKarmaFarmingAccounts |
| 6 | Evaluates each account using all evaluators | karmaFarmingSubsCheck.ts:evaluateAndHandleUser |
| 7 | If evaluators match + can auto-ban + meet threshold → auto-ban | karmaFarmingSubsCheck.ts:evaluateAndHandleUser |
The list of karma-farming subs is configurable — it’s stored in evaluator variables (generic:karmafarminglinksubs and generic:karmafarminglinksubsnsfw) which are loaded from wiki pages on r/BotBouncer. The list is NOT hardcoded in the source code — it’s maintained as a wiki configuration that can be updated without redeploying.
Key detail from karmaFarmingSubsCheck.ts:
- Checks up to 200 subs per run
- Checks subs that haven’t been checked in the last 25 minutes
- Processes accounts in cohorts (evens/odds) for load balancing
- Processes 10 accounts per batch
- If >3 failures in a batch, enters a 2-minute cooldown
Mode 3: Real-Time Content Detection (On Client Subreddits)
When ANY user posts or comments on a subreddit that has BotBouncer installed:
| Step | What Happens | Source File |
|---|---|---|
| 1 | Post or comment is created on a client subreddit | handleContentCreation.ts |
| 2. If author already classified as banned → ban + remove immediately | handleClientPostOrComment.ts:handleContentCreation | |
3. If author unknown → run ALL evaluators’ preEvaluatePost or preEvaluateComment | handleClientPostOrComment.ts:handleClientCommentCreate | |
| 4. If any evaluator’s pre-check triggers → run full evaluation | handleClientPostOrComment.ts:checkAndReportPotentialBot | |
| 5. Full evaluation fetches user’s 100 most recent items and runs all evaluators | handleClientPostOrComment.ts:checkAndReportPotentialBot | |
6. If any evaluator returns isLikelyBot = true → auto-submit to r/BotBouncer | handleClientPostOrComment.ts:checkAndReportPotentialBot | |
| 7. Rate limited: re-checks a user at most once per 15 minutes | handleClientPostOrComment.ts:handleClientCommentCreate |
Key detail: The preEvaluateComment and preEvaluatePost methods are FAST pre-checks — they decide whether to trigger the full evaluation. Each evaluator has different pre-check logic (see §3). The full evaluation fetches the user’s complete history and runs all evaluators in depth.
3. The 24 Evaluators (Actual Detection Logic)
From allEvaluators.ts, these are ALL the evaluators, in the order they run:
Tier 1: Account-Only Evaluators (Fastest — no history needed)
| # | Evaluator | What It Detects | Pre-Check Logic | Full Check Logic |
|---|---|---|---|---|
| 1 | EvaluateBadUsername | Bot-like username patterns | Checks username against regex patterns from config | If username matches banned patterns |
| 2 | EvaluateBioText | Bot text in user bio/profile description | Checks if bio text matches banned regex patterns | Checks bio against bantext regex list; skips if comment karma > 2000 AND link karma > 2000 |
| 3 | EvaluateBioTextDefinedHandles | Specific bio text patterns (configurable handles) | Same as BioText but with defined handle patterns | Same |
| 4 | EvaluateBadDisplayName | Bot display name patterns | Checks display name against regex | If display name matches banned patterns |
| 5 | EvaluateBadDisplayNameDefinedHandles | Specific display name patterns | Same with defined handles | Same |
| 6 | EvaluateObfuscatedBioKeywords | Obfuscated keywords in bio (e.g., using symbols to bypass filters) | Checks bio for obfuscated versions of banned keywords | Detects keyword obfuscation patterns |
Tier 2: Content Evaluators (Need post/comment history but not social links)
| # | Evaluator | What It Detects | Pre-Check Logic | Full Check Logic |
|---|---|---|---|---|
| 7 | EvaluateDomainSharer | Accounts sharing a specific domain across posts | Checks if post URL matches watched domains | Checks if user has multiple posts sharing the same domain |
| 8 | EvaluatePinnedPostTitles | Bots with identical pinned posts on their profile | Checks if pinned post title matches known patterns | Checks for specific pinned post title patterns |
| 9 | EvaluateSelfComment | Accounts commenting on their own posts | Checks if comment is on own post | Checks for self-comment patterns |
| 10 | EvaluatePostTitle | Posts with titles matching known bot patterns | Checks post title against bantext regex list | Checks NSFW posts from last week against banned title regexes; skips if comment karma > 2000 AND link karma > 5000 |
| 11 | EvaluatePostTitleDefinedHandles | Specific post title patterns (configurable) | Same with defined handles | Same |
| 12 | EvaluatePostTitleMulti | Multiple post titles matching bot patterns | Checks against multiple regex patterns | Checks for posts matching multiple criteria |
| 13 | EvaluateSuspiciousFirstPost | First post is suspicious (image/video on specific subs) | Checks if post is on a watched subreddit AND is an i.redd.it/v.redd.it/gallery post | Checks if account has exactly 1 post (on watched sub, image/video), ≤1 comment, and the comment came before the post; pre-check: account <14 days old AND comment karma <50 |
| 14 | EvaluateInconsistentAgeBot | NSFW accounts with inconsistent ages in post titles | Checks if NSFW post title contains an age number | Checks if user has ≥4 NSFW posts in last 2 weeks with ≥3 different ages found in titles; pre-check: comment karma <50 |
| 15 | EvaluateInconsistentGenderBot | NSFW accounts with inconsistent gender in post titles (M4F, F4M, etc.) | Checks NSFW post title for gender markers | Checks for inconsistent gender markers across NSFW posts |
| 16 | EvaluateWorldTraveller | Accounts posting in unrelated geo-subreddits (e.g., posting in r/London AND r/NYC AND r/Sydney) | Checks if post is on a geo-sub | Checks if user posts across multiple unrelated geographic subreddits |
| 17 | EvaluateCommentPhrase | Comments containing specific bot phrases | Checks if comment body matches a regex from phrases config | Checks if user has ≥1 comment matching a phrase regex; pre-check: account <60 days old AND comment karma <100 |
| 18 | EvaluateTGGroup | Telegram group spam bots | Checks for Telegram links in content | Checks for Telegram promotion patterns |
Tier 3: Complex Evaluators (Need social links or deeper analysis)
| # | Evaluator | What It Detects | Pre-Check Logic | Full Check Logic |
|---|---|---|---|---|
| 19 | EvaluateWarmupBot | Moderator accounts that are warmup bots | Checks if post title matches postTitleRegexes | Checks if user is a mod of a subreddit matching subredditRegexes AND has posts matching postTitleRegexes |
| 20 | EvaluateSocialLinks | Accounts with suspicious social links (OnlyFans, Instagram, etc.) | Checks if any social link matches badlinks config | Checks social links AND post URLs for bad domains; pre-check: (comment karma <500 AND account <2 months old) OR account >5 years old OR NSFW |
| 21 | EvaluateBotGroupAdvanced | The most powerful evaluator — flexible rule-based bot detection | Depends on group config | See §4 below |
| 22 | EvaluateTitleCopyBot | Bots whose comments copy the post title verbatim | Checks if comment body === post title | Checks if the 5 most recent comments all copy their respective post titles exactly, user has 0 posts, and all comments are single-line; pre-check: account <180 days old |
| 23 | EvaluateTextInNsfwImages | NSFW bots with text/watermarks on images (social handles) | Checks NSFW image posts | Analyzes NSFW images for embedded text/watermarks |
| 24 | EvaluateBotGroupAdvancedInternal | Same as BotGroupAdvanced but with experimental features enabled | Same | Same as BotGroupAdvanced but can use new features |
4. EvaluateBotGroupAdvanced — The Most Dangerous Evaluator
This is the most sophisticated and flexible evaluator. It’s a rule-based system that can be configured via wiki pages to detect virtually any bot pattern — without code changes.
How it works:
From EvaluateBotGroupAdvanced.ts (54,586 characters of source — the largest evaluator by far):
-
Bot Groups are defined in evaluator variables (configurable via wiki). Each group has:
name— group identifiersubmitterName— optional, only trigger if reported by specific submitter- Account criteria (age, karma, bio text, display name, social links, etc.)
- History criteria (posts/comments matching specific patterns)
- Social link criteria
-
Account Matching (
accountMatchesGroup):- Checks account age (max/min in days, or date range)
- Checks comment karma and link karma thresholds
- Checks bio text against regexes
- Checks display name against regexes
- Checks if account is NSFW
- Checks social links against patterns
-
History Matching (
historyMatchesCriteriaGroup):- Can match posts or comments with criteria like:
subredditName— must be in specific subredditsnotSubredditName— must NOT be in specific subredditsbodyRegex— comment/post body must match regextitleRegex— post title must match regex (for posts)minBodyLength/maxBodyLength— body length constraintsminParaCount/maxParaCount— paragraph count constraintsminKarma/maxKarma— score constraintsisTopLevel— for comments, must be top-levelisCommentOnOwnPost— comment on own postpostAuthorNameRegex— parent post’s author matches regexpostTitleRegex— parent post’s title matches regexpostBodyRegex— parent post’s body matches regexpostUrlRegex— parent post’s URL matches regexage— content age constraintsedited— whether content was editedmatchesNeeded— minimum number of matching itemsdistinctSubsNeeded— minimum number of distinct subreddits
- Can match posts or comments with criteria like:
-
Logical Operators: Criteria can be combined with:
some— OR logic (any sub-criteria must match)every— AND logic (all sub-criteria must match)not— negation
-
hasMoreThanOneCommentOnPosts: Can check if the user has multiple comments on the same post (detecting double-commenting behavior)
What this means for us:
BotBouncer operators can create a custom bot group that matches our exact behavior pattern without writing any code. For example, they could configure a group that matches:
- Accounts <180 days old
- Comment karma <250
- Has ≥3 comments in
bodyRegexmatching “what’s.*underrated|what’s.*discovered|what.*you.*think” - Comments in ≥2 of: NoStupidQuestions, AmItheAsshole, CasualConversation, TheTopicOfTheDay
- isTopLevel: true
This would catch our exact “question-back” pattern. The config is on a private wiki page — we can’t see what groups are currently defined.
5. OpenAI Integration — AI-Assisted Detection
What the aiAnalysis/ module actually does:
From the source code, BotBouncer uses OpenAI in two ways:
5a. OpenAI Summary Generation (createAISummary.ts)
When an account is submitted to r/BotBouncer, an OpenAI summary is generated to help moderators review:
| Step | What Happens | Source |
|---|---|---|
| 1 | Gathers user info: 100 most recent posts/comments, social links, account properties | gatherUserDetailsForOpenAI.ts:getUserInfoForOpenAI |
| 2 | For each comment, also fetches the parent post title and URL | gatherUserDetailsForOpenAI.ts:getUserInfoForOpenAI |
| 3 | Includes initial evaluator results (which evaluators matched) | createAISummary.ts:generateOpenAISummary |
| 4 | Includes moderator notes about the user | createAISummary.ts:generateOpenAISummary |
| 5 | Sends all this to OpenAI via a prompt template | createAISummary.ts:generateOpenAISummary |
| 6 | OpenAI model: gpt-5.4-mini (default) | openAI.ts:callOpenAI |
| 7 | Temperature: 0.7 (default) | openAI.ts:callOpenAI |
| 8 | Result is posted as a comment on the BotBouncer tracking post (removed, not public) | createAISummary.ts:createResponse |
| 9 | Cached for 1 day per user | createAISummary.ts:getCacheKeyForUserSummary |
Minimum requirements for AI summary (from createAISummary.ts):
- Account must be ≥30 days old (
openAIMinimumAccountAgeInDays) - User must have ≥25 content items (
openAIMinimumContentCount)
What data is sent to OpenAI:
{
"userInfo": {
"username": "...",
"commentKarma": 216,
"linkKarma": 1,
"hasVerifiedEmail": true,
"isModerator": false,
"createdAt": "2026-03-12...",
"socialLinks": [{"title": "...", "url": "..."}]
},
"history": [
{
"type": "comment",
"content": "love how this lets us share everything from books to music...",
"karma": 1,
"subredditName": "TheTopicOfTheDay",
"createdAt": "2026-08-10...",
"isTopLevel": true,
"edited": false,
"parentPostInfo": {
"title": "The topic of the day is... Media Monday!",
"createdAt": "2026-08-10...",
"url": "..."
}
},
...
]
}This means OpenAI sees: full comment text, subreddit, score, timestamp, whether it’s top-level, whether it was edited, AND the parent post’s title and URL. The AI can then judge whether the comment is relevant to the post, answers the question, or sounds AI-generated.
5b. Ask AI Feature (askAI.ts)
Moderators can type !askai <question> in modmail to ask OpenAI a specific question about a user. This sends the same user data to OpenAI along with the moderator’s specific question.
5c. OpenAI for Evaluation
From settings.ts, there are THREE separate OpenAI API keys:
OpenAIKey— for general AI summariesOpenAIEvaluationKey— for evaluation (used incheckAndReportPotentialBot)OpenAIAdminKey— for admin operations
From handleClientPostOrComment.ts:checkAndReportPotentialBot:
if (evaluator.needsOpenAiKey && openAIEvaluationKey) {
evaluator.setOpenAiKey(openAIEvaluationKey);
}This means some evaluators use OpenAI as part of the automated detection logic — not just for summaries. The needsOpenAiKey flag on UserEvaluatorBase is false by default, but can be overridden by evaluators that need AI analysis.
6. The User Summary — What BotBouncer Knows About Each Account
From userSummary.ts, when an account is evaluated, BotBouncer generates a detailed summary including:
| Data Point | How It’s Computed | Why It Matters |
|---|---|---|
| Account age | Time since createdAt | Young accounts are more suspicious |
| Comment karma | From profile | Low comment karma + high activity = bot pattern |
| Post karma | From profile | Lopsided post/comment ratio is suspicious |
| Verified email | From profile | Unverified email = lower trust |
| Is moderator | From profile | Mods are exempt from banning |
| Social links | From profile | Suspicious links (OnlyFans, Instagram, etc.) |
| Display name | From profile | Bot display name patterns |
| Bio text | From profile, with banned domains redacted | Bot bio text patterns |
| Original bio | Stored separately, compared to current | Detects bio changes after detection |
| Comment subreddits | countBy of subreddits in comment history | Shows karma-farming sub concentration |
| Comments per post | countBy of postId counts | Detects multiple comments on same post |
| First comment time | Time between account creation and first comment | Bots often comment immediately after creation |
| Time between comments | Min, 10th percentile, max, average, median | Uniform timing = automation |
| Time between posts | Same metrics for posts | Same |
| Edited posts % | Percentage of posts that were edited | Bots rarely edit; humans often do |
| Activity by time of day | Histogram of activity by hour | Shows timezone mismatch or 24/7 automation |
| Post subreddits | countBy of subreddits in post history | Shows targeting |
| First post time | Time between account creation and first post | Same as first comment |
Key insight: BotBouncer explicitly computes timing metrics — min/10th-percentile/max/average/median time between comments and posts. This is exactly the kind of analysis that would detect our RPA pipeline’s regular 7-second delays and scheduled commenting windows.
7. What BotBouncer Does NOT Do
Based on reading the actual source code, here’s what BotBouncer cannot detect:
| What It Doesn’t Check | Why |
|---|---|
| IP addresses | No IP checking in any evaluator — that’s Reddit’s admin-level system, not BotBouncer |
| Browser fingerprints | No fingerprint checking — same reason |
| Cookie/session linking | No cookie analysis |
| Cross-account timing correlation | Evaluators run per-account, not across accounts |
| Vote manipulation | No vote analysis in any evaluator |
| Direct AI-text detection (per-comment) | The aiAnalysis module uses OpenAI for summaries, not for per-comment AI detection. The CommentPhrase evaluator checks for specific regex patterns, not general AI-ness. However, OpenAI could flag AI patterns in the summary it generates for moderators. |
| Account creation IP | No IP analysis at all |
Important clarification: BotBouncer is a subreddit-level tool, not a platform-level tool. It does NOT do IP analysis, fingerprinting, or network-level detection. That’s Reddit’s “anti-evil” system. BotBouncer only analyzes publicly visible account behavior: post titles, comment text, bio text, social links, display name, username, and timing patterns.
8. Ban Message — The Exact Text
From settings.ts:CONFIGURATION_DEFAULTS.banMessage:
Bots and bot-like accounts are not welcome on /r/{subreddit}.
[I am a bot, and this action was performed automatically](/r/BotBouncer/wiki/index).
**If you wish to appeal the classification of the /u/{account} account, please
/message /r/BotBouncer rather than replying to this message.**
This is the default ban message. Subreddits can customize it. The “I am a bot, and this action was performed automatically” line is what we saw in our ban messages.
9. Exemptions — How to Not Get Banned
From the source code, these accounts are exempt from BotBouncer:
| Exemption | Source | How It Works |
|---|---|---|
| Approved Submitters | handleClientPostOrComment.ts:handleContentCreation | If exemptApprovedUsers setting is true (default) and user is an approved contributor of the sub, skip ban |
| Moderators | handleClientPostOrComment.ts:handleContentCreation | If user is a mod of the sub, skip ban |
| Proof flair | handleClientPostOrComment.ts:handleContentCreation | If user has a flair with CSS class ending in proof (e.g., botbustproof), skip ban |
| Previously unbanned | handleClientPostOrComment.ts:handleContentCreation | If autoWhitelist is true (default) and user was previously unbanned, skip ban |
| High karma (BioText) | EvaluateBioText.ts:preEvaluateUser | If comment karma > 2000 AND link karma > 2000, skip bio text check |
| High karma (PostTitle) | EvaluatePostTitle.ts:preEvaluateUser | If comment karma > 2000 AND link karma > 5000, skip post title check |
| High karma (CommentPhrase) | EvaluateCommentPhrase.ts:preEvaluateUser | If comment karma ≥ 100 OR account age > 60 days, skip comment phrase check |
| High karma (SuspiciousFirstPost) | EvaluateSuspiciousFirstPost.ts:preEvaluateUser | If comment karma ≥ 50 OR account age > 14 days, skip suspicious first post check |
| High karma (SocialLinks) | EvaluateSocialLinks.ts:preEvaluateUser | If comment karma ≥ 500 AND account > 2 months old, skip social links check (unless account > 5 years old or NSFW) |
| Old account (InconsistentAge) | EvaluateInconsistentAgeBot.ts:preEvaluateUser | If comment karma ≥ 50, skip inconsistent age check |
| Old account (TitleCopyBot) | EvaluateTitleCopyBot.ts:preEvaluateUser | If account > 180 days old, skip title copy check |
| Service bots | handleReportUser.ts:reportFormHandler | Bots that respond to user commands (e.g., RemindMeBot) are out of scope |
Key pattern: Most evaluators have karma thresholds that exempt high-karma accounts. The thresholds vary:
- Bio text: 2000 comment + 2000 link karma
- Post title: 2000 comment + 5000 link karma
- Comment phrase: 100 comment karma OR 60 days account age
- Suspicious first post: 50 comment karma OR 14 days account age
- Social links: 500 comment karma AND 2 months age
- Title copy: 180 days account age
For our accounts: Most of our banned accounts had <250 comment karma, so they were NOT exempt from any evaluator. If we had built accounts to 2000+ comment karma before farming in BotBouncer-monitored subs, most evaluators would have skipped them.
10. The canAutoBan and banContentThreshold System
Each evaluator has two flags that determine whether a match leads to automatic ban:
| Flag | Default | Purpose |
|---|---|---|
canAutoBan | true | If true, this evaluator’s match can trigger an automatic ban without human review |
banContentThreshold | 10 | Minimum number of content items (posts+comments) the user must have for an auto-ban |
From handleControlSubAccountEvaluation.ts:evaluateUserAccount:
const metThreshold = itemCount >= bot.banContentThreshold;If a user has fewer items than the threshold, the evaluator match is logged but doesn’t trigger auto-ban — it goes to manual review instead.
Thresholds by evaluator (from source code):
| Evaluator | banContentThreshold | Notes |
|---|---|---|
| BioText | 0 | Any match = auto-ban |
| SocialLinks | 0 | Any match = auto-ban |
| WarmupBot | 0 | Any match = auto-ban |
| CommentPhrase | 1 | Just 1 matching comment needed |
| SuspiciousFirstPost | 1 | Just 1 suspicious post needed |
| PostTitle | 1 | Just 1 matching post title needed |
| TitleCopyBot | 5 | 5 comments copying post titles needed |
| InconsistentAgeBot | 6 | 6 NSFW posts with inconsistent ages needed |
| BotGroupAdvanced | 10 (default) | 10 content items needed (configurable per group) |
11. How Our Accounts Got Caught — Mapping to Source Code
Based on the actual source code, here’s what likely happened to our accounts:
The Trigger Chain:
| Step | What Happened | Source File/Function |
|---|---|---|
| 1 | Our account commented on r/TheTopicOfTheDay (which has BotBouncer installed) | handleContentCreation.ts:handleCommentCreate |
| 2 | BotBouncer checked if the author was already classified → No | handleClientPostOrComment.ts:handleClientCommentCreate |
| 3 | BotBouncer ran preEvaluateComment on all evaluators | handleClientPostOrComment.ts:handleClientCommentCreate |
| 4 | CommentPhrase evaluator’s preEvaluateComment may have triggered — if our “question-back” phrases are in the configured phrases regex list | EvaluateCommentPhrase.ts:preEvaluateComment |
| 5 | OR: No pre-check triggered, but the comment was visible to a human moderator | N/A — human detection path |
| 6 | The human moderator clicked “Report to /r/BotBouncer” | handleReportUser.ts:handleReportUser |
| 7 | Moderator added context: “asking a question and not directly answering the post” | handleReportUser.ts:reportFormDefinition |
| 8 | Submission queued + post created on r/BotBouncer | externalSubmissions.ts:addExternalSubmissionFromClientSub |
| 9 | Full evaluation ran: all 24 evaluators against the user’s 100 most recent items | handleControlSubAccountEvaluation.ts:evaluateUserAccount |
| 10 | BotGroupAdvanced may have matched — if a bot group is configured for accounts that comment on karma-farming subs with question-back patterns | EvaluateBotGroupAdvanced.ts:evaluate |
| 11 | CommentPhrase may have matched — if question-back phrases are in the config | EvaluateCommentPhrase.ts:evaluate |
| 12 | OR: No evaluator auto-banned, so it went to manual review | handleControlSubAccountEvaluation.ts:handleControlSubAccountEvaluation |
| 13 | OpenAI summary generated for the moderator | createAISummary.ts:generateOpenAISummary |
| 14 | OpenAI received our comment text + parent post title + full history and may have flagged the AI pattern | gatherUserDetailsForOpenAI.ts:getUserInfoForOpenAI |
| 15 | Human moderator reviewed → classified as “Banned” | Manual action |
| 16 | Account auto-banned from r/TheTopicOfTheDay + ALL participating subs where it had content in the past week | handleClientPostOrComment.ts:handleContentCreation (retroactive) |
| 17 | ”Overview for hailybarnes37” post created on r/BotBouncer | postCreation.ts |
Why Small-Location7862 survived sitewide but hailybarnes37 didn’t:
BotBouncer only bans at the subreddit level. The escalation to sitewide suspension is done by Reddit’s own systems (not BotBouncer). From the BotBouncer docs: “Bot accounts should be reported to Reddit as Spam → Disruptive use of bots or AI. Reddit’s spam detection is getting better all the time and in many cases, the bot’s account will be shadowbanned immediately.”
BotBouncer explicitly recommends that moderators also report the account to Reddit — this is the path to sitewide suspension. The difference between hailybarnes37 (sitewide banned) and Small-Location7862 (not sitewide banned) may simply be whether the reporting moderator also filed a Reddit spam report.
12. What We Can’t See (And Why It Matters)
The most critical detection logic is in the evaluator variables — the configuration that defines what patterns to look for. These are stored on private wiki pages on r/BotBouncer that we cannot read:
| Hidden Config | Where It’s Stored | What It Contains |
|---|---|---|
generic:karmafarminglinksubs | r/BotBouncer wiki (evaluator-config/evaluatorvars) | List of subreddits BotBouncer proactively scans |
generic:karmafarminglinksubsnsfw | Same wiki | NSFW karma-farming subs list |
commentphrase:phrases | Same wiki | Regex patterns for bot comment phrases |
botgroupadvanced:* | Same wiki | Bot group definitions (account criteria + history criteria) |
biotext:bantext | Same wiki | Regex patterns for banned bio text |
posttitle:bantext | Same wiki | Regex patterns for banned post titles |
generic:sitewidebanneddomains | Same wiki | Domains that trigger automatic evaluation |
This means we don’t know:
- Which subreddits are on the karma-farming list (but r/TheTopicOfTheDay clearly is, since that’s where our reports came from)
- What comment phrases trigger the CommentPhrase evaluator
- What bot groups are configured in BotGroupAdvanced
- Whether our specific commenting patterns are explicitly targeted
What we DO know from behavior:
- r/TheTopicOfTheDay is on the karma-farming list (our accounts were proactively scanned there)
- NoStupidQuestions, AmItheAsshole, CasualConversation, Advice, TheTopicOfTheDay are likely all on the list (our accounts got banned from all of them simultaneously)
- The “question-back” pattern was noticed by human moderators, which means it’s likely also in the CommentPhrase regex config
13. Implications for Avoiding Detection
Based on the actual source code, here’s what would and wouldn’t help:
What Would Help:
| Strategy | Why It Works (from source code) | Source Evidence |
|---|---|---|
| Build comment karma to 2000+ before farming | BioText and PostTitle evaluators skip accounts with >2000 comment + >2000 link karma | EvaluateBioText.ts:preEvaluateUser, EvaluatePostTitle.ts:preEvaluateUser |
| Build comment karma to 100+ | CommentPhrase evaluator skips accounts with ≥100 comment karma OR >60 days old | EvaluateCommentPhrase.ts:preEvaluateUser |
| Don’t comment on known karma-farming subs | Proactive scanning only covers subs on the karmafarminglinksubs list | karmaFarmingSubsCheck.ts:getDistinctAccounts |
| Vary timing between comments | UserSummary explicitly computes min/10th-percentile/max/average/median time between comments | userSummary.ts:getCommonEntriesForContent |
| Edit some comments | UserSummary tracks edited post percentage; bots rarely edit | userSummary.ts:getSummaryForUser |
| Have posts, not just comments | TitleCopyBot explicitly checks if (this.getPosts().length > 0) return false — having posts exempts you | EvaluateTitleCopyBot.ts:evaluate |
| Don’t comment on the same post twice | BotGroupAdvanced can check hasMoreThanOneCommentOnPosts | EvaluateBotGroupAdvanced.ts:evaluate |
| Match comment content to post content | OpenAI summary sends parent post title + comment body — AI can judge relevance | gatherUserDetailsForOpenAI.ts:getUserInfoForOpenAI |
| Don’t use question-back patterns | CommentPhrase can regex-match specific phrases; BotGroupAdvanced can match bodyRegex patterns | EvaluateCommentPhrase.ts, EvaluateBotGroupAdvanced.ts |
| Be active for >14 days before posting on watched subs | SuspiciousFirstPost evaluator skips accounts >14 days old | EvaluateSuspiciousFirstPost.ts:preEvaluateUser |
| Have >50 comment karma before posting on watched subs | SuspiciousFirstPost and InconsistentAge skip accounts with ≥50 comment karma | EvaluateSuspiciousFirstPost.ts:preEvaluateUser, EvaluateInconsistentAgeBot.ts:preEvaluateUser |
What Would NOT Help (Myth Busting):
| Strategy | Why It Doesn’t Work | Source Evidence |
|---|---|---|
| Change IP address | BotBouncer does NOT check IP addresses at all | No IP checking in any evaluator |
| Change browser fingerprint | BotBouncer does NOT check fingerprints | No fingerprint checking in any evaluator |
| Use different proxies | BotBouncer does NOT check network info | No network analysis in any evaluator |
| Deliberate typos | BotBouncer doesn’t check spelling — it checks structural patterns via regex and OpenAI | EvaluateCommentPhrase uses regex on phrases, not spelling |
| Post at “human-like” intervals only | While timing IS analyzed, it’s in the summary for human review, not an automatic ban criterion (except via BotGroupAdvanced config) | userSummary.ts computes timing for the summary, not for auto-ban |
14. Source Code References
| File | Repo | Key Function |
|---|---|---|
karmaFarmingSubsCheck.ts | bot-bouncer | Proactive scanning of karma-farming subs |
handleClientPostOrComment.ts | bot-bouncer | Real-time content detection on client subs |
handleReportUser.ts | bot-bouncer | Human moderator reporting flow |
handleControlSubAccountEvaluation.ts | bot-bouncer | Full account evaluation on r/BotBouncer |
handleContentCreation.ts | bot-bouncer | Event router for content creation |
handleControlSubComment.ts | bot-bouncer | Comment handling on r/BotBouncer itself |
handleControlSubSubmission.ts | bot-bouncer | Post/submission handling on r/BotBouncer |
externalSubmissions.ts | bot-bouncer | External submission queue system |
createAISummary.ts | bot-bouncer | OpenAI summary generation |
gatherUserDetailsForOpenAI.ts | bot-bouncer | Data collection for OpenAI |
openAI.ts | bot-bouncer | OpenAI API wrapper (gpt-5.4-mini) |
askAI.ts | bot-bouncer | Modmail !askai command |
userSummary.ts | bot-bouncer | Detailed user summary with timing analysis |
settings.ts | bot-bouncer | App settings, ban message, action types |
constants.ts | bot-bouncer | Job names, flair IDs, evaluator imports |
types.ts | bot-bouncer | UserStatus enum (pending/banned/service/organic/purged/retired/inactive) |
evaluatorVariables.ts | bot-bouncer | Wiki-based evaluator config system |
allEvaluators.ts | bot-bouncer-evaluation | Complete evaluator list and order |
UserEvaluatorBase.ts | bot-bouncer-evaluation | Base class for all evaluators |
EvaluateBotGroupAdvanced.ts | bot-bouncer-evaluation | Flexible rule-based bot detection (54K chars) |
EvaluateCommentPhrase.ts | bot-bouncer-evaluation | Comment phrase regex matching |
EvaluateWarmupBot.ts | bot-bouncer-evaluation | Moderator warmup bot detection |
EvaluateBioText.ts | bot-bouncer-evaluation | Bio text pattern detection |
EvaluateTitleCopyBot.ts | bot-bouncer-evaluation | Title-copying bot detection |
EvaluateSuspiciousFirstPost.ts | bot-bouncer-evaluation | First post suspicious pattern detection |
EvaluateInconsistentAgeBot.ts | bot-bouncer-evaluation | Inconsistent age in NSFW posts |
EvaluateSocialLinks.ts | bot-bouncer-evaluation | Suspicious social link detection |
EvaluatePostTitle.ts | bot-bouncer-evaluation | Post title pattern detection |
changelog.md | bot-bouncer | Version history of detection additions |