Your checkout is the one page on your store that anyone on the internet can submit to, over and over, for free. That is why card-testing bots live there. They arrive with a list of stolen card numbers, push a cheap product through your checkout a few hundred times an hour, and use your gateway as a free validity checker. You are left with the fallout: a wall of failed orders, a pile of authorisation fees, a plummeting success rate, and eventually an unhappy email from your payment processor.
Most stores reach for a captcha plugin and assume the problem is solved. Then they switch their checkout page to the WooCommerce Checkout block — and any captcha plugin that only hooks the classic form silently stops working. The block checkout does not submit a form. It posts JSON to the WooCommerce Store API, and a plugin that only hooks woocommerce_checkout_process never sees that request at all. Worse, that route stays open even on stores whose visible checkout page still uses the classic shortcode. A bot does not need your checkout page. It only needs the route.
Checkout Bouncer is built around that gap. It follows one simple idea, end to end:
Detect every way an order can enter this store protect the ones that can carry a token block the ones that cannot.
Checkout Bouncer ships a real checkout scanner, not a settings page with a checkbox. It opens your store, works out how your checkout is actually built, and writes you a plain-English report:
[woocommerce_checkout] shortcode, or a page builder. Elementor, Divi, WPBakery, Beaver Builder, Bricks and Oxygen are detected by name, and Checkout Bouncer looks inside the builder’s own saved layout for the checkout element.[woocommerce_checkout] shortcode itself, or a page builder layout holding the checkout element. A knowledge-base page that merely writes about the shortcode is not flagged. Duplicate detection needs a checkout page configured in WooCommerce to compare against, so it is paused — and nothing is listed or blocked as a duplicate — while that setting is empty.Every finding comes with a one-click action, and every action explains what it will break before you switch it on.
Where a token can be attached, Checkout Bouncer attaches one and scores it with reCAPTCHA v3 — the invisible kind. There is no checkbox, no traffic-light puzzle, and nothing for a genuine customer to do.
Verification happens before any gateway is asked for money, on every surface.
Some surfaces cannot carry a token — an old WooCommerce that cannot register Store API extension data, or a duplicate page nobody maintains. For those, Checkout Bouncer closes the door instead:
reCAPTCHA answers “is this a browser?”. It cannot answer “is this browser behaving like a card tester?”, because each individual request looks perfectly human. So Checkout Bouncer also ships a gateway-agnostic order-rate throttle with three rules, all keyed on a salted hash of the client IP:
It covers the classic checkout, the block checkout’s Store API and pay-for-order alike, with no gateway-specific code anywhere. Each surface is enforced on the hook WooCommerce actually lets a rejection travel through — woocommerce_checkout_order_processed for the classic form, woocommerce_store_api_checkout_update_order_from_request for the Store API, and woocommerce_before_pay_action for pay-for-order, the page bots use to retry stolen cards. That last one matters: paying for an order that already exists never creates one, so a throttle hung on order creation alone would never see it.
Some deliberate details:
There is a monitor mode that records every trip without blocking anything, so you can tune the limits against your real traffic before you arm them. The throttle works even before you have finished setting up your reCAPTCHA keys.
wp-config.php. Define CHECKOUT_BOUNCER_SITE_KEY and CHECKOUT_BOUNCER_SECRET_KEY to keep them out of the database entirely; the settings fields then render read-only.Checkout Bouncer protects the WooCommerce checkout, and only the checkout, using reCAPTCHA v3 only. It deliberately does not touch your login form, registration, comments or contact forms, and it does not offer reCAPTCHA v2, hCaptcha or Turnstile. Doing one job completely beats doing six jobs partially.
Checkout Bouncer relies on one external service: Google reCAPTCHA v3. This is inherent to the plugin’s purpose — reCAPTCHA is the thing doing the scoring — and it cannot be switched off while the plugin is verifying checkouts. Please read this section before installing, and reflect it in your own privacy policy.
Checkout Bouncer enqueues Google’s reCAPTCHA v3 API script from https://www.google.com/recaptcha/api.js. Loading that script means Google receives your visitor’s IP address and standard request headers, and reCAPTCHA collects device, browser and interaction signals in order to produce a risk score. Google may set cookies in your visitor’s browser.
By default this happens on every front-end page of your shop, not only the checkout. That is deliberate: reCAPTCHA v3 scores a visitor on how they behaved across the whole site, and Google recommends running it in the background of pages rather than only on the form you are protecting, because a single data point produces unreliable scores. If you would rather limit Google’s reach, set the loading scope to “Checkout screens only” and the script is enqueued on checkout, pay-for-order and add-payment-method views alone — at the cost of less accurate scoring. Please check which setting fits your privacy policy, and, if you serve visitors in the EU or another consent regime, your cookie-consent flow.
When an order is submitted, Checkout Bouncer sends a single server-to-server POST request to Google’s verification endpoint:
https://www.google.com/recaptcha/api/siteverify
That request contains your secret key, the reCAPTCHA token minted in the visitor’s browser, and the visitor’s IP address (as remoteip, which is how Google’s API is designed to be called). Google replies with a success flag, a score between 0.00 and 1.00, the hostname and action the token was minted for, and any error codes. No order contents, no customer name, no email address and no payment details are ever sent to Google by Checkout Bouncer.
Your secret key is only ever used server-side. It is never printed into a page, never written to a log, and never returned to the browser — the settings screen shows a fixed mask instead of the stored value, and error messages are scrubbed of it before display.
Sites in regions where www.google.com is unreachable can point the browser script at Google’s www.recaptcha.net mirror using the checkout_bouncer_api_script_url filter.
{prefix}checkout_bouncer_events) holding one row per verification, throttle trip or block: timestamp, surface, verdict, reason, score, an anonymised IP address, the order id where one exists, the payment gateway id and a short note. IPv4 addresses are stored with the final octet zeroed and IPv6 addresses with the last 80 bits zeroed. Rows older than your retention window (30 days by default) are deleted by a daily scheduled job, and you can clear the table at any time.Uninstalling the plugin removes all of it: the settings, the transients, the scheduled job and the events table.
Google’s api.js and siteverify are the only outbound requests this plugin makes. There is no analytics, no licence check, no usage tracking, no remote font and no CDN asset of any kind.