Checkout Bouncer

Notes

WooCommerce already ships a checkout limiter, and it is off

The Store API carries its own limiter, switched off out of the box. Turning it on takes one filter, and getting it right takes an accurate client address.

4 min read

WooCommerce already ships checkout rate limiting. And it sits in core, needs no extra plugin, and stays switched off on a default install. So the useful question is not which tool to buy. It is whether you have turned on the one you already own.

This matters because volume is the whole point of an automated attack. Because a script that can try a card every second is a different problem from one that manages a card every four minutes, a limit does not have to be clever to change the arithmetic.

What core actually gives you

The WooCommerce Store API, which is the route the Checkout block posts to, carries its own limiter. So checkout rate limiting already sits in your install, waiting for a filter. Although the developer documentation states the position without ambiguity, it is easy to miss: "Rate Limiting is available for Store API endpoints. This is optional and disabled by default."

Once you enable it, the defaults are 25 requests in 10 seconds. Only writes are covered, because, as the docs put it, "Only POST requests are rate limited." So a visitor browsing your shop is unaffected. Someone hammering an endpoint is not.

Further, the checkout gets tighter treatment than the rest. WooCommerce allows the checkout endpoint to be configured separately, down to a maximum of three requests per sixty seconds.

Turning checkout rate limiting on

So one filter controls the whole thing. Add it in a site-specific plugin rather than your theme, and it will survive the next theme change.

add_filter( 'woocommerce_store_api_rate_limit_options', function() {
	return [
		'enabled'       => true,
		'proxy_support' => false,
		'limit'         => 25,
		'seconds'       => 10,
	];
} );

Four keys, and each one earns its place. enabled is the switch. Then limit and seconds define the window. And proxy_support decides how a visitor gets identified, which is the key most likely to catch you out.

Who counts as one visitor

First, a limiter has to decide whose requests it counts. WooCommerce tracks "by either USER ID (logged in), IP ADDRESS (unauthenticated requests) or filter defined logic to fingerprint and group requests."

For guests, that means the IP address. So the accuracy of your checkout rate limiting rests entirely on the accuracy of that address. Behind a CDN or a load balancer, though, the address your server sees may belong to the proxy rather than the shopper. Every guest then looks like the same visitor, and a limit meant for one person applies to all of them at once.

That is what proxy_support exists for, and it is also why the IP address on a WooCommerce order is worth checking before you trust anything counting by it. Get the address wrong and you either limit nobody or limit everybody.

What it will not stop

Still, checkout rate limiting is a blunt instrument, and it is worth being honest about the hole it leaves.

It counts requests. It does not judge them. So a patient script that stays under your threshold passes through untouched, while distributed traffic arriving from many addresses never trips a per-address counter at all.

Second, it covers the Store API. Because the classic checkout submits through a different endpoint entirely, a store running the shortcode checkout gains nothing here. Nor does a limit help with the pay for order page, which is a normal page load rather than a Store API call.

And a limit set too tight has a cost of its own. Even three attempts a minute sounds generous until a customer with a fumbled card number and a slow phone uses all three.

A sensible way to start

So begin with the defaults rather than the tightest setting you can imagine.

  1. First, enable the filter with 25 requests in 10 seconds and change nothing else.
  2. Then place a real test order yourself, including one deliberate mistake, so you know an honest customer clears the limit.
  3. Next, check whether your host or CDN already limits at the edge, because two limiters stacked on each other are hard to reason about later.
  4. Only after that, consider a tighter figure for the checkout endpoint specifically.

Further detail lives in the WooCommerce Store API rate limiting documentation, including the response headers the limiter sends back.

Where Checkout Bouncer fits

Checkout Bouncer answers a different question from a limiter. Checkout rate limiting asks how often this visitor has knocked. Meanwhile Checkout Bouncer asks how the visitor behaves, by scoring the checkout with Google reCAPTCHA v3, so a first request from a script is still a first request from a script. The plugin is free, GPL and listed on WordPress.org.

Its limits are worth naming. The plugin guards the WooCommerce checkout only, never login, registration, comments or contact forms. Nor is it a firewall or a malware scanner. And it uses reCAPTCHA v3, never v2 or another provider.

So the two work best together, because they fail in different directions. If you want to know which checkout routes on your store currently answer, the free scanner takes about two minutes.

See which doors into your checkout are standing open