Turnstile plugin

Show and validate a Cloudflare's Turnstile captcha

Usage

To use it, you need to register site and secret keys at the Cloudflare dashboard page.
The following piece of code is the starting point to use the Turnstile plugin:
<html>
<head>
<link rel="stylesheet" href="/vendors/@form-validation/umd/styles/index.min.css" />
</head>
<body>
<form id="demoForm" method="POST">
...
<!-- Prepare a container to show the captcha -->
<div id="captchaContainer"></div>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.3/es6-shim.min.js"></script>
<script src="/vendors/@form-validation/umd/bundle/popular.min.js"></script>
<script src="/vendors/@form-validation/umd/plugin-turnstile/index.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function(e) {
FormValidation.formValidation(
document.getElementById('demoForm'),
{
fields: {
...
},
plugins: {
...,
turnstile: new FormValidation.plugins.Turnstile({
element: 'captchaContainer',
message: ...,
siteKey: ...,
// Other options
// ...
}),
},
}
);
});
</script>
</body>
</html>
The sample code above assumes that the FormValidation files are placed inside the vendors directory. You might need to change the path depending on where you place them on the server.

Options

OptionTypeDescription
backendVerificationUrlStringThe URL of your back-end that verifies the captcha via Turnstile API
element *StringThe ID of element showing the captcha
message *StringThe invalid message that will be shown in case the captcha is not valid
siteKey *StringThe site key provided by Turnstile
Bellow are the list of options provided by Turnstile
OptionTypeDescription
actionStringA customer value that can be used to differentiate widgets under the same sitekey in analytics and which is returned upon validation
appearanceStringAppearance controls when the widget is visible. It can be always (default), execute, or interaction-only
cDataStringA customer payload that can be used to attach customer data to the challenge throughout its issuance and which is returned upon validation
languageStringLanguage to display, must be either: auto (default) to use the language that the visitor has chosen, or an ISO 639-1 two-letter language code (e.g. en) or language and country code (e.g. en-US)
refreshExpiredStringAutomatically refreshes the token when it expires. Can take auto (default), manual or never
retryStringControls whether the widget should automatically retry to obtain a token if it did not succeed. The default is auto, which will retry automatically. This can be set to never to disable retry upon failure
retryIntervalnumberWhen retry is set to auto, this controls the time between retry attempts in milliseconds. Value must be a positive integer less than 900000, defaults to 8000
sizeStringThe widget size. Can take the following values: normal, compact
tabIndexnumberThe tabindex of Turnstile’s iframe for accessibility purposes. The default value is 0
themeStringThe widget theme. Can take the following values: light, dark, auto (default)

Using the npm packages

If you are using a bundler such as Webpack, Rollup, Parcel or Vite, etc., to bundle your application, then it's recommended to use the FormValidation NPM packages.
  • Install the packages:
$ npm install @form-validation/bundle
$ npm install @form-validation/plugin-turnstile
  • Import and use the Turnstile plugin:
import { formValidation } from '@form-validation/bundle/popular';
import { Turnstile } from '@form-validation/plugin-turnstile';
formValidation(
document.getElementById('demoForm'),
{
fields: {
...
},
plugins: {
turnstile: new Turnstile({
...
}),
...
},
}
);

Turnstile widget

The following form shows a Turnstile widget.
reCAPTCHA widget

Invisible challenge

The following form shows an invisible widget. In order to use it properly, remember to set the appearance: 'execute' option.
Invisible challenge

Back-end verification

If you want to take more steps of checking if the visitor on your site isn't a robot, then let's verify the captcha on the back-end side. You need to point the backendVerificationUrl option to your back-end URL:
FormValidation.formValidation(
document.getElementById('demoForm'),
{
fields: {
...
},
plugins: {
...
turnstile: new FormValidation.plugins.Turnstile({
backendVerificationUrl: '/path/to/your/back-end/',
}),
},
}
);
When that option is enabled, the plugin will send an Ajax request with the value for cf-turnstile-response parameter. With the value of captcha and the Turnstile secret key, you can connect to Turnstile verification URL to verify the captcha.
In order to inform user in case the captcha is valid or invalid, the back-end has to return a JSON encoded version of
{
"success": "true"
}
// or
{
"success": "false"
}
The following code demonstrates how to do it in PHP, but you can do it with your favorite language.
<?php
// Replace it with your Turnstile secret key
$secretKey = '...';
// See https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
$fields = array(
'secret' => $secretKey,
'response' => $_POST['cf-turnstile-response']
);
$postVars = '';
$sep = '';
foreach ($fields as $key => $value) {
$postVars .= $sep . urlencode($key) . '=' . urlencode($value);
$sep = '&';
}
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, 'https://challenges.cloudflare.com/turnstile/v0/siteverify');
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $postVars);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
header('Content-Type: application/json');
echo $result;

Changelog

v2.4.0