Skip to content

Cloudflare Turnstile Configuration

Cloudflare Turnstile is an optional alternative captcha provider for the storefront forms Magento already guards. Google reCAPTCHA stays the default, and a store that does not install Turnstile behaves exactly as before.

Requires Venta 1.7.2 or later.

Overview

The reason to reach for Turnstile is cookie consent. On a store running the Magebit GDPR extension, that extension replaces the reCAPTCHA script loader with one that holds Google's api.js back until the visitor accepts cookies. A form guarded by reCAPTCHA v2, checkbox or invisible, then has no widget to complete, so a visitor who declines cannot submit it at all. Turnstile has no such gate, so its forms stay usable and guarded either way.

Without the GDPR extension there is no consent gate on either provider, and the choice comes down to which vendor you want your shoppers' browsers talking to.

Venta also replaces the way the token is verified. The Turnstile module picks its verification endpoint by looking for a cf-turnstile-response POST parameter, which is absent whenever the token travels as a header or inside a JSON body, so on stock Magento a Turnstile token from the product review form, which posts it as a header to GraphQL, or from the authentication popup, which sends it in a JSON body, is verified against Google and rejected. Venta routes verification by the configured secret instead, which is present in every transport.

Installation

The module is not part of the theme. Install it in the project that needs it:

bash
composer require boxtwentytwo/module-cloudflare-turnstile
bin/magento module:enable BoxTwentyTwo_CloudflareTurnstile
bin/magento setup:upgrade
bin/magento cache:flush

In production mode also run setup:di:compile and setup:static-content:deploy.

The package ships its own Content Security Policy entry for challenges.cloudflare.com. If you tighten the storefront policy by hand, keep that host allowed; the directives Turnstile needs are listed in Cloudflare's CSP reference.

Cloudflare Setup

Create the widget before touching the Magento admin, because the widget mode cannot be changed from Magento afterwards.

  1. In the Cloudflare dashboard, open Turnstile and add a widget.
  2. Set the hostnames the widget will run on, including your staging domain.
  3. Set the widget mode to Invisible. See Cloudflare's widget types for what each mode does.
  4. Copy the site key and the secret key.

Invisible mode is what Venta's form layouts expect. A Managed or Non-interactive widget renders a visible challenge box inside forms that were built without room for one. Magento cannot read the widget mode, so nothing in the admin will warn you if it is wrong.

Configuration

Configuration Path: Stores > Configuration > Security > Google reCAPTCHA Storefront

Once the module is installed, a Cloudflare Turnstile group appears in that section, next to the reCAPTCHA v2 and v3 groups.

#FieldDefaultWhat it does
1Site KeyEmptyThe site key from your Cloudflare widget. Stored encrypted.
2Secret KeyEmptyThe secret key from the same widget. Stored encrypted.
3SizenormalWidget size. Applies only to a visible widget.
4ThemelightWidget theme. Applies only to a visible widget.
5Language CodeEmptyWidget language. Applies only to a visible widget.

Config paths:

  1. recaptcha_frontend/type_cf_turnstile/public_key
  2. recaptcha_frontend/type_cf_turnstile/private_key
  3. recaptcha_frontend/type_cf_turnstile/size
  4. recaptcha_frontend/type_cf_turnstile/theme
  5. recaptcha_frontend/type_cf_turnstile/lang

Both keys are required. A form set to Turnstile with no site key saved renders no widget at all and is simply unguarded, with nothing on the page to say so.

Scopes are not uniform: Site Key, Secret Key, Size and Theme can be set at Default and Website level only, while Language Code can also be overridden per Store View. The matching group under Google reCAPTCHA Admin Panel, which guards the admin login and forgot-password forms, is Default scope only.

Each form is then switched over individually, in the Enable for ... groups of the same section: Enable for Contact Us, Enable for Newsletter Subscription, Enable for Customer Login and so on. Every one of them gains a Cloudflare Turnstile option alongside the reCAPTCHA versions.

Usage

  1. Create the invisible widget and copy both keys, as described under Cloudflare Setup.
  2. Go to Stores > Configuration > Security > Google reCAPTCHA Storefront.
  3. Paste the site key and secret key into the Cloudflare Turnstile group.
  4. In every Enable for ... group, select Cloudflare Turnstile.
  5. Reword the two failure messages and update your privacy policy, as described under Before Going Live.
  6. Save the configuration and flush the cache.

One Provider Per Store

Select Turnstile for every guarded form, or for none of them. Mixed configurations are not supported.

