The browser tool that KISS agents use to read web pages was being turned away by a growing number of sites. This report explains which sites did it and why, what was changed so the browser is treated like a person's Chrome, the measured effect, and what is deliberately not done.
Every result the browser tools (go_to_url, click, get_page_content) returned was scanned for the signatures of bot-protection pages. 95 distinct hosts served one. Grouped by the vendor behind the page:
| Vendor and page | Hosts (blocked page loads) |
|---|---|
Google /sorry/ "unusual traffic from your computer network" | google.com (68) |
| Cloudflare managed challenge "Just a moment… Performing security verification" | stackoverflow.com (35), dl.acm.org (14), npmjs.com (5), docs.vllm.ai (4), superuser, math.stackexchange, askubuntu, readthedocs sites, congress.gov, science.org, sloan.org, biorxiv, sagepub, aps.org, anthropic.com, cppreference, cryptography.io, and more |
| Cloudflare hard block "Sorry, you have been blocked" | medium.com (4), acm.org, oddschecker, usfunds, coursehero, physicsforums, obd-codes, modelcontextprotocol.io |
| Cloudflare Turnstile (OpenAI family) | openai.com (6), platform/help.openai.com, chatgpt.com, bbb.org |
| Akamai "Access Denied … errors.edgesuite.net" | carmax.com (4), costco.com |
| Anubis proof-of-work "Making sure you're not a bot" | dblp.org (5), wiki.archlinux.org, gitlab.kitware.com, safereddit |
| Imperva Incapsula "Request unsuccessful" | cato.org, bizfileonline.sos.ca.gov |
| PerimeterX "Robot or human? Press and hold" | walmart.com |
| Search-engine CAPTCHAs | search.brave.com, startpage.com, ecosia.org, mojeek.com |
| Others | sciencedirect "Are you a robot?", researchgate "Security check required", pmc.ncbi reCAPTCHA, scribd, arxiv HTML 403 |
Two things stand out. First, Cloudflare accounts for most of the hosts, and most of those are the silent managed challenge: a page that checks the browser with JavaScript and reloads the real content on its own when the browser looks like a person's. Second, Google is different in kind: its page says so itself, "if a network you use … seems to be sending automated traffic", and Google Cloud address space is such a network.
The old configuration launched the open-source Chromium build through Playwright in headless mode, with a hard-coded Los Angeles timezone, a Retina scale factor of 2 on a Linux server, a JavaScript override of navigator.userAgent, and clicks that teleported the pointer onto the target. Each of these is visible to a page, and detection vendors score them in layers:
The single most important finding came late. On an X server without a GPU, Chromium puts its graphics stack on a blocklist and ships no WebGL at all. Practically every human browser has WebGL, and challenge scripts test for it first. With the browser otherwise fixed, six publisher sites (ACM, Science, ScienceDirect, Sage, cppreference, ResearchGate) still showed Cloudflare's "Verify you are human" checkbox, and pressing it was accepted by the widget but rejected by the verdict every time. One flag, --ignore-gpu-blocklist, lets Chromium render WebGL through Mesa's software renderer, which reports itself as ANGLE (Mesa, llvmpipe …), exactly what a Linux desktop without a GPU reports. After that, all six cleared.
Fourteen URLs from the blocked list were used as a development set during the work. A second set of fourteen hosts from the same list, never probed during development, served as a held-out check. All runs used fresh browser profiles from the same GCP machine.
tmp/probe_blocks.py and tmp/probe_tool.py. The one remaining development-set miss is Google's /sorry/ page; the tool now answers that query on Bing. On the held-out set every host loads; ResearchGate clears Cloudflare and then serves its own HTTP 403 to datacenter addresses.The intermediate row "10 / 14 (Turnstile rejected)" is worth a sentence: it was lower than the row above only because the six publisher sites were now reached far enough to show the checkbox, and the checkbox verdict failed on the missing WebGL. That is what pointed to the graphics blocklist.
src/kiss/agents/sorcar/web_stealth.pyplaywright_api(), playwright_package(): use Patchright's sync API when installed, stock Playwright otherwise. Patchright 1.63.0 was added to pyproject.toml.chrome_channel(): launch Google Chrome when it is installed, the bundled Chromium otherwise.virtual_display(), stop_virtual_display(): one Xvfb per process, started with -displayfd so it picks a free display number, wrapped in a tiny shell loop that kills Xvfb within two seconds if the Python process dies without running atexit. Falls back to real headless mode on macOS, Windows, or Linux without Xvfb.mouse_path(): cubic Bezier pointer path with ease-out and sub-pixel jitter. typing_chunks(): per-word typing speed with a longer pause at each space.challenge_vendor(): recognises an interstitial by its exact title ("Just a moment…", "Access Denied", "Robot or human?") or by two co-occurring body phrases ("Sorry, you have been blocked" plus "Ray ID"), so an article that merely mentions CAPTCHAs is not mistaken for a block.search_fallback_url(): turns a Google search or /sorry/index?continue=… URL into the same query on Bing, which served 72 of 73 searches in the task history (DuckDuckGo was flagged on 37 of 63).src/kiss/agents/sorcar/web_use_tool.pyheadless=True, still the default) now means a headed Chromium on the virtual display when one is available. Callers, show_browser(), screenshots and the persistent profile behave as before.--disable-features=IsolateOrigins,site-per-process; added --window-size and --ignore-gpu-blocklist. Context options: no more locale, timezone_id, device_scale_factor=2; no_viewport when headed.go_to_url reads the cf-mitigated: challenge response header and the page, waits up to 12 s for a challenge to clear while the pointer drifts, ticks Cloudflare's single "Verify you are human" box if it appears, and otherwise prefixes the result with a one-line Note: naming the vendor and suggesting show_browser() or another source.Note: www.science.org answered with a bot-protection page (Cloudflare challenge) that did not
clear within 12s. Call show_browser() so the user can complete the check, or use another source
for the same information.
Note: Google answered with its 'unusual traffic' page. It rates this network's IP address as
automated traffic, which no browser setting changes, so the same query was opened on Bing instead.
src/kiss/tests/agents/sorcar/test_web_stealth.py holds 24 end-to-end tests that drive a real Chromium against a local HTTP server: engine and display selection (including reading DISPLAY from the browser's /proc/<pid>/environ), fingerprint properties, the curved click path and held button, typing cadence, wheel notches, all fallback paths, Cloudflare-style challenges that clear and that do not, a routed Turnstile widget, vendor recognition with benign-text negatives, the Google-to-Bing mapping, Xvfb restart hygiene (descriptor count and atexit callbacks constant; descriptor exhaustion handled), and a live load of journals.sagepub.com. web_stealth.py has 100 % branch coverage; the 254 existing tests that touch the browser tool still pass.
The tool presses exactly one thing on the user's behalf: Cloudflare's "Verify you are human" checkbox, which is a single affirmation, not a puzzle. It does not solve reCAPTCHA or hCaptcha images, does not perform PerimeterX press-and-hold, does not use third-party solving services, and does not try to get past Akamai, Imperva or Cloudflare hard blocks. Those pages are reported with a Note: so the agent can hand the browser to the user through show_browser(). Google's /sorry/ page is an address-reputation decision about the Google Cloud network this machine sits on; the only honest fix is a different network, so the tool re-runs the query on Bing.
Xvfb binary (Debian package xvfb) and Mesa (libgl1-mesa-dri) for the headed mode with WebGL; both are present on this host. Without Xvfb the tool logs a warning and runs headless as before.~/.cache/ms-playwright; the tool does this automatically, as it did for Playwright.isolated_context=False. Console events do not fire under Patchright; the tool never relied on them.