Introduction
Running Puppeteer against Cloudflare, you’ve probably noticed more Turnstile prompts and challenge loops showing up without any apparent changes to your code. Cloudflare in 2026 pays close attention to how a session behaves, from JA4 and HTTP/2 patterns to browser APIs, rendering signals, and input timing. Puppeteer still drives Chromium reliably, but the default local environment often produces signals that don’t line up with real user sessions anymore. In this article, we’ll break down what Cloudflare is actually evaluating and show how Puppeteer can be run in an environment that matches those expectations instead of fighting them.
Why Cloudflare Challenges Puppeteer in 2026

Puppeteer scripts have been running into Cloudflare challenges more often lately. You probably didn’t break anything. The code still does what it always did, but Cloudflare has changed how it judges browser sessions.
In 2026, it looks at the whole picture network behavior, browser internals, and how the page is used, and compares that to real traffic. When those signals feel off, challenges show up. That’s why runs that used to pass quietly now hit Turnstile or verification loops: not because Puppeteer is caught, but because the session no longer looks like a normal browser.
What Cloudflare Likely Evaluates Before Your Code Runs (TLS / JA3 / JA4)
According to Cloudflare’s documentation, TLS fingerprints, such as JA3 and JA4, are exposed through Bot Management and used as inputs to bot scoring. These fingerprints describe how a client negotiates TLS, including protocol versions and extension ordering.
While Cloudflare doesn’t document exact thresholds, it’s reasonable to assume that TLS profiles that don’t align with common browser and IP combinations can reduce trust early in the request lifecycle and influence whether challenges appear later.
How Network Traffic Patterns Factor Into Scoring (HTTP/2)
Cloudflare doesn’t publicly describe HTTP/2 priority trees or request graphs as explicit fingerprints. What it does document is an analysis of traffic characteristics as part of its detection engines.
Differences in how connections are opened, how requests are sequenced, and how predictable traffic patterns appear can contribute to heuristic or machine-learning scores.
Automated sessions often produce more uniform network behavior than real browsing, which likely becomes more relevant when combined with other low-confidence signals.
Browser Environment Signals Collected via JavaScript
On some pages, Cloudflare runs JavaScript-based detections to gather client-side signals. The exact properties collected aren’t listed publicly, but the intent is to evaluate the browser environment after load.
Rather than relying on a single flag, Cloudflare assesses whether the overall environment matches profiles it commonly sees in real browsers. Unusual or internally inconsistent combinations can increase the likelihood of a higher bot score.
Runtime Variability and Entropy Signals
Cloudflare doesn’t explicitly document fingerprinting via WebGL, canvas, or audio APIs. That said, JavaScript detections can collect a range of runtime signals, and low variability across sessions tends to make automated traffic easier to classify in general.
When runtime behavior appears overly uniform, especially across different sessions or IPs, it can reinforce other signals suggesting automation. These inputs are best understood as contributors to scoring, not direct block triggers.
Session Behavior Over Time (Machine Learning)
Cloudflare’s bot detection relies heavily on machine learning models that evaluate traffic patterns over time. While the specific features aren’t public, Cloudflare does state that behavior and request patterns factor into classification.
Session flow, timing between actions, and how interactions progress compared to known traffic profiles can all influence whether a session is treated as automated and whether challenges appear earlier.
How Turnstile Fits Into the Flow
Turnstile acts as a verification step when Cloudflare’s confidence in a session is low. It’s typically triggered by bot management or WAF decisions rather than by random events.
When a session repeatedly encounters challenges after a successful solve, it usually suggests that earlier signals haven’t raised the overall confidence score enough for Cloudflare to allow the session to continue without further verification.

