Stop spam without punishing real users. Kitgenix CAPTCHA for Cloudflare Turnstile integrates Cloudflare’s modern, low-friction,
reCAPTCHA-free challenge with WordPress so you can block bots
and keep conversions high.
Protect
WordPress login/registration/password/comments,
WooCommerce checkout & account (Classic + Blocks / Store API), and
popular form builders using
server-side verification,
replay protection, and
proxy-aware IP detection. Built for performance (async/conditional loading) and privacy (no cookies or tracking added by the plugin; GDPR-friendly).
Why Kitgenix
- Ultra-lightweight & fast — Modern WP Script API (6.3+) with
strategy=async; loads only where needed.
- Privacy-first — No cookies/tracking added by the plugin; Turnstile minimizes data collection.
- Rock-solid server-side validation — Official
siteverify endpoint.
- Replay protection — Rejects reused tokens by default (TTL filterable).
- Proxy-aware client IP — Honors CF/Proxy headers only from trusted proxies.
- Seamless integrations — WordPress Core, WooCommerce (Classic & Blocks), Elementor Pro, and major form plugins.
- Smart UX — Optional “disable submit until verified”, token freshness timers, inline error hints.
- Production-ready admin — Onboarding, Site Health test, JSON import/export, accessible UI.
- Multisite aware — Clean uninstall removes settings site-wide (and network-wide on Multisite).
Supported Forms & Integrations (with descriptions)
WordPress Core
- Login, Registration, Lost/Reset Password, Comments\
Adds a Turnstile widget to core auth and discussion forms. Validates tokens on submit (POST-only) and blocks invalid/expired/reused tokens with a clear message.
WooCommerce (Classic)
- Checkout, Login, Registration, Lost Password\
Renders near the Place order area and account/auth forms. Server-side verification runs during checkout validation and account actions. Designed to work with fragment reloads; avoids double-submit and duplicate renders.
WooCommerce (Blocks / Store API)
- Checkout (Blocks)\
Injects the widget in Blocks checkout UIs and validates Store API requests on the server. Token can be forwarded via header (e.g.,
X-Turnstile-Token) and is handled automatically by the plugin/extension.
Elementor Pro (Forms & Popups)
- Elementor Pro Forms (including Popups and dynamically rendered forms)\
Injects before/after the submit area. Listens to Elementor events to re-render on popups, AJAX submissions, and validation errors. Ensures a fresh token on each attempt.
Contact Form 7
- All CF7 forms\
Auto-injects the widget; resets and re-renders after AJAX errors. No special shortcode needed. Prevents send on failed verification.
Fluent Forms
- All Fluent Forms\
Auto-injects and validates server-side via the plugin’s hooks. Handles AJAX and multi-step flows with automatic re-render.
Formidable Forms
- All Formidable forms\
Auto-injects the widget; validates on submit; re-renders after client or server validation errors.
Forminator Forms
- All Forminator forms\
Works with regular and AJAX-loaded forms, including multi-step. Automatically resets token on failed submissions.
Gravity Forms
- All Gravity Forms\
Widget placement before/after submit; validates server-side on the form’s native hooks. Handles AJAX and multi-page with safe re-render.
Jetpack Forms
- Jetpack Contact Forms\
Adds Turnstile to Jetpack forms and validates on submit. Respects Jetpack’s AJAX behaviors.
Kadence Forms (Kadence Blocks)
- Kadence Forms\
Auto-injects on Kadence form blocks; validates server-side; re-renders on client errors.
WPForms
- All WPForms (Lite/Pro)\
Injects before/after the submit area; prevents send until verification passes (optional disable-until-verified UX); resets on AJAX errors.
Forums: bbPress
- Create Topic & Reply forms (bbPress)\
Adds Turnstile to bbPress posting forms to reduce automated spam topics/replies. Validates before content is saved.
Enable/disable each integration and location in Settings → Cloudflare Turnstile.
How It Works (Technical)
- Loads
https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit with async strategy (WP ≥ 6.3).
- Injects a widget into enabled forms; re-renders for dynamic loads (AJAX, multi-step, popups).
- Validates server-side via
/v0/siteverify with your secret key and request IP (when appropriate).
- On failure (invalid/expired/reused token) submission is blocked with clear, customizable messaging.
Quick Start
- Install & Activate → Plugins → Add New → search “Kitgenix Turnstile”.
- Add Keys → Settings → Cloudflare Turnstile → paste Site Key & Secret Key from your Cloudflare dashboard.
- Choose Integrations → toggle WordPress/WooCommerce/Form plugins and specific locations.
- Save & Test → try login/register/comments/checkout + your form pages.
- Optional Hardening → enable Disable Submit Until Verified and review Tools → Site Health hints.
Performance Playbook
- Async by default with WP Script API (6.3+).
- Conditional loading — scripts only where protection is active.
- Optimization plugins:
- Allowlist
https://challenges.cloudflare.com.
- Do not inline or block the Turnstile script.
- Exclude login, account, and checkout pages from full-page caching.
- Resource hints — preconnect/dns-prefetch for faster first paint.
Security Tips
- Replay protection — enabled by default; tune TTL via
kitgenix_turnstile_replay_ttl.
- Trusted proxies — configure Trusted Proxies for accurate client IPs behind Cloudflare/NGINX/etc.
- Developer Mode (warn-only) — on staging, log failures without blocking.
- Whitelisting — logged-in/IP/UA; use sparingly.
Troubleshooting
Widget not showing → Check keys + enabled location; confirm you’re not whitelisted; clear caches; allowlist
challenges.cloudflare.com; check console for blockers.\
“Please verify you are human” → Token expired/invalid; reduce page-cache TTL on form pages; don’t cache auth/checkout; ensure the server can reach Cloudflare.\
Elementor popups/AJAX → Don’t over-defer Elementor/form plugin JS; the plugin listens for those events.\
WooCommerce checkout → Don’t cache fragments; confirm widget renders before
Place order; ensure token is forwarded on custom checkouts.
Frequently Asked Questions
= Do I need a Cloudflare account? =\
Yes. A free Cloudflare account is enough to generate a
Turnstile Site Key and
Secret Key.
= Does this support Elementor Free? =\
We officially support
Elementor Pro Forms. A fallback injector helps on general Elementor forms (including popups), but
Pro Forms is the target for reliability.
= Is this compatible with caching/optimization plugins? =\
Yes. Scripts are async/conditional and the widget re-renders after dynamic events. If your optimizer inlines/defers third-party scripts, ensure
challenges.cloudflare.com isn’t blocked.
= Can I skip validation for certain users? =\
Yes - whitelist logged-in users, IPs (exact/wildcard/CIDR), or user agents.
= How is this different from Google reCAPTCHA? =\
Cloudflare Turnstile is a
privacy-first, low-friction alternative that avoids user tracking while blocking bots.
= Which form plugins are supported? =\
WPForms, Fluent Forms, Gravity Forms, Formidable Forms, Contact Form 7, Forminator, Jetpack Forms, Kadence Forms — plus Elementor Pro Forms.
= Can I change theme/size/language? =\
Yes - choose
auto/light/dark,
small/normal/large,
always/interaction-only, and language (
auto or locale code).
= Can I pin/self-host the Turnstile script? =\
Yes, via the
kitgenix_captcha_for_cloudflare_turnstile_script_url filter.
= Does it work on Multisite? =\
Yes. Settings are per-site. Uninstall removes settings site-wide (and network-wide when run network-wide).
= Is the plugin GDPR compliant? =\
The plugin itself doesn’t store personal data. Cloudflare Turnstile processes IP and user-agent for verification. Consult legal counsel and Cloudflare’s docs for your use case.
Developers
Filters
kitgenix_captcha_for_cloudflare_turnstile_script_url( $url, $settings ) - Override the Turnstile script URL or add params.
kitgenix_turnstile_freshness_ms - Control token auto-reset interval (ms).
kitgenix_turnstile_replay_ttl - Adjust replay-protection cache duration (seconds).
-
kitgenix_turnstile_is_whitelisted( $is_whitelisted, $context ) - Modify whitelist decisions programmatically.
Server-side endpoint
-
Validates via
https://challenges.cloudflare.com/turnstile/v0/siteverify.
Text domain
-
kitgenix-captcha-for-cloudflare-turnstile (POT included).
Integration Files (for developers)
(Each integration listed above corresponds to the file(s) below.)
-
WordPress Core:\
includes/integrations/wordpress/class-wp-core.php
-
WooCommerce (Classic):\
includes/integrations/ecommerce/class-woocommerce.php
-
WooCommerce (Blocks / Store API):\
includes/integrations/ecommerce/class-woocommerce-blocks.php
-
Elementor Pro:\
includes/integrations/page-builder/class-elementor.php
-
Form Plugins:\
Contact Form 7 —
includes/integrations/forms/contact-form-7.php\
Fluent Forms —
includes/integrations/forms/fluent-forms.php\
Formidable Forms —
includes/integrations/forms/formidable-forms.php\
Forminator Forms —
includes/integrations/forms/forminator-forms.php\
Gravity Forms —
includes/integrations/forms/gravity-forms.php\
Jetpack Forms —
includes/integrations/forms/jetpack-forms.php\
Kadence Forms —
includes/integrations/forms/kadence-forms.php\
WPForms —
includes/integrations/forms/wpforms.php
-
Forums:\
bbPress —
includes/integrations/forums/bbpress.php
-
Integration folders:\
includes/integrations/\
includes/integrations/ecommerce/\
includes/integrations/forms/\
includes/integrations/forums/\
includes/integrations/page-builder/\
includes/integrations/wordpress/
1.0.11 (19 October 2025)
- Fix: Elementor AJAX regression — prevented a brief layout “bump” where interaction-only lost
.kt-ts-collapsed during the AJAX send; the container now stays collapsed unless a visible challenge is explicitly required.
1.0.10 (16 October 2025)
- Fix: Elementor Popups — reliably initializes the Turnstile challenge when a popup opens (even if the widget was inserted while hidden). Clears stale render flags, resets hidden iframes, and triggers a fresh render on show.
- Fix: Hidden input — always ensures
input[name="cf-turnstile-response"] exists for Elementor forms (including popups) so the token is properly captured and validated.
- Fix: Interaction Only empty gaps — placeholders are now fully collapsed until the widget actually renders (via
data-rendered). After successful AJAX submits, the container is collapsed/hidden to prevent any blank space.
- Fix: Multiple forms on a page — consistent collapsed behavior across instances; prevents duplicate containers in Elementor popups and re-renders only when needed.
- Improvement: Event-driven rendering — added
kgx:turnstile-containers-added event from injectors; public script listens and re-initializes rendering automatically for dynamically added containers.
- Improvement: Stability and UX — defensive re-render guards, explicit
data-rendered attribute for CSS control, and safer visibility checks to avoid rendering inside hidden containers.
1.0.9 (15 October 2025)
- Fix: “Disable Submit Button” now respects “Interaction Only” — submit stays enabled when Turnstile can verify invisibly, and is disabled only if a visible challenge is actually required (unsupported/timeout/error). Applies to Elementor, WordPress Core forms, WooCommerce, Gravity Forms, Formidable, Forminator, Jetpack, Fluent Forms, and Kadence.
- Improvement: Proactive reveal for Interaction Only — if auto-verification doesn’t complete after a short period (~5s), the widget is surfaced and the challenge is triggered so users aren’t left waiting.
- Improvement: Submit-time guards — for regular forms and Elementor AJAX; when no token is present, we halt that submission, reveal the widget, scroll it into view, and start a fresh challenge.
- Improvement: Streamlined inline messaging to align with Cloudflare’s own phrasing; reduced redundant prompts to let Cloudflare’s UI lead the experience.
- Dev: Standardized render locks and defensive pre-render cleanup across remaining integrations to prevent duplicate iframes and race conditions.
1.0.8 (15 October 2025)
- Fix: Interaction Only placeholder stays collapsed (no gap/shadow) after invisible validation; it only expands when UI is truly required (via
unsupported/timeout/error callbacks or actual visible challenge).
- Fix: Prevent loader overlay, no spinner is injected for Interaction Only while the API loads; collapsed state fully hides any inner spinner and spinners never intercept clicks.
- Fix: Elementor popup - reliably renders Turnstile when popups open after page load (e.g., delayed by timer); if a widget initialized while hidden, it is reset and re-rendered on open.
- Fix: Elementor popup duplicates - de-duplicated popup/form event listeners and centralized rendering to avoid multiple widget instances; idempotent guards ensure one render per container.
- Fix: Prevent duplicate renders on Gravity Forms, Formidable, Forminator, and Jetpack by adding per-element render locks and pre-render cleanup.
- Improvement: Deferred render - widgets now render when their container is visible (Elementor + generic paths), reducing layout thrash and improving perceived load times across dynamic UIs.
- Dev: Simplified collapse logic by removing the previous mutation-based watcher and relying on Turnstile callbacks + visibility checks.
1.0.7 (14 October 2025)
- New: Added "Flexible (100% width)" widget size (Cloudflare Turnstile
data-size="flexible") for fully responsive, container-width layouts. (Thank You: @kammsw)
- New: Interaction Only UX refinement – collapses initial blank gap (no more 50+px empty space) until the user interacts or the widget needs to expand. (Thank You: @kammsw)
- Improvement: Unified size handling in JS (
flexible passes straight through; existing custom sizes still map to Cloudflare equivalents).
- Improvement: Consistent collapsed/expand logic across Elementor, Gravity Forms, Formidable, Forminator, Jetpack, Fluent Forms, Kadence, WPForms, and core render paths.
- Improvement: CSS enhancements for flexible width + reduced gap state (
.kt-ts-collapsed).
- Prep: Foundation laid for upcoming modal/delayed form robustness (MutationObserver structure ready for attribute watching & visibility checks in a future release).
- Dev: Sanitization now allows
flexible; admin settings UI updated with help text.
1.0.6 (10 September 2025)
- Improvement: Updated plugin assets (banners, icons, screenshots with clearer cropping/labels).
- Improvement: Updated readme.txt — full integrations list, screenshot captions, Support Development section, improved tags/short description, and clarified WooCommerce Blocks/Store API notes.
1.0.5 (10 September 2025)
- Fix: Expose
window.KitgenixCaptchaForCloudflareTurnstile so Cloudflare onload can reliably call renderWidgets() (prevents “no widget → no token”).
- Fix: Guarded “render once” logic to prevent duplicate widget rendering across core, WooCommerce and form plugins.
- Fix: Contact Form 7 injects once and resets cleanly on CF7 validation/error events.
- Fix: WooCommerce login/checkout placement (Classic & Blocks / Store API), including correct “Place order” positioning.
- Fix: Prevent Turnstile overlapping submit buttons for Gravity Forms and WPForms; adjusted spacing and placement heuristics.
- Fix: Admin: detect duplicate Turnstile API loader and show a dismissible notice on Settings and Plugins screens.
- Fix: “Disable Submit Until Verified” now disables buttons on render and re-enables only after a valid token callback.
- Fix: Token handling — canonical token channel, auto-create hidden
cf-turnstile-response input, getLastToken() helper, and kitgenixcaptchaforcloudflareturnstile:token-updated event.
- Fix: Sanitization & import/export hardening — preserve CIDR & wildcard IP patterns.
- Fix: Guard Elementor script enqueue to avoid PHP warnings in REST/AJAX or early hooks.
- Improvement: More reliable widget injection and cleanup on AJAX/dynamic DOM events; tighter re-render/reset behavior.
- Security: Replay protection enabled by default (TTL filterable via
kitgenix_turnstile_replay_ttl).
1.0.4 (17 August 2025)
- Fix: Position Turnstile above the WooCommerce reviews submit button. Thank You @carlbensy16.
- Fix: Prevent Turnstile from rendering inline with the submit button on Gravity Forms. Thank You @carlbensy16.
- Fix: Add spacing so Turnstile no longer overlaps the WPForms submit button. Thank You @carlbensy16.
1.0.3 (12 August 2025)
- Fix: "Save Settngs" button not working after a few attempts
1.0.2 (12 August 2025)
- Fix: Run Turnstile validation only on POST submissions for core forms (login, register, lost password, reset password, comments). Prevents the “Please complete the Turnstile challenge” message on refresh or wrong password.
- Fix: Added widget render on resetpass_form and proper validation via validate_password_reset; lost password now validates via lostpassword_post.
- Fix: Reintroduced inline centering on wp-login/wp-admin to stabilize layout across all auth screens.
- Fix: Expose the public module globally as window.KitgenixCaptchaForCloudflareTurnstile so the Cloudflare API onload callback can actually call renderWidgets() (prevents “no widget → no token” failures).
- Fix: Guarded “render once” logic so widgets don’t duplicate across hooks (core + WooCommerce + form plugins).
- Fix: Contact Form 7 integrates cleanly (single injection, resets on CF7 error events).
- Fix: WooCommerce login handles both modern woocommerce_process_login_errors and legacy woocommerce_login_errors.
- Fix: Duplicate Turnstile API loader detection with a dismissible admin notice (surfaces on our Settings page and Plugins screen).
- Improvement: When Disable Submit Button is enabled, submit buttons are now disabled immediately on render and re-enabled only after a valid token callback (previously disabled only on error/expired).
- Improvement: Added a canonical token channel. (getLastToken() helper and kitgenixcaptchaforcloudflareturnstile:token-updated event dispatched on each token change.) (Hidden cf-turnstile-response input is auto-created in forms that don’t already have it.)
- Improvement: Token freshness & UX. (Idle timer and token-age timer auto-reset widgets after ~150s (filterable via kitgenix_turnstile_freshness_ms).) (Gentle inline “Expired / Verification error — please verify again.” message displayed next to the widget.)
- Improvement: Add preconnect/dns-prefetch resource hints for https://challenges.cloudflare.com to speed up first paint.
- Improvement: Public CSS greatly reduced in scope (fewer global !importants), small min-height to prevent CLS, better RTL + reduced-motion support, and per-integration spacing.
- Improvement: Admin CSS fully scoped to the settings wrapper, compact modern fields, focus-visible styles, and reduced-motion fallback.
- Improvement: “Test widget” is rendered only via a tight inline onload callback (prevents double-render / undefined globals).
- Improvement: Site Health test (“Cloudflare Turnstile readiness”) reporting keys presence, duplicate loader detection, last verification snapshot, and possible JS delay/defer from optimization plugins (with guidance).
- Improvement: Export / Import JSON for settings (merge/replace). Optional inclusion of Secret Key (explicitly allowed).
- Improvement: Onboarding screen with one-time activation redirect, quick start steps, and helpful links.
- Improvement: Late alignment helpers for consistent widget placement on login/admin.
- Improvement: Housekeeping—centralized render flow, lightweight MutationObserver to catch dynamically added forms, safer class/existence guards.
- Improvement: Ensure hidden input + container are present; don’t inject a container if no site key is available. (Elementor)
- Improvement: Include token in Elementor Pro AJAX payloads; re-render in popups and dynamic forms; reset widget on submit/errors.
- Improvement: Server-side validation hook support (elementor_pro/forms/validation).
- Improvement: Consistent widget + validation across checkout/login/register/lost password. (WooCommerce Classic)
- Improvement: Checkout protected via woocommerce_checkout_process and woocommerce_after_checkout_validation. (WooCommerce Classic)
- Improvement: Inject container next to the “Place order” area via render_block_woocommerce/checkout-actions-block. (WooCommerce Blocks)
- Improvement: Validate Store API POSTs early via REST auth filter; token accepted from X-Turnstile-Token header or extensions. (WooCommerce Blocks)
- Improvement: Reliable widget injection before submit, spinner cleanup, and re-render on each plugin’s AJAX/DOM events.
- Improvement: Server-side validation mapped to each plugin’s native API.
- Improvement: Preserve CIDR and wildcard IP patterns instead of stripping them; sanitize lines while keeping valid patterns.
- New: Added advanced fields - respect_proxy_headers and trusted_proxy_ips (legacy), plus new trust_proxy and trusted_proxies (current).
- New: Developer Mode (warn-only) — Turnstile failures are logged and annotated inline for admins but do not block submissions (great for staging/troubleshooting).
- New: Replay protection — caches recent Turnstile tokens (hashed) for ~10 minutes and rejects re-use. Enabled by default; duration filterable via kitgenix_turnstile_replay_ttl.
- Security: Added Cloudflare/Proxy-aware client IP handling. New Trust Cloudflare/Proxy headers + Trusted Proxy IPs/CIDRs settings. We only honor CF-Connecting-IP / X-Forwarded-For when the request comes from a trusted proxy; otherwise fall back to REMOTE_ADDR.
- Security: Whitelist supports logged-in bypass, IPs with exact/wildcard/CIDR (IPv4/IPv6), and UA wildcards; decision cached per request and filterable via kitgenix_turnstile_is_whitelisted.
- Security: Validator accepts token from POST, X-Turnstile-Token header, or custom filter; memoized siteverify; robust HTTP args; remote IP + URL + timeouts filterable; friendly error mapping; last verify snapshot stored for diagnostics.
1.0.1 (11 August 2025)
- Fix: Center Cloudflare Turnstile on all
wp-login.php variants (login, lost password, reset, register) and across wp-admin.
- Change: Overhauled includes/core/class-script-handler.php to use the modern Script API (async strategy on WP 6.3+, attribute helpers on 5.7–6.2) and eliminated raw output.
- Dev: Public/admin assets now use filemtime() for cache-busting.
- Dev: Added filter
kitgenix_captcha_for_cloudflare_turnstile_script_url for advanced control.
- Docs: Expanded readme and updated links.
1.0.0 (11 August 2025)
- New: Initial release
- New: WordPress Login Integration
- New: WordPress Registration Integration
- New: WordPress Lost Password Integration
- New: WordPress Comment Integration
- New: WooCommerce Checkout Integration
- New: WooCommerce Login Integration
- New: WooCommerce Registration Integration
- New: WooCommerce Lost Password Integration
- New: Elementor Forms Integration
- New: WPForms Integration
- New: Kandence Forms Integration
- New: Jetpack Forms Integration
- New: Gravity Forms Integration
- New: Forminator Forms Integration
- New: Formidable Forms Integration
- New: Fluent Forms Integration
- New: Contact Form 7 Integration
- New: Conditional Script Loading for Performance
- New: Widget Size, Theme, and Appearance Options
- New: Defer Scripts and Disable-Submit Logic
- New: Whitelist by IP, User Agent, or Logged-in Users
- New: Custom Error and Fallback Messages
- New: Modern Admin UI with Onboarding Wizard
- New: Optional Plugin Badge
- New: Multisite Support
- New: Works With Elementor Element Cache
- New: GDPR-friendly, No Cookies or Tracking
- New: Optimized for Caching, AJAX, and Dynamic Forms
- New: No Impact on Core Web Vitals
- New: Site Key & Secret Key Management
- New: Per-Form and Per-Integration Enable/Disable
- New: Language Selection for Widget
- New: Customizable Widget Appearance
- New: Server-Side Validation for All Supported Forms
- New: CSRF Protection (Nonce Fields)
- New: Error Handling and User Feedback
- New: Support for AJAX and Dynamic Form Rendering
- New: Admin Notices and Settings Errors
- New: Plugin Translations/Localization