DEV Community

Cover image for I got tired of bot detection in automation testing, so I wrote this 4-line Python fix
Dhiraj Das
Dhiraj Das

Posted on • Edited on • Originally published at dhirajdas.dev

I got tired of bot detection in automation testing, so I wrote this 4-line Python fix

🎯

Undetectable Automation

  • The Reality: Standard Headless Chrome is dead
  • The Fix: Use Xvfb to fake a display on Linux
  • Heuristics: Human-like clicking/hovering beats scripts
  • Result: Bypassing Cloudflare, Turnstile & 403s

SB Stealth Wrapper Cover

Click to zoom

Handling bot detection with SB Stealth Wrapper

The Cat and Mouse Game

The Cat and Mouse Game

Bot detection AI is getting smarter every day. Static user-agents strings no longer work. You need behavioral stealth.

πŸ›‘οΈ

It happened again. My script was perfect locally. I pushed it to CI, and... 403 Forbidden. I wasn't testing a bank; I was testing a landing page. The modern web has become hostile to automation.

Developers are tired of getting blocked by 403 Forbidden errors, Cloudflare Turnstiles, and "Verify you are human" loops when using Selenium or Playwright. We spend more time fighting bot detection than writing actual tests.

The Old Way (The Struggle)

We've all been there. You try to make Selenium 'stealthy' by piling on options, changing user agents, and praying.

# The "Please don't ban me" starter pack
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("user-agent=Mozilla/5.0...")
# ... 20 more lines of hoping it works
driver = webdriver.Chrome(options=options)

# Result: Still blocked.
Enter fullscreen mode Exit fullscreen mode

The New Way (The 4-Line Fix)

I built sb-stealth-wrapper to solve this once and for all. It wraps SeleniumBase's UC Mode with intelligent defaults that just work.

from sb_stealth_wrapper import StealthBot

# 1. Initialize with one line (Auto-handles Linux/Xvfb)
with StealthBot(headless=True) as bot:
    # 2. Navigate safely
    bot.safe_get("https://nowsecure.nl")

    # 3. Interact like a human
    bot.smart_click("#verify")
Enter fullscreen mode Exit fullscreen mode

The Secret Sauce: Why it Works

1. The Linux/Xvfb Hack

Headless Chrome on Linux is a dead giveaway. It screams 'I am a bot' because it lacks a display server. My wrapper detects if it's running on Linux and automatically spawns a virtual display (Xvfb). This means Chrome *thinks* it has a screen, giving you the stealth of a headed browser with the convenience of a headless server.

2. Heuristic Clicking

bot.click() is too perfect. It's instantaneous and mechanical. smart\_click() is different. It scrolls the element into view, hovers for a split second, and then clicks. If the element is obscured (a common anti-bot tactic), it intelligently falls back to a JavaScript click. It feels human.

Benchmark Results

I ran a comparison against standard Selenium and Playwright on a tough bot challenge (NowSecure). The results speak for themselves.

Run python examples/benchmark_comparison.py
=== Starting Benchmark Comparison ===
Target: https://nowsecure.nl
Timeout: 15s

[Benchmark] Running Standard Selenium (Chrome)...
[Result] Selenium: FAIL (0.50s) - Message: session not created: Chrome instance exited. Examine ChromeDriver verbose log to determine ...

[Benchmark] Running Playwright (Chromium)...
[Result] Playwright: FAIL (0.36s) - BrowserType.launch: Target page, context or browser has been closed
Browser logs:

╔════════════════...

[Benchmark] Running StealthBot...
[StealthBot] Linux detected. Enabling Xvfb and disabling native headless mode for stealth.
[StealthBot] Navigating to https://nowsecure.nl...
[StealthBot] Waiting for page content...
[StealthBot] Challenge passed!
   -> navigator.webdriver: False
[Result] StealthBot: PASS (3.65s)

========================================
Tool            | Status     | Time
----------------------------------------
Selenium        | FAIL       | 0.50s
Playwright      | FAIL       | 0.36s
StealthBot      | PASS (Bot Detected: False) | 3.65s
========================================
Enter fullscreen mode Exit fullscreen mode

Put This to Test Now

You don't need complex error handling to see the magic. Here is the raw proof.

We will run this in headless=True (which usually fails instantly) against NowSecure (a tough bot challenge).

from sb_stealth_wrapper import StealthBot

if __name__ == "__main__":
    # 1. Initialize (Auto-handles Xvfb/Headless)
    with StealthBot(headless=True) as bot:

        print("--- Testing Protected Site (nowsecure.nl) ---")
        bot.safe_get("https://nowsecure.nl")

        # 2. Verify we passed the challenge
        try:
            # We wait for the success header (Note: The text changed from "OH YEAH" recently)
            bot.sb.wait_for_text("NOWSECURE", "h1", timeout=30)
            print("βœ… SUCCESS: Bypassed Cloudflare/Turnstile!")
            bot.save_screenshot("success_proof")

        except Exception as e:
            print(f"❌ FAILURE: Detection triggered. Error: {e}")

            # 3. Auto-Debug (Saves HTML so you can see why it failed)
            with open("debug_failure.html", "w", encoding="utf-8") as f:
                f.write(bot.sb.get_page_source())
            print("Dumped page source to debug_failure.html")

    print("Test Complete.")
Enter fullscreen mode Exit fullscreen mode

That is it. If you want the robust, production-ready version with error handling and HTML debugging, check out the full example on GitHub:

examples/robust_demo.py

Get It Now

Stop writing boilerplate. Start writing tests.

pip install sb-stealth-wrapper
Enter fullscreen mode Exit fullscreen mode

Credits

This project stands on the shoulders of giants. A massive shoutout to the SeleniumBase team for their incredible work on UC Mode. sb-stealth-wrapper is essentially a love letter to their engineering, wrapping it in a way that makes it even more accessible for specific use cases.

Ethical Disclaimer: This tool is for educational purposes and for testing environments you own. Do not use it for unauthorized scraping or bypassing security controls on websites you do not have permission to test.

Top comments (0)