iTranslated by AI
How to Use Cloudflare Bot JavaScript Detections
What are Bot JavaScript detections?
JavaScript detections are another method that help Cloudflare identify bot requests.
Each of Cloudflare's bot products passively calculates a bot-likelihood score (Bot Score) based on features of incoming HTTP requests to protect against bots. In contrast, JavaScript detections enhance detection by adding an active approach: Cloudflare delivers a detection script to the client and utilizes the results.
These detections are implemented via a lightweight, invisible JavaScript code snippet that follows Cloudflare’s privacy standards ↗. JavaScript is injected only in response to requests for HTML pages or page views, excluding AJAX calls. API and mobile app traffic is unaffected. Additionally, code is not injected again until the current session expires. After page load, the script is deferred and utilizes a separate thread (where available) to ensure that performance impact is minimal.
The snippets of JavaScript will contain a source pointing to the challenge platform, with paths that start with /cdn-cgi/challenge-platform/.
Plans
On the Free plan, it is enabled alongside Bot Fight Mode, while on paid plans, you can configure whether to enable or disable it.
| Plan | Bots | JavaScript detections |
|---|---|---|
| Free | Bot Fight Mode | Always enabled |
| Pro, Business, Enterprise | Super Bot Fight Mode | Toggleable |
| Enterprise | Bot Management | Toggleable |
Challenge Platform
JavaScript detections leverage the power of the Challenge Platform, which is also used by WAF and other products.
However, unlike WAF action challenges, the purpose is different; JavaScript detections themselves do not block requests.
| Product | Function | Purpose | cf_clearance cookie Issuance | Communication with Challenge Platform |
|---|---|---|---|---|
| Bot Management | JavaScript detections | ・Bot Score adjustment (detection ➜ Score 1) ・Use detection results in WAF, Workers, etc.(*) |
○ | Own host/cdn-cgi/challenge-platform/... |
| WAF | Managed Challenge | Blocks clients that fail the challenge (Interactive, Non-Interactive, etc.) | ○ | Own host/cdn-cgi/challenge-platform/... |
challenges.cloudflare.com/...|
|WAF|JS Challnege|Blocks clients that fail the challenge (Non-Interactive)|○|Own host/cdn-cgi/challenge-platform/...
challenges.cloudflare.com...|
|WAF|Interactive Challenge|Blocks clients that fail the challenge (Interactive)|○|Own host/cdn-cgi/challenge-platform/...
challenges.cloudflare.com/...|
(*) The JavaScript detection result (Boolean) is stored in:
-
Rule Field available in WAF Custom Rules, etc.cf.bot_management.js_detection.passed -
Workers variablerequest.cf.botManagement.jsDetection.passed
It becomes true for PASSED and false for FAILED or MISSING.
Verifying JavaScript detections
You can check the detection results in Security > Events.
It looks like the following examples.
-
JavaScript Verificationis Failure, and theBot scoreis 1 due to theBot sourcebeing JavaScript detections.
-
JavaScript Verificationis Passed, and theBot scoreis 99 due to theBot sourcebeing Machine learning.

You can also check via Firewall event logs
$ rclone cat r2:logs/firewall/...log.gz | jq '.Metadata.js_detection'
"PASSED"
"MISSING"
Usage in WAF Custom Rules
WAF Custom Rules can utilize JavaScript detection results in the following two ways:
- Bot Score 1 (adjusted by bot detection)
- Boolean of
cf.bot_management.js_detection.passed
I will test option 2 here, but the prerequisites are as follows:
| Condition | Test Environment |
|---|---|
| You must have JavaScript detections enabled on your zone. |
Configured JavaScript detections for the zone. Currently enabled for the entire zone. |
| You must have updated your Content Security Policy headers for JavaScript detections. | Since I am using CSP on the origin, I have specified a nonce in script-src.JavaScript detections injects inline scripts into original content using that nonce. Also added self and allowed the /cdn-cgi/challenge-platform/... path. |
| You must not run this field on websocket endpoints. | The URL to which the cf.bot_management.js_detection.passed field is applied is not a websocket endpoint. |
| You must use the field in a custom rules expression that expects only browser traffic. | The URL to which the cf.bot_management.js_detection.passed field is applied is an endpoint expected to receive browser traffic. |
| The action should always be a managed challenge in case a legitimate user has not received the challenge for network or browser reasons. | The action is set to Managed Challenge. |
| The path specified in the rule builder should never be the first HTML page a user visits when browsing your site. | It is assumed that the user accesses the target /jsd.php (content type optional) after first visiting the parent page / (HTML). |
The Custom Rules setting for the protected endpoint looks like the image below.

