Your code did not change, but the request the site sees did. Anti-bot systems score three things together: the IP the request comes from, the network fingerprint of the client (TLS and HTTP/2), and, for browsers, the environment the page runs in. In a container on a cloud server or on AWS Lambda, the IP belongs to a datacenter, the TLS stack comes from a different build, and the browser is headless with no GPU, few fonts and a UTC clock. Any one of those can trigger a block. The IP is the most common cause, but it is not always the cause, and testing is the only way to know which one you have.
This is the most common blocking complaint we see. In String's weekly scrape of Reddit, Stack Overflow and GitHub issues for the week ending August 31, 2026, blocking and anti-bot threads were 84 of 184 scraping threads (45.7%), up from 31.6% in the run ending August 20. The scoring method also changed between those two runs, so read the rise as a direction rather than a precise change. The repeated pattern was an identical script that passes on a desktop and fails from a container or a serverless function.
A Stack Overflow question from August 2026 describes the Lambda case exactly:
"The same Playwright code works correctly on my local machine, but when I run it on AWS Lambda, Avito returns a Cloudflare Turnstile challenge with HTTP 403." Stack Overflow, question 79997812
The asker had already set a Chrome user agent, a French locale and a Moroccan timezone, and hidden navigator.webdriver. None of it helped, which points toward the network.
A Camoufox bug report shows the opposite case. The reporter ran the same script in Docker and locally, with no proxy, and Cloudflare blocked only the container:
"from within a container some leak/fingerprint is detected and no content is rendered. Doing it from local environment with same script works just fine." daijro/camoufox issue 311
Asked whether the site loaded in a normal browser on the same IP, the reporter answered yes, and the detection happened every time. Here the IP was not the problem. The container environment was.
Egress IP reputation. Cloud providers publish their address ranges (AWS lists them in ip-ranges.json), and bot vendors score datacenter ranges as automated by default. Lambda functions outside a VPC share AWS-owned addresses with other tenants, so the reputation you inherit is not only yours. A container on your laptop still uses your home IP. A container on EC2, ECS, Cloud Run or Kubernetes does not.
TLS and HTTP/2 fingerprint. The server sees your client's TLS handshake (cipher order, extensions) and HTTP/2 settings before it sees a header. A Python client on a slim Debian image links a different OpenSSL than the one on your Mac, and the Chromium builds packaged for Lambda are not the Chrome on your desktop. A browser user-agent string on a non-browser handshake is a mismatch the site can see.
Headless and container browser signals. Containers ship headless Chromium with no display, software rendering in place of a GPU (WebGL reports SwiftShader or llvmpipe), and often the headless-shell build. Docker's default /dev/shm is 64 MB, which crashes Chrome tabs on heavy pages. A crash mid-challenge looks like a block.
Missing fonts and locale. Slim base images carry few fonts, and font enumeration is a standard fingerprint check. The container clock is UTC and the locale is often C or POSIX, which rarely matches the IP's geography or the user agent you claim.
Runtime lifecycle. Lambda freezes and reuses execution environments, limits /tmp, and caps run time. A browser context that dies during a challenge, or cookies that vanish between cold starts, produce failures that look like detection.
Run the same image in three places and compare:
/tmp, timeouts, and whether the browser context survives the challenge.Log what came back, not only the status code: the HTML, the title and the response headers. A Cloudflare challenge carries a cf-ray header and a __cf_chl_ token in the URL, and a 200 status can still be a challenge page. Hit a TLS echo service such as tls.peet.ws from both environments and compare the JA3/JA4 hashes. Open a fingerprint test page from both browsers and compare timezone, fonts, WebGL renderer and navigator values.
curl_cffi in Python, or drive full Chrome in place of the headless shell.TZ and the locale to match the proxy's country, raise --shm-size or pass --disable-dev-shm-usage, and prefer headed Chrome under Xvfb over headless-shell for hard targets./tmp between runs, and treat a killed context as a retry, not a block.These fixes interact. Matching the fingerprint does little from a flagged IP, and a clean residential IP does little from a browser that fails every fingerprint check.
You can also take the network and the browser out of your container. String's Web Access API takes a URL from wherever your code runs, Lambda included, and returns the page as Markdown by default. Each request starts as a plain fetch and escalates to a browser, residential routing or CAPTCHA solving only when the target needs it, so egress IP and fingerprint are String's problem, not your function's.
In our September 16, 2026 benchmark of 16 providers on 100 protected sites, String passed 97% of 500 requests, and 100% on the 15 sites behind Cloudflare. Pricing is per 1,000 successful requests: $0.20 for a plain fetch on the Growth plan, up to $4.00 for a browser on a premium proxy, with 5,000 standard requests free. For how String compares with raw proxies and unblockers, see web scraping API vs web unblocker vs proxy, and for the full field, the best web scraping APIs.
The site sees a different request. In the cloud, your IP belongs to a datacenter range, your TLS and HTTP/2 fingerprint comes from a different client build, and your browser runs headless with no GPU, few fonts and a UTC clock. Anti-bot systems score these together, so any one can trigger a block even when the code is identical.
No. The IP is the most common cause, but a container can be blocked from the same IP your laptop uses. In Camoufox issue 311, the site loaded in a normal browser on the same IP while the Dockerized browser was detected every time. Run the container on your laptop first: if it fails there, the cause is the environment.
Run the same image in three places: Docker on your laptop, a cloud VM with a fixed IP, and Lambda. If only the cloud runs fail, the egress IP is the cause. If only Lambda fails, check memory, /tmp and timeouts. Save the returned HTML and headers, since a Cloudflare challenge page can come back with a 200 status.
They fix the IP cause only. A mismatched TLS fingerprint or a headless browser that fails fingerprint checks still gets blocked, so match the client and the browser environment too.
Yes. Lambda sends a URL to the Web Access API and gets the page back, so the site never sees Lambda's IP or runtime. In the September 16, 2026 benchmark, String passed 97% of 500 requests across 100 protected sites.