Skip to main content

Rate Limiting for Store API endpoints

Rate Limiting is available for Store API endpoints. This is optional and disabled by default. It can be enabled by following these instructions.

The main purpose prevent abuse on endpoints from excessive calls and performance degradation on the machine running the store.

Rate limit tracking is controlled by either USER ID (logged in), IP ADDRESS (unauthenticated requests) or filter defined logic to fingerprint and group requests.

It also offers standard support for running behind a proxy, load balancer, etc. This also optional and disabled by default.

UI Control

Currently, this feature is only controlled via the woocommerce_store_api_rate_limit_options filter. To control it via a UI, you can use the following community plugin: Rate Limiting UI for WooCommerce.

Checkout rate limiting

You can enable rate limiting for Checkout place order and POST /checkout endpoint only via the UI by going to WooCommerce -> Settings -> Advanced -> Features and enabling "Rate limiting Checkout block and Store API".

When enabled via the UI, the rate limiting will only be applied to the POST /checkout and Place Order flow for Checkout block. The limit will be a maximum of 3 requests per 60 seconds.

Limit information

A default maximum of 25 requests can be made within a 10-second time frame. These can be changed through an options filter.

Methods restricted by Rate Limiting

POST, PUT, PATCH, and DELETE

Rate Limiting options filter

A filter is available for setting options for rate limiting:

add_filter( 'woocommerce_store_api_rate_limit_options', function() {
return [
'enabled' => false, // enables/disables Rate Limiting. Default: false
'proxy_support' => false, // enables/disables Proxy support. Default: false
'limit' => 25, // limit of request per timeframe. Default: 25
'seconds' => 10, // timeframe in seconds. Default: 10
];
} );

Proxy standard support

If the Store is running behind a proxy, load balancer, cache service, CDNs, etc. keying limits by IP is supported through standard IP forwarding headers, namely:

  • X_REAL_IP|CLIENT_IP Custom popular implementations that simplify obtaining the origin IP for the request
  • X_FORWARDED_FOR De-facto standard header for identifying the originating IP, Documentation
  • X_FORWARDED Documentation, RFC 7239

This is disabled by default.

Enable Rate Limit by request custom fingerprinting

For more advanced use cases, you can enable rate limiting by custom fingerprinting. This allows for a custom implementation to group requests without relying on logged-in User ID or IP Address.

Custom basic example for grouping requests by User-Agent and Accept-Language combination

add_filter( 'woocommerce_store_api_rate_limit_id', function() {
$accept_language = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : '';

return md5( wc_get_user_agent() . $accept_language );
} );

Limit usage information observability

Current limit information can be observed via custom response headers:

  • RateLimit-Limit Maximum requests per time frame.
  • RateLimit-Remaining Requests available during current time frame.
  • RateLimit-Reset Unix timestamp of next time frame reset.
  • RateLimit-Retry-After Seconds until requests are unblocked again. Only shown when the limit is reached.

Response headers example

RateLimit-Limit: 5
RateLimit-Remaining: 0
RateLimit-Reset: 1654880642
RateLimit-Retry-After: 28

Tracking limit abuses

This uses a modified wc_rate_limit table with an additional remaining column for tracking the request count in any given request window. A custom action woocommerce_store_api_rate_limit_exceeded was implemented for extendability in tracking such abuses.

Custom tracking usage example

add_action(
'woocommerce_store_api_rate_limit_exceeded',
function ( $offending_ip, $action_id ) { /* Custom tracking implementation */ }
);