Demo
Access to the parent page
First, sending a request to the parent page / results in a sequence like the one below.
1️⃣ The browser encounters a script embedded in the HTML body similar to the following.

2️⃣ The browser successfully verifies and obtains the cf_clearance cookie. The domain is the zone itself.

Expiration of cf_clearance cookie in JavaScript detection
As long as the cf_clearance cookie issued by JavaScript detections is valid, the detection will not trigger. Regarding the part in the Dev Docs that says "Additionally, code is not injected again until the current session expires," in the case of JavaScript detections, I observed behavior where JavaScript detections were re-executed and the cookie was updated after about 12 minutes from the issuance of the cf_clearance cookie. (The cookie itself expires in 1 year.)
Request to a protected endpoint
From this state, I access /jsd.php, which is protected by WAF Custom Rules.
3️⃣ Subsequent requests to /jsd.php are accompanied by the cf_clearance cookie that has passed JavaScript detections. Therefore, cf.bot_management.js_detection.passed becomes true, and the request reaches the origin without undergoing Managed Challenge or JavaScript detections.
4️⃣ Even if the response from the origin is HTML, JavaScript is not injected.
Direct access
I assume a case of direct access without the cf_clearance cookie mentioned above.
Managed Challenge
Since I followed the condition stated in the prerequisites, "The action should always be a managed challenge in case a legitimate user has not received the challenge for network or browser reasons," a Managed Challenge is triggered.
Once the Managed Challenge is cleared, a cf_clearance cookie is issued by the WAF.
If the content is HTML, JavaScript detections are performed after clearing the Managed Challenge, and upon success, the cf_clearance cookie for JavaScript detections is overwritten. The sequence became complex, with the Challenge Platform being used twice, as shown below.
Block
I tried setting the action to Block and using the HTML block page.

Interestingly, JavaScript detections were triggered against the HTML of the block page.
In other words, the browser passed the JavaScript detections in the process of displaying the block page, resulting in the same situation as when accessing the parent page.

When reloading, the response is returned without being subject to JavaScript detections.

This behavior was the same for both the default block page and Custom Pages.
Custom HTML was also similar.
However, by using this, I was able to perform JavaScript detections while redirecting to the parent page, which was more user-friendly than the Managed Challenge.

Custom HTML Example
<!doctype html><html><head>
<meta charset="utf-8" />
<meta http-equiv="refresh" content="1; url='https://<parent page>/'"/>
</head>
<body></body></html>
As shown above, the parent page was displayed automatically, allowing access to the endpoint link.
Communicating JavaScript detection results to the origin server
I verified if JavaScript detection results could be communicated to the origin server.
While there is a bot protection headers option in Managed Transforms of Transform Rules, unfortunately, it seems JavaScript detections are not included as of this writing.

Therefore, I embedded it in the headers using Workers (in this case, Snippets).


snippets
export default {
async fetch(request) {
const newRequest = new Request(request)
const jsDetectionValue = request.cf?.botManagement?.jsDetection?.passed ?? 'unknown'
newRequest.headers.set(
'X-Bot-JS-Detection-Passed',
jsDetectionValue.toString()
)
return fetch(newRequest)
}
}
It seems that the origin side can also use this in implementing security logic, in combination with other signals such as Bot Score and JA4 Fingerprint.
Conclusion
Methods to circumvent bot detection and WAF challenges are constantly researched, evolved, and disclosed, both old and new. On the other hand, the defense platform side is also undergoing continuous development, leading to a cat-and-mouse game. Since this field is advancing day by day, I am noting this article as observations as of the time of writing (January 2025).
Discussion