Both providers publish themselves to the page through the same window.grecaptcha global, because Turnstile runs in reCAPTCHA compatibility mode. Venta's loaders no longer key off that global at all: each waits for its own vendor's load callback before it acts, so neither can silence the other. What the loaders cannot fix is the global itself. Both widget templates still call grecaptcha.render() on it, and on a mixed page the vendor whose script settles last owns it, so the other provider's widget can fail to render.

The resulting failure does not name its cause. The losing vendor's submit path calls into the wrong shim: a form on reCAPTCHA v3 calls grecaptcha.ready(), reaches Turnstile's ready() instead, and Cloudflare logs turnstile.ready() would break if called *before* the Turnstile api.js script is loaded by visitors. No token is issued and the form does not submit. Both vendors' api.js showing up in the network tab is the quickest confirmation.

Ending up mixed by accident is easy, because the Enable for ... fields are Default and Website scope only. A website override is invisible until you switch the scope selector, and a store view row cannot be set from the admin at all, yet still wins at runtime if one exists from an older Magento version, a config:import, or bin/magento config:set --scope=store. Read every scope out of the database rather than trusting the admin screen:

sql
SELECT scope, scope_id, path, value
FROM core_config_data
WHERE path LIKE 'recaptcha_frontend/type_for/%'
ORDER BY path, scope;

The footer disclosure is also a page-level decision rather than a per-form one. A store mixing Turnstile with reCAPTCHA v3 or v2 Invisible keeps showing Google's written disclosure, because one of its forms still uses a badge-hidden Google type.

Before Going Live

Reword the failure messages. The reCAPTCHA Failure Messages group in the same section holds the two texts a shopper sees when verification fails, and both defaults name Google:

  • reCAPTCHA Validation Failure Message - reCAPTCHA verification failed.
  • reCAPTCHA Technical Failure Message - Something went wrong with reCAPTCHA. Please contact the store owner.

These are the texts Magento shows for every provider. The field labels come from Magento and cannot be changed from the admin, but the values can.

Update your privacy policy. Cloudflare requires the site operator to disclose Turnstile's use. Your privacy policy has to reference the Cloudflare Privacy Policy and the terms covering Turnstile, in the same way the site already discloses Google reCAPTCHA. See the Cloudflare privacy documentation for the text that applies. An invisible widget shows the visitor nothing, so the privacy policy is the only place this disclosure exists. Venta does not add a Turnstile notice to the footer.

Installing the module also seeds a CMS page, venta-privacy-policy-turnstile-edition, as a starting point. It is disabled and full of placeholders, so it is a draft to adapt and have reviewed, not a policy to publish as it stands.

Console Output

The widget runs inside an iframe served by challenges.cloudflare.com, and that iframe writes several messages to the browser console on every page carrying a Turnstile-guarded form. They come from Cloudflare's code, not from the theme, and none of them indicates a problem:

  • [Cloudflare Turnstile] Compatibility layer enabled. - Confirms the script loaded with ?compat=recaptcha, so window.grecaptcha is now Turnstile's shim.
  • OTS parsing error: Size of decompressed WOFF 2.0 is less than compressed size - A font inside Cloudflare's iframe fails the browser's font validator.
  • No available adapters. - A WebGPU probe inside the same iframe.

Switching the captcha off removes all of them, which is the quickest way to tell whether a console message belongs to the widget or to the form.

Opening developer tools changes what the widget does. Execution pauses for an instant on a debugger statement, which runs in a Web Worker created from a blob: URL on Cloudflare's own origin. Turnstile also treats an open console, and an automated browser such as one driven by Playwright, as suspicious: the widget can then fail on every render with [Cloudflare Turnstile] Error: 600010, while the same page passes once the tools are closed. Reproduce a suspected captcha fault in an ordinary browser session before reading 600010 as a configuration error.

Removing the Module

Switch every form off Cloudflare Turnstile before removing the package.

The config rows outlive the module. If the package is removed while a form is still set to Turnstile, that form is left unguarded: Venta treats a captcha type with no installed provider as disabled and writes a warning to the log rather than failing the page, so the storefront keeps working and nothing on screen says the form lost its protection.

Notes

  • Both keys are registered as sensitive and environment-specific, so bin/magento app:config:dump does not export them. A pipeline that ships app/etc/config.php will deploy a store with no keys, and therefore with unguarded forms, unless the keys are set on the target environment.
  • Cloudflare publishes dummy site and secret keys for each outcome you might want to test, including always-passes, always-blocks and forced-interactive. See Turnstile testing. Google publishes no equivalent for reCAPTCHA v3, so a test environment that needs a working Google captcha has to use a real key.
  • Pre-Clearance, which lets one solved challenge cover later requests through a cf_clearance cookie, is configured on the Cloudflare side. See Pre-Clearance support.
  • Offlabel widgets, which drop the Cloudflare branding, require a Cloudflare Enterprise plan.