Puppeteer Script in Action
A default Puppeteer session often starts quietly when a browser first connects to a Cloudflare-protected site. Cloudflare typically allows the request and begins observing. At this stage, the session hasn’t produced enough data to justify a challenge, especially if the IP reputation is clean and the page is a public entry point.
This launch uses Puppeteer exactly as most developers start: no stealth plugins, no flags, no user-agent overrides. From Cloudflare’s perspective, this establishes the baseline environment, TLS behavior, browser characteristics, and the initial request pattern.
The first navigation usually succeeds. Cloudflare sees a single page load, standard resource fetching, and no interaction yet. That alone rarely triggers a challenge.
Where things start to change is after additional activity within the same session. Cloudflare evaluates behavior over time, not just a single request. Reloads and secondary navigations provide more signal about how the session behaves and how predictable that behavior is.
At this point, Cloudflare has seen multiple navigations from the same browser instance, happening quickly and without the natural delays typical of real users.
In some environments, that’s enough to lower confidence and introduce a managed challenge. In others, Cloudflare may continue to allow the session and keep observing.
To make the outcome visible, the script checks for one of the most common indicators of a Cloudflare challenge: a Turnstile iframe injected into the page.
Whether this check returns true or false depends on factors outside the script itself IP reputation, ASN, prior traffic patterns, and how often similar sessions have appeared. The same code can pass one day and be challenged the next, which is exactly how Cloudflare’s adaptive model is designed to work.
Finally, capturing a screenshot provides concrete evidence of what the browser actually rendered, whether that’s the intended page or a verification flow.
The important takeaway isn’t that this script always triggers a challenge, it doesn’t. The takeaway is that Cloudflare’s decision isn’t tied to Puppeteer itself. As Cloudflare has expanded its detection methods, even Puppeteer setups that appear “stealthy” can be challenged once enough contextual signals accumulate, especially at scale. This makes reliability a matter of environment and behavior, not just code.
Strengthening Puppeteer With Browserless
At this point, the limitation isn’t Puppeteer’s API or control model, it’s the environment in which the browser runs. Cloudflare evaluates browser sessions holistically: network characteristics, browser fingerprints, runtime behavior, and how a session unfolds over time.

Browserless helps by improving those layers without changing how you write Puppeteer code. The aim isn’t to “hide” Puppeteer, but to run it in a browser environment that produces realistic, internally consistent signals and can handle Cloudflare challenges as they arise.
Connecting Puppeteer to Browserless Stealth Browsers
Browserless exposes Chromium instances designed for automation under modern detection systems. When using Browserless launch parameters, setting stealth: true enables built-in stealth mitigations. When connecting through a dedicated stealth endpoint such as /chromium/stealth, advanced stealth behavior is already enabled by default.
Optional humanlike modes introduce timing jitter, cursor movement, and interaction randomness to avoid perfectly deterministic input patterns. Browserless can also perform Cloudflare-aware pre-navigation checks and supports residential proxies when network reputation is a concern.
From a Puppeteer perspective, nothing about your workflow changes. You still connect to a browser and control pages the same way; the only difference is that Chromium is running remotely with the right defaults already in place.
Puppeteer connecting to Browserless with stealth and proxy settings:
This keeps your Puppeteer code intact while moving execution into a browser environment that aligns more closely with what Cloudflare expects to see from real users.
Using BrowserQL to Handle Cloudflare Before Puppeteer Attaches
One common failure mode with Cloudflare is that challenges appear before Puppeteer fully attaches or before your script has a chance to react. BrowserQL allows you to run browser actions ahead of time, including navigating to a page and completing Cloudflare verification flows, then hand off a ready browser session to Puppeteer.
With BrowserQL, you can explicitly navigate and verify Cloudflare challenges before your automation logic starts.
Snippet A BrowserQL handling Cloudflare verification:
Once this completes successfully, the browser session is already past Cloudflare’s initial gate. This verification applies only to the current browser session. If later behavior or network conditions reduce Cloudflare’s confidence again, additional challenges may still appear.
Snippet B Hybrid workflow with Puppeteer:
- Run the BrowserQL mutation to navigate and verify Cloudflare.
- Retrieve the browserWSEndpoint from the BrowserQL response.
- Attach Puppeteer to that session.
This split keeps responsibilities clear: Puppeteer handles your workflow logic, while Browserless prepares a browser session that’s already cleared initial Cloudflare checks.
When to Use /unblock for Cloudflare’s Hardest Cases
Some Cloudflare configurations rely heavily on passive fingerprinting and don’t require full browser interaction. For these cases, Browserless provides the /unblock endpoint, a minimal-surface environment designed to reduce the amount of exposed entropy while still returning practical artifacts.
/unblock is useful when you need:
- Raw HTML
- Session cookies
- A screenshot
- Or a prepared session you can later attach Puppeteer to
This can include HTML content and cookies that represent a Cloudflare-approved session. In some workflows, those cookies can then be injected into Puppeteer to continue automation without re-triggering the initial challenge. These artifacts are environment-dependent and may become invalid if the IP address, proxy type, or TLS configuration changes.
Recommended 2026 Cloudflare Workflow

