Conditionally enforce Turnstile
Last updated Apr 16, 2026 This tutorial explains how to conditionally enforce Turnstile based on the incoming request, such as a pre-shared secret in a header or a specific IP address.
Overview
You may have setups such as automation that cannot load or run the Turnstile challenge. Using HTMLRewriter, this tutorial will demonstrate how to conditionally handle the client-side widget and Siteverify API when specific criteria are met.
Note
While this tutorial removes Turnstile client-side elements when specific criteria are met, you could instead conditionally insert them.
Caution
It is critical to make sure you are validating tokens with the Siteverify API when your criteria for enforcing Turnstile are not met.
It is not sufficient to only remove the client-side widget from the page, as an attacker can forge the request to your API.
Implementation
This tutorial will modify the existing Turnstile demo ↗︎ to conditionally remove the existing script and widget container elements.
src/index.mjsdiff
export default {
async fetch(request) {
// ...
+ if (request.headers.get("x-bypass-turnstile") === "VerySecretValue") {
+ class RemoveHandler {
+ element(element) {
+ element.remove();
+ }
+ }
+
+ return new HTMLRewriter()
+ // Remove the script tag
+ .on(
+ 'script[src="https://challenges.cloudflare.com/turnstile/v0/api.js"]',
+ new RemoveHandler(),
+ )
+ // Remove the container used in implicit rendering
+ .on(
+ '.cf-turnstile',
+ new RemoveHandler(),
+ )
+ // Remove the container used in explicit rendering
+ .on(
+ '#myWidget',
+ new RemoveHandler(),
+ )
+ .transform(body);
+ }
return new Response(body, {
headers: {
"Content-Type": "text/html",
},
});
},
};
Server-side integration
We will exit early in our validation if the same logic we used to remove the client-side elements is present.
Caution
The same logic must be used in both the client-side and the server-side implementations.
src/index.mjsdiff
async function handlePost(request) {
+ if (request.headers.get("x-bypass-turnstile") === "VerySecretValue") {
+ return new Response('Turnstile not enforced on this request')
+ }
// Proceed with validation as normal!
const body = await request.formData();
// Turnstile injects a token in "cf-turnstile-response".
const token = body.get('cf-turnstile-response');
const ip = request.headers.get('CF-Connecting-IP');
// ...
}
With these changes, Turnstile will not be enforced on requests with the header x-bypass-turnstile: VerySecretValue present.
Demonstration
After running npm run dev in the project folder, you can test the changes by running the following command:
curl -X POST http://localhost:8787/handler -H "x-bypass-turnstile: VerySecretValue"
Turnstile not enforced on this request
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/turnstile/tutorials/conditionally-enforcing-turnstile/#page","headline":"Conditionally enforce Turnstile","description":"This tutorial explains how to conditionally enforce Turnstile based on the incoming request, such as a pre-shared secret in a header or a specific IP address.","url":"https://developers.cloudflare.com/turnstile/tutorials/conditionally-enforcing-turnstile/","inLanguage":"en","image":"https://developers.cloudflare.com/turnstile/tutorials/conditionally-enforcing-turnstile/og.png?v=3404859b89a76109","dateModified":"2026-04-16","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["Node.js","TypeScript"]}
description: This tutorial explains how to handle Turnstile in your end-to-end (E2E) tests by using Turnstile's dedicated testing keys. title: Exclude Turnstile from E2E tests image: https://developers.cloudflare.com/turnstile/tutorials/excluding-turnstile-from-e2e-tests/og.png?v=5f2490f78d7e438f
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/turnstile/llms.txt
Use this file to discover all available pages before exploring further.
Docs