How to implement Turnstile to detect a Bot in React web application?


What’s Turnstile of Cloudflare?
In fact, I previously used Google CAPTCHA to detect bots on all my websites, but recently I discovered Cloudflare’s Turnstile and took advantage of it. As a result, I think it is more efficient and useful than Google CAPTCHA.
Turnstile is Cloudflare’s smart CAPTCHA alternative. It can be embedded into any website without sending traffic through Cloudflare and works without showing visitors a CAPTCHA.
I’ve provided an image of Turnstile’s workflow, if you’d like to learn more about it, visit here.
Turnstile Concepts
Widget types
Every instance of Turnstile belongs to a Turnstile widget. It is configured on a per-widget level. Every widget has a mode, a label, a sitekey, and a secret key.
The 3 modes for Turnstile are Managed, Non-Interactive, and Invisible.
Managed (recommended)
This mode is fully managed by Cloudflare. It automatically chooses the appropriate action based on various signals and risk levels. Cloudflare will use the information from the visitor to decide if an interactive challenge should be used. Turnstile will only require interaction if a further check is necessary to verify that the visitor is human. When Turnstile shows an interaction, the user will be prompted to check a box (no images or text to decipher). This managed mode is ideal for users who want a simple configuration without needing to fine-tune the behavior.
Refer to appearance modes to configure whether to have the widget be always visible or visible only when interaction is required.Non-Interactive
Visitors will see a widget with a loading bar while the browser challenges run. Unlike managed mode, visitors will never be required or prompted to interact with the widget. This mode is ideal for users who want to prioritize visitor experience and do not want to add any friction with a Turnstile interaction.Invisible
This mode is similar to non-interactive mode where visitors will never interact with the Turnstile widget. Visitors will not see a widget or any indication that an invisible browser challenge is in progress. Invisible challenges should take a few seconds to complete.
Domain management
You must specify a list of domains when creating a widget. The widget can only be used on these domains and will not work on any other domains. You can use subdomains to restrict the widgets further.
The domain should not contain a scheme http://
or https://
, a port 443
, or a path /
.
Specifying a subdomain is optional.
For example, using the www.example.com
value will allow widgets on the following domains:
but not on the following domains:
When the widget is embedded on a domain not listed, it will show an error message.
Enterprise Bot Management customers can remove the domain validation requirement for a widget. For more information on this feature, contact your account team.
Pre-Clearance support for single-page applications
You can integrate Cloudflare challenges on single-page applications (SPAs) by allowing Turnstile to issue a Pre-Clearance cookie. The Pre-Clearance level is set upon widget creation or widget modification using the Turnstile API’s clearance_level
. Possible values for the configuration are no_clearance
, jschallenge
, managed
, or interactive
. All widgets are set to no_clearance
by default.
For Enterprise customers eligible to toggle off domain checks, Cloudflare recommends issuing Pre-Clearance cookies on widgets where at least one domain is specified.
Pre-Clearance cookies only support zones that are orange-clouded.
Refer to the blog post for an example of Pre-Clearance implementation.
Pre-Clearance level options
- Interactive: Interactive Pre-Clearance allows a user with a clearance cookie to not be challenged by Interactive, Managed Challenge, or JavaScript Challenge Firewall Rules
- Managed: Managed allows a user with a clearance cookie to not be challenged by Managed Challenge or JavaScript Challenge Firewall Rules
- Non-interactive: Non-interactive allows a user with a clearance cookie to not be challenged by JavaScript Challenge Firewall RulesDuration
Clearance cookies generated by the Turnstile widget will be valid for the time specified by the zone-level Challenge Passage value. To configure the Challenge Passage setting, refer to the WAF documentation.Enable Pre-Clearance on a new site
- Log in to the Cloudflare dashboard and select your account.
- Go to Turnstile \> Add Site.
- Under Would you like to opt for Pre-Clearance for this site? select Yes.
- Choose the Pre-Clearance level from the select box.
- Select Create.Enable Pre-Clearance on an existing site
- Log in to the Cloudflare dashboard and select your account.
- Go to Turnstile.
- Go to the existing widget or site and select Settings.
- Under Would you like to opt for Pre-Clearance for this site? select Yes.
- Choose the Pre-Clearance level from the select box.
- Select Update.
Implement Turnstile in your React website.
Step 1. Get a sitekey and secret key
To start using the Turnstile widget, you will need to obtain a sitekey and a secret key. The sitekey and secret key are always associated with one widget and cannot be reused for other widgets.
The sitekey is public and used to invoke the Turnstile widget on your site.
The sitekey and secret key are generated upon the creation of a widget, allowing communication between your site and Cloudflare to verify responses for a solved challenge from Turnstile. Make sure you keep the secret key safe for security reasons.
You can find special sitekeys to be used for testing in the testing section.
New sites
Log in to the Cloudflare dashboard and select your account.
Go to Turnstile
Select Add a site and fill out the site name and your website’s hostname or select from your existing websites on Cloudflare.
Select the widget mode.
(Optional) Opt in for pre-clearance support.
Copy your sitekey and secret key.
Existing sites
Log in to the Cloudflare dashboard and select your account.
Go to Turnstile
In the widget overview, select Settings.
(Optional) Opt in for pre-clearance support.
Copy your sitekey and secret key.
Step 2. Add the Turnstile widget to your site
- Insert the Turnstile script snippet in your HTML’s
<head>
element
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
Install @marsidev/react-turnstile on your react app.
Render a Turnstile widget
const TurnstileWidget = () => { const [token, setToken] = useState(''); const [tokenStatus, setTokenStatus] = useState(null); useEffect(() => { if (token === '') { const response = await axios.post('/api/check/turnstile', { token }); const result = response.data; if (result.outcome.success === true) { console.log('You are a human.'); } else { console.log('You are a bot.'); } } }, [token]); return ( <Turnstile style={{ width: '0px', height: '0px', overflow: 'hidden' }} siteKey={process.env.REACT_APP_TURNSTILE_SITE_KEY} onError={() => setTokenStatus('error')} onExpire={() => setTokenStatus('expired')} onSuccess={token => { setToken(token); setTokenStatus('solved'); }} onWidgetLoad={widgetId => console.log('Widget loaded', widgetId)} /> ); }; export default TurnstileWidget;
Step 3. Validate the server-side
After you have installed the Turnstile widget on your site, you must configure your server to validate the Turnstile response. Refer to Server-side validation.
In my case, my server is express and I used my own logic for it.
const checkTurnstileToken = async (req, res) => {
try {
const { token } = req.body;
// Validate the token by calling the Turnstile API
let formData = new FormData();
formData.append('secret', config.TURNSTILE_SECRET_KEY);
formData.append('response', token);
formData.append('remoteip', ip); // Optional
const url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
const result = await fetch(url, {
body: formData,
method: 'POST',
});
const outcome = await result.json();
if (outcome.success) {
return res.status(200).json({ outcome });
} else {
return res.status(400).json({ error: MESSAGE.INVALID_TOKEN });
}
} catch (error) {
console.error('Error checking turnstile token:', error);
return res.status(500).json({ error: MESSAGE.INTERNAL_SERVER_ERROR });
}
};
Conclusion
In this blog, I wrote about the Cloudflare Turnstile feature, which is a very useful and efficient way to detect on websites. In the future, I will share more of the experiences I have gained throughout my IT career.
Thanks for reading!
Subscribe to my newsletter
Read articles from Youth Dream directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Youth Dream
Youth Dream
Accomplished Software Engineer with 6 years of experience specializing in the Python, Node.js, React and Next.js ecosystem, and a proven track record in testing and performance optimization. Demonstrated leadership in guiding teams and implementing best practices in development.