Cloudflare challenges don’t appear at a single, predictable point in a session. Sometimes the first request passes. Sometimes, a secondary navigation can trigger a challenge.
Sometimes the block happens before Puppeteer even attaches. Because of that, the most reliable approach in 2026 is an escalation-based workflow where Puppeteer stays in charge, and the browser environment adapts only when Cloudflare signals low confidence.
Browserless is designed to support this pattern, you start with the least invasive setup and move to more targeted tools only when needed. Each step addresses a different class of Cloudflare detection signals.
Step 1: Start With Stealth Browserless via Puppeteer
The first step is to run Puppeteer against a Browserless stealth browser. This improves baseline browser consistency, protocol behavior, and fingerprint alignment without changing your automation code. At this stage, you’re not trying to “solve” Cloudflare just to avoid unnecessary friction on the initial request.
For many sites, this is enough. If Cloudflare is satisfied with the session’s network and browser signals, Puppeteer can continue normally, and no escalation is required.
Step 2: Detect Whether a Cloudflare Challenge Appeared
Rather than assuming a challenge will always happen, the workflow explicitly checks for one. This keeps your automation fast when no challenge is present and avoids unnecessary work.
This step reflects how Cloudflare actually behaves: challenges are conditional. Many sessions never reach this point.
Step 3: Escalate to BrowserQL When a Challenge Is Detected
If a challenge does appear, the workflow escalates. Instead of trying to handle Turnstile inside Puppeteer, BrowserQL is used to navigate and explicitly verify the Cloudflare challenge before automation resumes. This is especially useful when challenges appear early or block navigation entirely.
At this point, Cloudflare’s verification flow has completed, and the browser session is in a clean, post-challenge state.
Step 4: Reattach Puppeteer to the Verified Session
Once BrowserQL completes verification, Puppeteer reconnects to the same browser instance using the returned WebSocket endpoint. Automation resumes without re-triggering the challenge.
This handoff keeps responsibilities clean: BrowserQL handles challenge resolution, and Puppeteer handles the rest of the workflow.
Step 5: Use /unblock only as a Final Fallback
In cases where Cloudflare relies heavily on passive fingerprinting or where full browser interaction isn’t necessary, /unblock provides a lower-entropy alternative. This step isn’t part of the main flow; it’s a fallback for the hardest cases.
The response can include HTML, cookies, or other artifacts that represent a Cloudflare-approved session. Depending on the use case, those cookies can be reused later in Puppeteer or used without a browser.
Conclusion
Cloudflare’s challenge systems aren’t something to “beat” so much as something to understand. Puppeteer is still a powerful and reliable automation tool, but modern detection goes beyond scripts to the full browser environment and session behavior. As Cloudflare’s methods have expanded, reliability has become less about clever tricks and more about how closely automation matches real user signals over time. Approaching this problem with a focus on maintainability, ethical use, and realistic behavior leads to better long-term results. If you want to experiment with these ideas in practice, you can start a free Browserless trial and see how your existing Puppeteer workflows behave in a more production-like browser environment.
FAQs
Can Cloudflare block Puppeteer?
Cloudflare doesn’t block Puppeteer by default, but it can challenge or restrict Puppeteer-driven sessions depending on the environment. Cloudflare evaluates signals like network behavior, browser characteristics, and session patterns over time. When those signals don’t match typical user traffic, challenges such as Turnstile may appear.
Why does Puppeteer sometimes work on Cloudflare sites and sometimes get blocked?
Cloudflare’s detection is adaptive, not deterministic. The same Puppeteer script may work in one environment but be challenged in another based on factors such as IP reputation, ASN, region, request frequency, and prior session history. This variability is expected and intentional.
Do Puppeteer stealth plugins bypass Cloudflare?
Stealth plugins can reduce some obvious automation signals, but they don’t guarantee reliable access to Cloudflare-protected sites. As Cloudflare correlates behavior across sessions and traffic patterns, stealth techniques alone often break down at scale, especially when automation becomes repetitive.
How does Cloudflare detect automated browsers?
Cloudflare uses a combination of network-level signals, JavaScript-based detections, and machine learning models to score sessions. Rather than relying on a single fingerprint or flag, it evaluates how closely a session resembles real user traffic over time and escalates challenges when confidence is low.
What’s the best way to run Puppeteer reliably on Cloudflare-protected sites?
The most reliable approach is to run Puppeteer in a browser environment that closely matches real users, rather than relying on evasion tricks. This includes realistic network behavior, consistent browser signals, and controlled session patterns. Infrastructure-level solutions can align these signals and improve long-term stability.