{"id":325675,"date":"2026-06-19T07:12:52","date_gmt":"2026-06-19T07:12:52","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/cap-captcha\/"},"modified":"2026-06-26T09:19:52","modified_gmt":"2026-06-26T09:19:52","slug":"privacy-captcha-for-cap","status":"publish","type":"plugin","link":"https:\/\/ast.wordpress.org\/plugins\/privacy-captcha-for-cap\/","author":6326268,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.2.0","stable_tag":"1.2.0","tested":"7.0","requires":"6.5","requires_php":"8.3","requires_plugins":null,"header_name":"Privacy CAPTCHA for Cap","header_author":"Zirkel Design","header_description":"Privacy-friendly spam protection for WordPress comments, login, registration, WooCommerce checkout, and Gravity Forms, powered by your own Cap (trycap.dev) server.","assets_banners_color":"","last_updated":"2026-06-26 09:19:52","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/zirkeldesign\/privacy-captcha-for-cap","header_author_uri":"https:\/\/zirkel.design","rating":0,"author_block_rating":0,"active_installs":0,"downloads":96,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"d.sturm","date":"2026-06-19 07:12:22"},"1.1.0":{"tag":"1.1.0","author":"d.sturm","date":"2026-06-26 09:18:06"},"1.2.0":{"tag":"1.2.0","author":"d.sturm","date":"2026-06-26 09:19:52"}},"upgrade_notice":[],"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","1.1.0","1.2.0"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[262246],"plugin_tags":[362,107,34331,599,286],"plugin_category":[44,45,54],"plugin_contributors":[256580],"plugin_business_model":[],"class_list":["post-325675","plugin","type-plugin","status-publish","hentry","plugin_section-dashboard-widgets","plugin_tags-captcha","plugin_tags-comments","plugin_tags-proof-of-work","plugin_tags-spam","plugin_tags-woocommerce","plugin_category-discussion-and-community","plugin_category-ecommerce","plugin_category-security-and-spam-protection","plugin_contributors-dsturm-1","plugin_committers-dsturm"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/privacy-captcha-for-cap.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p><strong>Privacy CAPTCHA for Cap<\/strong> integrates <a href=\"https:\/\/trycap.dev\/\">Cap<\/a> \u2014 a self-hosted, privacy-friendly, proof-of-work CAPTCHA \u2014 into the parts of WordPress that attract the most spam: comments, login, user registration, WooCommerce checkout, and Gravity Forms.<\/p>\n\n<p>Unlike third-party CAPTCHAs (reCAPTCHA, hCaptcha, Turnstile), Cap runs the proof-of-work entirely in the visitor's browser and verifies the token against your own Cap server. No data leaves your infrastructure.<\/p>\n\n<blockquote>\n  <p><strong>Unofficial integration.<\/strong> Cap is an independent open-source project by tiagozip (https:\/\/trycap.dev\/, Apache-2.0). This plugin is a third-party integration and is <strong>not affiliated with, endorsed by, or sponsored by<\/strong> the Cap project. \"Cap\" refers to that project solely to describe what this plugin works with.<\/p>\n<\/blockquote>\n\n<h4>Features<\/h4>\n\n<ul>\n<li><strong>First-class Gravity Forms field<\/strong> \u2014 drag a \"Privacy CAPTCHA for Cap\" into any form from the Advanced Fields group. Per-field display-mode override.<\/li>\n<li><strong>Contact Form 7<\/strong> integration \u2014 protects every CF7 form automatically.<\/li>\n<li><strong>WordPress comments, wp-login, registration<\/strong> integrations \u2014 togglable from one settings page.<\/li>\n<li><strong>WooCommerce<\/strong> integration \u2014 checkout plus the My Account login, registration, and lost-password forms, each its own toggle. Only loads when WooCommerce is active.<\/li>\n<li><strong>Dashboard widget<\/strong> \u2014 at-a-glance Cap server stats (challenges, verified, failed, hourly chart) right on the WordPress dashboard.<\/li>\n<li><strong>Granular per-surface toggles<\/strong> and <strong>developer filters<\/strong> (<code>cap_captcha_protect<\/code>) to enable\/disable protection on any form, even conditionally.<\/li>\n<li><strong>Three display modes<\/strong>: inline widget, floating popover, or fully programmatic (auto-solves silently).<\/li>\n<li><strong>Fully self-hosted assets<\/strong> \u2014 the proof-of-work WebAssembly module, the cap-widget script, and the pako decompression library all ship inside the plugin and are served locally, so no jsdelivr or other third-party CDN is contacted at runtime. DSGVO\/GDPR-clean by default.<\/li>\n<li><strong>WP 6.5+ native script-module API<\/strong> for proper ES-module loading.<\/li>\n<li><strong>i18n-ready<\/strong> with German translations bundled.<\/li>\n<li><strong>Theme-friendly CSS<\/strong> built on Gravity Forms Orbital tokens with <code>--cap-captcha-*<\/code> overrides.<\/li>\n<li><strong>Filter hooks<\/strong> for protection gating, asset URLs, button classes, i18n strings, and the display mode.<\/li>\n<\/ul>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>WordPress 6.5 or later<\/li>\n<li>PHP 8.3 or later<\/li>\n<li>A reachable Cap server (see https:\/\/trycap.dev\/)<\/li>\n<li>Gravity Forms 2.5+ (only if you enable the Gravity Forms integration)<\/li>\n<li>WooCommerce (only if you enable the WooCommerce integration)<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>privacy-captcha-for-cap<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin via the <em>Plugins<\/em> menu in WordPress.<\/li>\n<li>Go to <strong>Settings \u2192 Privacy CAPTCHA for Cap<\/strong> and enter your Cap endpoint URL, site key, and secret key.<\/li>\n<li>Tick the integrations you want to enable.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20this%20an%20official%20cap%20plugin%3F\"><h3>Is this an official Cap plugin?<\/h3><\/dt>\n<dd><p>No. Cap is an independent open-source project by tiagozip (https:\/\/trycap.dev\/), licensed under Apache-2.0. This plugin is an unofficial third-party integration and is not affiliated with or endorsed by the Cap project. We reference the \"Cap\" name only to indicate which software this plugin works with.<\/p><\/dd>\n<dt id=\"where%20do%20i%20get%20a%20cap%20endpoint%2C%20site%20key%20and%20secret%3F\"><h3>Where do I get a Cap endpoint, site key and secret?<\/h3><\/dt>\n<dd><p>You provision those in your self-hosted Cap server. See the Cap documentation at https:\/\/trycap.dev\/.<\/p><\/dd>\n<dt id=\"where%20is%20the%20wasm%20loaded%20from%3F\"><h3>Where is the WASM loaded from?<\/h3><\/dt>\n<dd><p>By default: from the copy bundled inside this plugin at <code>wp-content\/plugins\/privacy-captcha-for-cap\/assets\/wasm\/cap_wasm_bg.wasm<\/code>. You can optionally switch to your own Cap server's <code>\/assets\/cap_wasm_bg.wasm<\/code> endpoint under <strong>Settings \u2192 Privacy CAPTCHA for Cap \u2192 Privacy<\/strong>. Either way the file is served from your own infrastructure \u2014 no third-party CDN is contacted.<\/p><\/dd>\n<dt id=\"why%20is%20a%20%60.wasm%60%20file%20bundled%2C%20and%20where%20does%20it%20come%20from%3F\"><h3>Why is a `.wasm` file bundled, and where does it come from?<\/h3><\/dt>\n<dd><p>The bundled <code>assets\/wasm\/cap_wasm_bg.wasm<\/code> is the WebAssembly module the Cap widget uses to run the proof-of-work challenge in the visitor's browser. Bundling it locally is the privacy-friendly default: it means no third-party CDN (jsdelivr) is contacted at page load, so visitor IPs are never shared (DSGVO\/GDPR-clean).<\/p>\n\n<p>It is the unmodified upstream file from the <code>@cap.js\/wasm<\/code> npm package (Apache-2.0), part of the open-source Cap project. The plugin does not alter it. Its source and build live in the Cap repository at https:\/\/github.com\/tiagozip\/cap, and the vendoring step is reproducible via <code>scripts\/build-assets.mjs<\/code> (<code>bun run build<\/code>), which copies the file verbatim and <code>bun run build:check<\/code> verifies it matches upstream.<\/p><\/dd>\n<dt id=\"can%20i%20store%20the%20secret%20outside%20the%20database%3F\"><h3>Can I store the secret outside the database?<\/h3><\/dt>\n<dd><p>Yes. Define <code>CAP_CAPTCHA_SECRET_KEY<\/code> in <code>wp-config.php<\/code> and the plugin will use it instead of the value saved in <code>wp_options<\/code>.<\/p><\/dd>\n<dt id=\"what%20is%20%22fail-open%22%20mode%3F\"><h3>What is \"fail-open\" mode?<\/h3><\/dt>\n<dd><p>When enabled, the plugin lets submissions through if the Cap server is unreachable. Off by default \u2014 only turn it on if temporary outages must not block legitimate users (logins, checkouts). It applies only when Cap genuinely can't be reached; a CAPTCHA the server actively rejects is always blocked. You can set fail-open <strong>per form<\/strong> (e.g. open for logins, closed for contact forms) under the global toggle, and any submission accepted this way is flagged for review (Gravity Forms entries, WooCommerce orders, comments, and new users get a <code>cap_captcha_fail_open<\/code> marker; orders also get a note).<\/p><\/dd>\n<dt id=\"does%20the%20bundled%20%60cap-widget%60%20script%20make%20any%20external%20requests%3F\"><h3>Does the bundled `cap-widget` script make any external requests?<\/h3><\/dt>\n<dd><p>No third-party CDN requests. All widget assets are bundled and served from this plugin, including the <code>pako<\/code> decompression library (<code>assets\/js\/vendor\/pako_inflate.min.js<\/code>), which older browsers without the native <code>DecompressionStream<\/code> API load locally instead of from jsdelivr. The only network requests the widget makes are to your own Cap endpoint to fetch and verify challenges.<\/p><\/dd>\n<dt id=\"can%20i%20turn%20protection%20on%20or%20off%20per%20form%20in%20code%3F\"><h3>Can I turn protection on or off per form in code?<\/h3><\/dt>\n<dd><p>Yes. Every surface passes through the <code>cap_captcha_protect<\/code> filter \u2014 <code>($enabled, $context)<\/code> returning a boolean \u2014 before the widget renders and before a submission is verified. For example, to skip the CAPTCHA for logged-in users everywhere: <code>add_filter('cap_captcha_protect', fn($on, $ctx) =&gt; is_user_logged_in() ? false : $on, 10, 2);<\/code>. There is also a per-surface filter, e.g. <code>cap_captcha_protect_woocommerce_login<\/code>. Context ids: gravity_forms, contact_form_7, comments, login, registration, woocommerce_checkout, woocommerce_login, woocommerce_registration, woocommerce_lost_password.<\/p><\/dd>\n<dt id=\"can%20i%20keep%20the%20captcha%20off%20a%20specific%20contact%20form%207%20or%20gravity%20forms%20form%3F\"><h3>Can I keep the CAPTCHA off a specific Contact Form 7 or Gravity Forms form?<\/h3><\/dt>\n<dd><p>Yes \u2014 useful for legally required or accessibility-sensitive forms. For <strong>Contact Form 7<\/strong>, set the mode to <em>Manual<\/em> (Settings \u2192 Form placement) and add the <code>[cap_captcha]<\/code> tag only to the forms you want protected; or, in <em>Automatic<\/em> mode, add <code>cap_captcha: off<\/code> to a form's Additional Settings to skip just that one. For <strong>Gravity Forms<\/strong>, each form has a <em>Privacy CAPTCHA<\/em> setting (Default \/ Always \/ Never) so you can exclude individual forms even when \"protect all\" is on.<\/p><\/dd>\n<dt id=\"are%20there%20developer%20hooks%20%2F%20filters%3F\"><h3>Are there developer hooks \/ filters?<\/h3><\/dt>\n<dd><p>Yes. The main ones:<\/p>\n\n<ul>\n<li><code>cap_captcha_protect<\/code> \u2014 master gate for every surface: <code>($enabled, $context)<\/code> returning a boolean. Runs before the widget renders and before a submission is verified.<\/li>\n<li><code>cap_captcha_protect_{context}<\/code> \u2014 per-surface gate, e.g. <code>cap_captcha_protect_woocommerce_login<\/code>.<\/li>\n<li><code>cap_captcha_fail_open<\/code> \u2014 <code>($open, $context)<\/code> the resolved fail-open decision for a surface; plus a <code>cap_captcha_fail_open_pass<\/code> action when a submission is accepted via fail-open.<\/li>\n<li><code>cap_captcha_widget_src<\/code>, <code>cap_captcha_floating_src<\/code>, <code>cap_captcha_programmatic_src<\/code>, <code>cap_captcha_style_src<\/code> \u2014 override the script\/style URLs (return <code>''<\/code> for the style to disable bundled CSS).<\/li>\n<li><code>cap_captcha_wasm_url<\/code>, <code>cap_captcha_pako_url<\/code> \u2014 override the WASM \/ pako URLs (default to the bundled copies).<\/li>\n<li><code>cap_captcha_i18n<\/code> \u2014 override the widget's <code>data-cap-i18n-*<\/code> strings.<\/li>\n<li><code>cap_captcha_floating_button_classes<\/code>, <code>cap_captcha_floating_position<\/code>, <code>cap_captcha_floating_autosubmit_src<\/code> \u2014 floating-mode tweaks.<\/li>\n<li><code>cap_captcha_display_mode<\/code> \u2014 override the resolved display mode for a specific Gravity Forms field.<\/li>\n<\/ul>\n\n<p>The full, annotated list with examples is in README.md.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Added: per-form fail-open \u2014 let logins through during a Cap outage while still requiring a valid proof on contact forms (or any mix). Set it per surface, or keep the global default.<\/li>\n<li>Added: submissions accepted during a Cap outage are now flagged for review (Gravity Forms entries, WooCommerce orders, comments, and new users get a \"fail-open\" marker; orders also get a note).<\/li>\n<li>Improved: a CAPTCHA that the Cap server actively rejects is always blocked \u2014 fail-open only applies when Cap genuinely can't be reached.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Added: Contact Form 7 integration with placement control \u2014 automatic on all forms, or manual via the [cap_captcha] tag (so you can keep the CAPTCHA off legally required or accessibility-sensitive forms).<\/li>\n<li>Added: Gravity Forms automatic protection \u2014 global \"protect all\" plus a per-form Default \/ Always \/ Never override, alongside the existing field.<\/li>\n<li>Added: WooCommerce My Account login, registration, and lost-password forms (each its own toggle, alongside checkout).<\/li>\n<li>Added: dashboard widget showing your Cap server stats at a glance.<\/li>\n<li>Added: granular per-surface toggles and a <code>cap_captcha_protect<\/code> developer filter to control protection on any form, even conditionally.<\/li>\n<li>Fixed: the Login integration no longer interferes with WooCommerce My Account logins.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Gravity Forms field (inline \/ floating \/ programmatic display).<\/li>\n<li>Comments, login, registration, WooCommerce integrations.<\/li>\n<li>Fully self-hosted assets \u2014 WASM module, cap-widget script, and pako library all bundled and served locally; no third-party CDN is contacted at runtime. DSGVO-clean by default.<\/li>\n<li>WP 6.5 native script-module loading.<\/li>\n<li>Top-level Settings \u2192 Privacy CAPTCHA for Cap page with integration toggles, WASM source choice (this plugin or your own Cap server), fail-open switch.<\/li>\n<li>German translations.<\/li>\n<\/ul>","raw_excerpt":"Privacy-friendly spam protection for comments, login, registration, WooCommerce, and Gravity Forms, powered by your own Cap server.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/325675","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=325675"}],"author":[{"embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/dsturm"}],"wp:attachment":[{"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=325675"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=325675"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=325675"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=325675"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=325675"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=325675"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}