Build a Stealth Web Scraper
Bypass bot detection and extract structured data using CloakBrowser.
Introduction
30 Second Summary
Every time you browse the web, websites are watching how your browser behaves. They check dozens of hidden signals to decide if you're a real person or a bot. Most automated tools fail these checks immediately.
In this project, you will build a stealth web scraper using CloakBrowser that passes bot detection tests where standard automation tools fail. You will extract structured data from a website while flying under the radar as a normal human browser.
What You'll Build
A Python-based stealth web scraper powered by CloakBrowser that bypasses anti-bot detection systems and extracts structured JSON data from websites.
By the end of this project, you'll have:
- A working stealth scraper that passes bot detection tests where stock Playwright fails.
- Extracted structured JSON data from a real website using CSS selectors with anti-bot bypass.
- A reusable scraper template with humanized behavior, fingerprint pinning, and configurable stealth settings.
- Secret Mission: persistent browser profiles that simulate a returning visitor across multiple scraping sessions.
Are there any prerequisites?
You need a basic understanding of what web scraping is. No coding experience is required. AI agents in your IDE will assist with writing the code, and the project guides you through each concept.
Install CloakBrowser and Verify Setup
CloakBrowser is a stealth Chromium browser with 58 source-level C++ patches that make it invisible to bot detection systems. It works as a drop-in replacement for Playwright, so you write standard Playwright API code with zero new syntax to learn.
In this step, you'll install the CloakBrowser pip package, set up the Playwright system dependencies it needs, and run a quick verification script to confirm the stealth Chromium binary launches correctly.
In this step, get ready to:
- Install CloakBrowser and Playwright system dependencies.
- Verify the stealth Chromium binary launches and loads a page.
- Confirm the binary version and installation status.
Install CloakBrowser and Playwright dependencies
CloakBrowser needs two things: its Python wrapper package and the system-level libraries that Chromium requires to render pages.
- In Antigravity IDE, open a terminal panel.
- Install CloakBrowser and the Playwright system dependencies by running these commands:
pip install cloakbrowser==0.3.31
playwright install-deps chromium
What do these commands do?
- pip install cloakbrowser==0.3.31 installs the CloakBrowser Python wrapper. This package manages the stealth Chromium binary and exposes the Playwright-compatible API you'll use throughout this project.
- playwright install-deps chromium installs operating system libraries (fonts, codecs, GPU support) that Chromium needs to run. You do NOT need playwright install chromium because CloakBrowser downloads its own patched binary separately.
- Confirm both commands complete without errors. You should see Successfully installed cloakbrowser-0.3.31 in the pip output.
Seeing a network timeout or download error?
- If pip install fails with a timeout, check that you are not behind a corporate proxy or VPN that blocks PyPI. Try disconnecting from the VPN and running the command again.
- If playwright install-deps fails, make sure you are running the terminal with administrator privileges. On Windows, right-click your terminal and select Run as administrator.
- Help me troubleshoot my CloakBrowser installation
Verify the installation works
The first time CloakBrowser launches, it auto-downloads its stealth Chromium binary (~200MB) to ~/.cloakbrowser/. You'll trigger this download now by running a short test script.
- Create a new file called verify.py in your project folder.
- Paste the following code into verify.py:
from cloakbrowser import launch
browser = launch(headless=False)
page = browser.new_page()
page.goto("https://example.com")
print(f"Title: {page.title()}")
browser.close()
print("CloakBrowser is working!")
What does this code do?
- from cloakbrowser import launch imports the CloakBrowser launcher. This is the only import you need to start a stealth browser session.
- launch(headless=False) opens a visible Chrome window so you can confirm it works. The stealth patches are active in both headed and headless modes.
- page.goto() navigates to a URL using the standard Playwright Page API. CloakBrowser passes all API calls through to its patched Chromium.
- browser.close() shuts down the browser cleanly and releases system resources.
- Save verify.py.
- Run the script by entering this command in your terminal:
python verify.py
- You should see a Chrome window open briefly, load example.com, then close. Your terminal prints:
Title: Example Domain
CloakBrowser is working!
What about the ~200MB download?
The first time you run the script, CloakBrowser downloads its patched Chromium binary. This takes 1-3 minutes depending on your internet speed. Subsequent launches skip this download entirely because the binary is cached in ~/.cloakbrowser/.
Chrome window didn't appear?
- If you see a download progress bar that hangs or times out, check your internet connection. The binary is approximately 200MB and needs a stable connection.
- If you see an import error mentioning cloakbrowser, make sure you ran pip install cloakbrowser==0.3.31 in the same Python environment your terminal is using.
- Help me debug why my verify.py script isn't working
✔️ Awesome, I've got everything!
Great. Double check you've saved verify.py and that your terminal printed CloakBrowser is working! with no errors.
ⓧ I'd like to double check the full code
Here's the complete verify.py file for comparison:
from cloakbrowser import launch
browser = launch(headless=False)
page = browser.new_page()
page.goto("https://example.com")
print(f"Title: {page.title()}")
browser.close()
print("CloakBrowser is working!")
Pre-download the binary explicitly
If the binary already downloaded during your verify.py run, these commands will confirm its status. If it didn't download for any reason, the first command forces the download.
- Run the install command to ensure the binary is present:
python -m cloakbrowser install
- Confirm the installation details by running:
python -m cloakbrowser info
- You should see output showing version 146.0.7680.177.5 and installed: True. This confirms the stealth Chromium binary is cached and ready.
Why check the version?
CloakBrowser's stealth patches are tied to a specific Chromium build. Version 146.0.7680.177.5 includes 58 C++ patches that disable automation signals at the source code level. Knowing your version helps you troubleshoot if a site's detection catches a vulnerability that was fixed in a later build.
Command not found or wrong version?
- If python -m cloakbrowser says the module is not found, make sure pip install cloakbrowser==0.3.31 completed successfully. Run pip show cloakbrowser to verify the package is installed.
- If the version number is different from 146.0.7680.177.5, you may have an older wrapper version. Run pip install -U cloakbrowser to upgrade.
- Help me fix my CloakBrowser binary installation
Your stealth browser is ready to go. Next up, you'll put it to the test against real bot detection sites and prove it passes where stock Playwright fails.
Prove CloakBrowser Beats Stock Playwright
In the previous step, you installed CloakBrowser and confirmed it launches a browser window. But how do you know it's actually stealthier than regular Playwright?
In this step, you'll build a test runner that visits real bot detection websites and captures their verdicts. You'll see concrete proof that CloakBrowser passes where stock Playwright fails.
In this step, get ready to:
- Build a detection test runner that visits multiple bot detection sites.
- Run the test and confirm CloakBrowser passes as a human browser.
- Understand what stock Playwright leaks that CloakBrowser patches at the source level.
Build a detection test runner
Bot detection sites analyze dozens of browser signals to decide if a visitor is human or automated. Your test runner will visit two of these sites and extract the key signals that separate real browsers from automation tools.
- Create a new file called stealth_test.py in your project folder inside Antigravity IDE.
- Add the imports and function setup by pasting this code:
import json
from cloakbrowser import launch
def run_detection_tests():
"""Run CloakBrowser against bot detection sites and report results."""
browser = launch(headless=False, humanize=True)
page = browser.new_page()
results = {}
What does this code do?
This sets up the test runner function. The launch(headless=False, humanize=True) call opens a visible browser window with human-like behavior enabled.
The results dictionary will store each detection test's verdict so you can compare them at the end.
You won't see any output yet. The next chunk adds the detection site visits.
- Add the bot detection site visits below the results = {} line:
# Test 1: bot.incolumitas.com
print("Testing bot.incolumitas.com...")
page.goto("https://bot.incolumitas.com/")
page.wait_for_load_state("networkidle")
import time
time.sleep(5)
webdriver_result = page.evaluate("() => navigator.webdriver")
results["navigator.webdriver"] = webdriver_result
print(f" navigator.webdriver: {webdriver_result}")
# Test 2: deviceandbrowserinfo.com
print("Testing deviceandbrowserinfo.com...")
page.goto("https://deviceandbrowserinfo.com/are_you_a_bot")
page.wait_for_load_state("networkidle")
time.sleep(3)
webdriver_check = page.evaluate("() => navigator.webdriver")
results["deviceandbrowserinfo_webdriver"] = webdriver_check
print(f" navigator.webdriver: {webdriver_check}")
What does this code do?
The script visits two public bot detection sites. At each site, it waits for the page to fully load, then extracts the navigator.webdriver property using JavaScript evaluation.
The time.sleep() calls give the detection sites time to run their analysis scripts. CloakBrowser's docs warn against using page.wait_for_timeout() because it sends CDP protocol commands that reCAPTCHA can detect.
You won't see output yet. The next chunk adds the stealth signal checks and the summary that ties everything together.
- Add the stealth signals check, summary, and main block below the Test 2 code:
# Test 3: Check core stealth signals
print("Checking core stealth signals...")
signals = page.evaluate("""() => {
return {
webdriver: navigator.webdriver,
plugins_count: navigator.plugins.length,
chrome_exists: typeof window.chrome !== 'undefined',
languages: navigator.languages,
platform: navigator.platform
}
}""")
results["stealth_signals"] = signals
print(f" Plugins: {signals['plugins_count']}")
print(f" window.chrome exists: {signals['chrome_exists']}")
print(f" Platform: {signals['platform']}")
browser.close()
# Summary
print("\n--- RESULTS SUMMARY ---")
print(f"navigator.webdriver = {results['navigator.webdriver']}")
print(f" (Stock Playwright would show: True)")
print(f"Plugins count = {signals['plugins_count']}")
print(f" (Stock Playwright would show: 0)")
print(f"window.chrome exists = {signals['chrome_exists']}")
print(f" (Stock Playwright would show: False)")
passed = (
results["navigator.webdriver"] is False
and signals["plugins_count"] > 0
and signals["chrome_exists"] is True
)
print(f"\nOverall: {'PASS - Looks human!' if passed else 'FAIL'}")
return results
if __name__ == "__main__":
run_detection_tests()
What does this code do?
Test 3 evaluates multiple browser signals at once: the webdriver flag, installed plugins count, and whether window.chrome exists. These are the signals that most anti-bot systems check first.
The summary section prints each result alongside what stock Playwright would show. This gives you a clear before/after comparison for explaining CloakBrowser's value.
The passed check requires all three signals to look human: webdriver must be False, plugins must be present, and window.chrome must exist.
- Save stealth_test.py.
Seeing a syntax error on save?
- Check that the indentation is consistent. Every line inside run_detection_tests() should be indented with 4 spaces.
- Make sure the triple-quoted string in Test 3 uses three double quotes """ on both sides, not single quotes.
Help me fix a syntax error in stealth_test.py.
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before running it.
ⓧ I'd like to double check the full code
import json
from cloakbrowser import launch
def run_detection_tests():
"""Run CloakBrowser against bot detection sites and report results."""
browser = launch(headless=False, humanize=True)
page = browser.new_page()
results = {}
# Test 1: bot.incolumitas.com
print("Testing bot.incolumitas.com...")
page.goto("https://bot.incolumitas.com/")
page.wait_for_load_state("networkidle")
import time
time.sleep(5)
webdriver_result = page.evaluate("() => navigator.webdriver")
results["navigator.webdriver"] = webdriver_result
print(f" navigator.webdriver: {webdriver_result}")
# Test 2: deviceandbrowserinfo.com
print("Testing deviceandbrowserinfo.com...")
page.goto("https://deviceandbrowserinfo.com/are_you_a_bot")
page.wait_for_load_state("networkidle")
time.sleep(3)
webdriver_check = page.evaluate("() => navigator.webdriver")
results["deviceandbrowserinfo_webdriver"] = webdriver_check
print(f" navigator.webdriver: {webdriver_check}")
# Test 3: Check core stealth signals
print("Checking core stealth signals...")
signals = page.evaluate("""() => {
return {
webdriver: navigator.webdriver,
plugins_count: navigator.plugins.length,
chrome_exists: typeof window.chrome !== 'undefined',
languages: navigator.languages,
platform: navigator.platform
}
}""")
results["stealth_signals"] = signals
print(f" Plugins: {signals['plugins_count']}")
print(f" window.chrome exists: {signals['chrome_exists']}")
print(f" Platform: {signals['platform']}")
browser.close()
# Summary
print("\n--- RESULTS SUMMARY ---")
print(f"navigator.webdriver = {results['navigator.webdriver']}")
print(f" (Stock Playwright would show: True)")
print(f"Plugins count = {signals['plugins_count']}")
print(f" (Stock Playwright would show: 0)")
print(f"window.chrome exists = {signals['chrome_exists']}")
print(f" (Stock Playwright would show: False)")
passed = (
results["navigator.webdriver"] is False
and signals["plugins_count"] > 0
and signals["chrome_exists"] is True
)
print(f"\nOverall: {'PASS - Looks human!' if passed else 'FAIL'}")
return results
if __name__ == "__main__":
run_detection_tests()
Run the test and capture results
Your detection test runner is ready. Time to see CloakBrowser in action against real bot detection systems.
- Run the detection tests by entering this command in your terminal:
python stealth_test.py
A Chrome window opens and visits each detection site. After about 10 seconds, the window closes and your terminal prints the results summary.
What should I see?
Your terminal output should show:
- navigator.webdriver = False (CloakBrowser patches this at the Chromium source level).
- Plugins count = 5 or higher (real browsers have plugins installed).
- window.chrome exists = True (confirms the browser exposes the Chrome API object).
- Overall: PASS - Looks human! at the bottom.
Seeing FAIL or a timeout error?
- If the browser window hangs on a site, the detection site might be temporarily down. The script still passes if the other signals check out.
- If you see a connection error, check your internet connection and try running the script again.
- If navigator.webdriver shows True, make sure you installed cloakbrowser (not plain playwright) and that your import says from cloakbrowser import launch.
Help me debug my detection test runner.
Compare with stock Playwright
Look at the summary output in your terminal. Each result line is paired with what stock Playwright would show. These differences are what anti-bot systems use to catch automated browsers.
Why does stock Playwright fail these tests?
Stock Playwright sets navigator.webdriver to true because the WebDriver specification requires it. It exposes zero plugins because headless Chromium strips them. It also lacks the window.chrome object that every real Chrome installation has.
CloakBrowser fixes these at the Chromium source level with 58 C++ patches. This is fundamentally different from JavaScript injection hacks that run after page load. Source-level patches cannot be detected by the page's own scripts.
Why does this matter for interviews?
You now have a concrete before/after comparison. In an interview, you can explain exactly which browser signals anti-bot systems check and how source-level patching differs from runtime JavaScript workarounds.
You've now proven that CloakBrowser passes as a human browser where stock Playwright gets caught. Next up, you'll put this stealth to work by extracting real data from a website using CSS selectors.
Extract Data with CSS Selectors
Your stealth browser proved it can slip past bot detection unnoticed. Now it is time to put that power to work on a real target.
In this step, you will build a scraper that navigates a website, identifies the data you want using CSS selectors, and extracts structured book data into a clean JSON file.
In this step, get ready to:
- Identify the CSS selectors for book titles, prices, and ratings on a scraping practice site.
- Write a scraper that extracts data across multiple pages with humanized stealth behavior.
- Export the results to a structured JSON file.
Identify CSS selectors on the target site
Your scraper needs to know exactly which HTML elements contain the data you want. On books.toscrape.com (a legal scraping practice site), every book listing follows a consistent structure.
- Each book is wrapped in an article.product_pod element.
- The title lives inside h3 a as a title attribute.
- The price is in a .price_color paragraph element.
- The star rating is encoded in the class name of a p.star-rating element (for example, star-rating Three).
What are CSS selectors?
CSS selectors are patterns that identify specific HTML elements on a page. They are the same selectors you would use in a stylesheet to apply colors or fonts.
In scraping, you use them to pinpoint exactly which elements contain the data you want to extract. A selector like article.product_pod means "find every <article> element with the class product_pod."
Build the extraction scraper
You will create a single file that launches CloakBrowser with full stealth settings, loops through multiple pages, and pulls book data using those selectors.
- Create a new file called scraper.py in your project folder and add the imports and launch configuration by pasting this code:
import json
import time
import random
from cloakbrowser import launch
def scrape_books():
"""Scrape books.toscrape.com with CloakBrowser stealth and humanized behavior."""
browser = launch(
headless=False,
humanize=True,
human_preset="careful",
args=["--fingerprint=42069"],
)
page = browser.new_page()
all_books = []
base_url = "https://books.toscrape.com/catalogue/page-{}.html"
What does this code do?
- humanize=True replaces all mouse and keyboard actions with human-like equivalents using Bezier curves and per-character typing delays.
- human_preset="careful" uses slower, more deliberate movements with idle micro-movements between actions.
- args=["--fingerprint=42069"] pins the browser's device fingerprint to a consistent identity. The same seed always produces the same canvas, WebGL, and audio fingerprint.
- base_url uses a format placeholder so you can loop through pages 1, 2, and 3 by inserting the page number.
- Directly below the base_url line, add the page loop and CSS selector extraction logic:
for page_num in range(1, 4):
url = base_url.format(page_num)
print(f"Scraping page {page_num}: {url}")
page.goto(url)
page.wait_for_load_state("networkidle")
# Extract book data using CSS selectors
books = page.query_selector_all("article.product_pod")
for book in books:
title_el = book.query_selector("h3 a")
price_el = book.query_selector(".price_color")
rating_el = book.query_selector("p.star-rating")
title = title_el.get_attribute("title") if title_el else "Unknown"
price = price_el.inner_text() if price_el else "N/A"
# Extract rating from class name (e.g., "star-rating Three")
rating_class = rating_el.get_attribute("class") if rating_el else ""
rating_map = {
"One": 1,
"Two": 2,
"Three": 3,
"Four": 4,
"Five": 5,
}
rating = 0
for word, value in rating_map.items():
if word in rating_class:
rating = value
break
all_books.append({
"title": title,
"price": price,
"rating": rating,
})
print(f" Found {len(books)} books on page {page_num}")
# Human-like delay between pages (not page.wait_for_timeout!)
if page_num < 3:
delay = random.uniform(2.0, 4.0)
print(f" Waiting {delay:.1f}s before next page...")
time.sleep(delay)
What does this extraction code do?
- page.query_selector_all("article.product_pod") grabs every book card on the page. Each page has 20 books.
- For each book, three sub-selectors pull the title (from the title attribute of the link), the price text, and the rating class name.
- The rating_map dictionary converts the word in the class name (like "Three") to a numeric value (3).
- time.sleep() with a random delay between 2 and 4 seconds simulates a human pausing between page clicks.
Why time.sleep() instead of page.wait_for_timeout()?
CloakBrowser's documentation explicitly warns against using page.wait_for_timeout() because it sends CDP (Chrome DevTools Protocol) commands that reCAPTCHA and other systems can detect.
Native time.sleep() pauses your Python process without touching the browser. The browser sees nothing happening, which is exactly what a real human looks like when they pause to read a page.
You won't see a change yet because the script still needs its closing logic to run and save results.
Export results to JSON and run the scraper
- After the for page_num loop (back at the function's top-level indentation), add the browser close, JSON export, and entry point:
browser.close()
# Save to JSON
with open("output.json", "w", encoding="utf-8") as f:
json.dump(all_books, f, indent=2, ensure_ascii=False)
print(f"\nDone! Scraped {len(all_books)} books total.")
print("Results saved to output.json")
return all_books
if __name__ == "__main__":
scrape_books()
What does this code do?
- browser.close() shuts down the stealth Chromium instance after all pages are scraped.
- json.dump() writes the list of book dictionaries to output.json with readable indentation.
- ensure_ascii=False preserves special characters in book titles (like accented letters).
- The if __name__ guard makes the script runnable from the terminal.
- Save scraper.py.
- Run the scraper by executing this command in your terminal:
python scraper.py
A Chrome window opens and you will see it navigate through three pages of books.toscrape.com with visible human-like scrolling and clicking pauses between pages.
- When the script finishes, confirm you see this output in your terminal:
Done! Scraped 60 books total.
Results saved to output.json
- Verify the output file exists by running:
ls output.json
You should see output.json listed. Open it to confirm it contains 60 book entries, each with title, price, and rating fields.
Scraper timing out or freezing?
- If the browser window opens but pages load slowly, your network may be throttling requests. Wait a bit longer. The wait_for_load_state("networkidle") call ensures the page is fully loaded before extraction begins.
- If you see a TimeoutError, the site may be temporarily unavailable. Try running the script again after a minute.
- If output.json is empty or has fewer than 60 entries, check that the base_url uses page-{}.html with curly braces for the format placeholder.
Help me debug my CloakBrowser scraper
✔️ Awesome, I've got everything!
Great. Double check that you have saved scraper.py and that output.json contains 60 book entries.
ⓧ I'd like to double check the full code
import json
import time
import random
from cloakbrowser import launch
def scrape_books():
"""Scrape books.toscrape.com with CloakBrowser stealth and humanized behavior."""
browser = launch(
headless=False,
humanize=True,
human_preset="careful",
args=["--fingerprint=42069"],
)
page = browser.new_page()
all_books = []
base_url = "https://books.toscrape.com/catalogue/page-{}.html"
for page_num in range(1, 4):
url = base_url.format(page_num)
print(f"Scraping page {page_num}: {url}")
page.goto(url)
page.wait_for_load_state("networkidle")
# Extract book data using CSS selectors
books = page.query_selector_all("article.product_pod")
for book in books:
title_el = book.query_selector("h3 a")
price_el = book.query_selector(".price_color")
rating_el = book.query_selector("p.star-rating")
title = title_el.get_attribute("title") if title_el else "Unknown"
price = price_el.inner_text() if price_el else "N/A"
# Extract rating from class name (e.g., "star-rating Three")
rating_class = rating_el.get_attribute("class") if rating_el else ""
rating_map = {
"One": 1,
"Two": 2,
"Three": 3,
"Four": 4,
"Five": 5,
}
rating = 0
for word, value in rating_map.items():
if word in rating_class:
rating = value
break
all_books.append({
"title": title,
"price": price,
"rating": rating,
})
print(f" Found {len(books)} books on page {page_num}")
# Human-like delay between pages (not page.wait_for_timeout!)
if page_num < 3:
delay = random.uniform(2.0, 4.0)
print(f" Waiting {delay:.1f}s before next page...")
time.sleep(delay)
browser.close()
# Save to JSON
with open("output.json", "w", encoding="utf-8") as f:
json.dump(all_books, f, indent=2, ensure_ascii=False)
print(f"\nDone! Scraped {len(all_books)} books total.")
print("Results saved to output.json")
return all_books
if __name__ == "__main__":
scrape_books()
Your scraper now extracts real data from a live website while flying under the radar of bot detection systems. Next up, you will take on a secret mission to make your scraper even more persistent across sessions.
Secret mission
Add Persistent Browser Profiles
Production scrapers don't start fresh every time. They maintain cookies, localStorage, and browsing history across sessions to look like returning visitors. Can you upgrade your scraper to persist its browser identity between runs?
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally using open-source tools. There are no ongoing costs or cloud resources to worry about.
Decide whether to keep your resources for future scraping projects, or delete them to free up disk space.
Resources you used:
- ~/.cloakbrowser/ directory containing the stealth Chromium binary (~200MB).
- cloakbrowser Python package.
- Project files: verify.py, stealth_test.py, scraper.py, scraper_persistent.py, output.json, state.json.
- ./scraper-profile/ directory containing the persistent browser profile (Secret Mission).
Keep everything running
No action needed. Choose this if you plan to continue experimenting with CloakBrowser or reuse the stealth binary for future scraping projects.
- The cached Chromium binary in ~/.cloakbrowser/ takes ~200MB of disk space but costs nothing to keep.
- Your persistent browser profile in ./scraper-profile/ retains cookies and session state for future runs.
- The cloakbrowser pip package stays installed and ready to use in new scripts.
Pause - I'll come back to this later
There are no running processes or services to pause. Everything in this project is on-demand.
- Your files and the cached binary remain on disk until you delete them manually.
- No background processes or servers are running after your scripts finish.
Delete - I don't want to use this again
Remove all project resources and free up disk space. This deletes the cached binary, project files, and persistent profile.
- Remove the cached CloakBrowser binary by running:
python -m cloakbrowser clear-cache
- Uninstall the cloakbrowser pip package by running:
pip uninstall cloakbrowser
- Delete the persistent browser profile and session state.
On macOS/Linux:
rm -rf ./scraper-profile/
rm state.json
On Windows (PowerShell):
Remove-Item -Recurse -Force .\scraper-profile\
Remove-Item state.json
- Delete your project files and output.
On macOS/Linux:
rm verify.py stealth_test.py scraper.py scraper_persistent.py output.json
On Windows (PowerShell):
Remove-Item verify.py, stealth_test.py, scraper.py, scraper_persistent.py, output.json
Nice Work!
Nice Work!
You just built a stealth web scraper that passes bot detection tests where stock Playwright fails. You now have a concrete, working example of anti-bot bypass using source-level browser patches.
Here's what you accomplished:
- Proved CloakBrowser passes bot detection tests that stock Playwright fails, with navigator.webdriver reporting false and real browser plugins present.
- Built a working scraper that extracts structured data from a live website using CSS selectors with humanized behavior including Bezier-curve mouse movements and per-character keyboard timing.
- Configured fingerprint pinning for consistent device identity and implemented pagination with randomized time.sleep() delays to avoid rate-limiting detection.
- Secret Mission: Created a persistent browser profile that maintains cookies and session state across multiple scraping runs, simulating a returning visitor.
Ready to quiz yourself?