Cloudflare Docs
WAF
Edit this page
Give us feedback
Set theme to dark (⇧+D)

Rate limiting best practices

The following sections cover typical rate limiting configurations for common use cases. You can combine the provided example rules and adjust them to your own scenario.

The main use cases for rate limiting are the following:

​​ Enforcing granular access control

​​ Limit by user agent

A common use case is to limit the rate of requests performed by individual user agents. The following example rule allows a mobile app to perform a maximum of 100 requests in 10 minutes. You could also create a separate rule limiting the rate for desktop browsers.

SettingValue
Matching criteriaUser Agent equals MobileApp
Expressionhttp.user_agent eq "MobileApp"
Counting characteristicsIP
Rate (Requests / Period)100 requests / 10 minutes
ActionManaged Challenge

​​ Allow specific IP addresses or ASNs

Another use case when controlling access to resources is to exclude or include IP addresses or Autonomous System Numbers (ASNs) from a rate limiting rule.

The following example rule allows up to 10 requests per minute from the same IP address doing a GET request for /status, as long as the visitor’s IP address is not included in the partner_ips IP list.

SettingValue
Matching criteriaURI Path equals /status and Request Method equals GET and IP Source Address is not in list partner_ips
Expressionhttp.request.uri.path eq "/status" and http.request.method eq "GET" and not ip.src in $partner_ips
Counting characteristicsIP
Rate (Requests / Period)10 requests / 1 minute
ActionManaged Challenge

​​ Limit by referrer

Some applications receive requests originated by other sources (for example, used by advertisements linking to third-party pages). You may wish to limit the number of requests generated by individual referrer pages to manage quotas or avoid indirect DDoS attacks.

SettingValue
Matching criteriaURI Path equals /status and Request Method equals GET
Expressionhttp.request.uri.path eq "/status" and http.request.method eq "GET"
Counting characteristicsHeader (Referer) 1
Rate (Requests / Period)100 requests / 10 minutes
ActionBlock

  1. The HTTP header name uses a misspelling of “referrer”. ↩︎

This example rule requires Advanced Rate Limiting.

​​ Limit by destination host

SaaS applications or customers using Cloudflare SSL for SaaS might have thousands of hosts under the same zone, which makes creating individual rules per host impractical. To overcome this, you can create a rate limiting rule that uses the host as a counting characteristic.

The following example rule will track the rate of requests to the /login endpoint for each host:

SettingValue
Matching criteriaURI Path equals /login and Request Method equals GET
Expressionhttp.request.uri.path eq "/login" and http.request.method eq "GET"
Counting characteristicsIP and Host
Rate (Requests / Period)10 requests / 10 minutes
ActionBlock

This example rule requires Advanced Rate Limiting.

​​ Protecting against credential stuffing

A typical use case of rate limiting is to protect a login endpoint. The following example contains three different rate limiting rules with increasing penalties to manage clients making too many requests.

Rule #1

SettingValue
Matching criteriaHostname equals example.com and URI Path equals /login and Request Method equals POST
Expressionhttp.host eq "example.com" and http.request.uri.path eq "/login" and http.request.method eq "POST"
Counting characteristicsIP
Counting criteriaURI Path equals /login and Method equals POST and Response code is in (401, 403)
Counting expressionhttp.request.uri.path eq "/login" and http.request.method eq "POST" and http.response.code in {401 403}
Rate (Requests / Period)4 requests / 1 minute
ActionManaged Challenge

Rule #2

SettingValue
Matching criteriaHostname equals example.com and URI Path equals /login and Request Method equals POST
Expressionhttp.host eq "example.com" and http.request.uri.path eq "/login" and http.request.method eq "POST"
Counting characteristicsIP
Counting criteriaURI Path equals /login and Request Method equals POST and Response Status Code is in (401, 403)
Counting expressionhttp.request.uri.path eq "/login" and http.request.method eq "POST" and http.response.code in {401 403}
Rate (Requests / Period)10 requests / 10 minutes
ActionManaged Challenge

Rule #3

SettingValue
Matching criteriaHost equals example.com
Expressionhttp.host eq "example.com"
Counting characteristicsIP
Counting criteriaURI Path equals /login and Request Method equals POST and Response Status Code is in (401, 403)
Counting expressionhttp.request.uri.path eq "/login" and http.request.method eq "POST" and http.response.code in {401 403}
Rate (Requests / Period)20 requests / 1 hour
ActionBlock for 1 day

Rule #1 allows up to four requests per minute, after which a Managed Challenge is triggered. This configuration allows legitimate customers a few attempts to remember their password. If an automated actor makes several requests, that client will likely be blocked by an unsolved Managed Challenge. On the other hand, if a human gets and passes the challenge when reaching rule #1’s rate limit, rule #2 will provide the next level of protection, allowing for up to 10 requests over the next 10 minutes. For clients exceeding this second threshold, rule #3 (the most severe) will apply, blocking the client for one day.

These three rules have a counting expression separate from the rule expression (also known as mitigation expression). When you configure a separate counting expression, the matching criteria will only be used when an action is triggered. In the counting expression you can include conditions based on the HTTP response status code and HTTP response headers, therefore integrating rate limiting with your backend logic.

You can also decide to have two different expressions — a counting expression and a rule/mitigation expression — to define:

  1. The requests used to compute the rate.
  2. The requests actually acted upon.

For example, rule #3 computes the rate considering POST requests to /login that returned a 401 or 403 HTTP status code. However, when the rate limit is exceeded, Cloudflare blocks every request to the example.com host generated by the same IP. For more information on counting expressions, refer to How Cloudflare determines the request rate.

​​ Limiting the number of operations

You can use rate limiting to limit the number of operations performed by a client. The exact rule providing this protection will depend on your application. The following examples address content scraping via query string parameters or JSON body.

​​ Prevent content scraping (via query string)

In this example, clients perform operations (such as looking up prices and adding to basket) on an ecommerce website using different query string parameters. For example, a typical request sent by a client could be similar to the following:

GET https://store.com/merchant?action=lookup_price&product_id=215
Cookie: session_id=12345

Your security team might want to consider setting up a limit on the number of times a client can lookup prices to prevent bots — which may have eluded Cloudflare Bot Management — from scraping the store’s entire catalog.

Rule #1

SettingValue
Matching criteriaURI Path equals /merchant and URI Query String contains action=lookup_price
Expressionhttp.request.uri.path eq "/merchant" and http.request.uri.query contains "action=lookup_price"
Counting characteristicsIP
Rate (Requests / Period)10 requests / 2 minutes
ActionManaged Challenge

Rule #2

SettingValue
Matching criteriaURI Path equals /merchant and URI Query String contains action=lookup_price
Expressionhttp.request.uri.path eq "/merchant" and http.request.uri.query contains "action=lookup_price"
Counting characteristicsIP
Rate (Requests / Period)20 requests / 5 minute
ActionBlock

These two rate limiting rules match requests performing a selected action (look up price, in this example) and use IP as the counting characteristic. Similarly to the previous /login example, the two rules will help reduce false positives in case of persistent (but legitimate) visitors.

To limit the lookup of a specific product_id via query string parameter, you could add that specific query parameter as a counting characteristic, so that the rate is calculated based on all the requests, regardless of the client. The following example rule limits the number of lookups for each product_id to 50 requests in 10 seconds.

SettingValue
Matching criteriaURI Path equals /merchant
Expressionhttp.request.uri.path eq "/merchant"
Counting characteristicsQuery (product_id)
Rate (Requests / Period)50 requests / 10 seconds
ActionBlock

This example rule requires Advanced Rate Limiting.

You could follow the same pattern of rate limiting rules to protect applications handling reservations and bookings.

​​ Prevent content scraping (via body)

Consider an application that handles the operation and its parameters through the request body in JSON format. For example, the lookup_price operation could look like the following:

POST https://api.store.com/merchant
Cookie: session_id=12345
Body:
{
"action": "lookup_price",
"product_id": 215
}

In this scenario, you could write a rule to limit the number of actions from individual sessions:

SettingValue
Matching criteriaURI Path equals /merchant and JSON String action equals lookup_price
Expressionhttp.request.uri.path eq "/merchant" and lookup_json_string(http.request.body.raw, "action") eq "lookup_price"
Counting characteristicsCookie (session_id)
Rate (Requests / Period)10 requests / 2 minutes
ActionManaged Challenge

This example rule requires Advanced Rate Limiting and payload inspection.

You could also limit the number of lookups of each product_id regardless of the client making the requests by deploying a rule like the following:

SettingValue
Matching criteriaURI Path equals /merchant and JSON field action equals lookup_price
Expressionhttp.request.uri.path eq "/merchant" and lookup_json_string(http.request.body.raw, "action") eq "lookup_price"
Counting characteristicsJSON field (product_id)
Rate (Requests / Period)50 requests / 10 seconds
ActionBlock

This example rule requires Advanced Rate Limiting and payload inspection.

​​ Limit requests from bots

A general approach to identify traffic from bots is to rate limit requests that trigger a large volume of 403 or 404 response status codes from the origin server. This usually indicates automated activity from scraping applications.

In this situation, you could configure a rule similar to the following:

SettingValue
Matching criteriaHostname equals example.com
Expressionhttp.host eq "example.com"
Counting characteristicsIP
Increment counter whenResponse Status Code is in (401, 403)
Counting expressionhttp.response.code in {401 403}
Rate (Requests / Period)5 requests / 3 minutes
ActionManaged Challenge

To control the rate of actions performed by automated sources, consider use rate limiting rules together with Cloudflare Bot Management. With Bot Management, you can use the bot score as part of the matching criteria to apply the rule only to automated or likely automated traffic. For example, you can use a maximum score (or threshold) of 30 for likely automated traffic and 10 for automated traffic.

If your application tracks sessions using a cookie, you can use the cookie to set the rate limiting context (that is, use it as a counting characteristic). By setting the rate limiting characteristic to Cookie, the rule will group together requests from different IP addresses but belonging to the same session, which is a common scenario when dealing with a bot network performing a distributed attack.

Rule #1

SettingValue
Matching criteriaBot Score less than 30 and URI Query String contains action=delete
Expressioncf.bot_management.score lt 30 and http.request.uri.query contains "action=delete"
Counting characteristicsCookie (session_id)
Rate (Requests / Period)10 requests / 1 minute
ActionManaged Challenge

Rule #2

SettingValue
Matching criteriaBot Score less than 10 and URI Query String contains action=delete
Expressioncf.bot_management.score lt 10 and http.request.uri.query contains "action=delete"
Counting characteristicsCookie (session_id)
Rate (Requests / Period)20 requests / 5 minute
ActionBlock

These example rules require Advanced Rate Limiting and Bot Management.

If the application does not use a session cookie, you can use JA3 fingerprints to identify individual clients. A JA3 fingerprint is a unique identifier, available to customers with Bot Management, that allows Cloudflare to identify requests coming from the same client. All clients have an associated fingerprint, whether they are automated or not.

SettingValue
Matching criteriaURI Path equals /merchant and Bot Score less than 10
Expressionhttp.request.uri.path eq "/merchant" and cf.bot_management.score lt 10
Counting characteristicsJA3 Fingerprint
Rate (Requests / Period)10 requests / 1 minute
ActionManaged Challenge

This example rule requires Advanced Rate Limiting and Bot Management.

​​ Protecting REST APIs

APIs can put significant strain on the application backend because API requests can be expensive to compute or serve. These requests may also require complex operations (such as data processing and large data lookups) that, if abused, can eventually bring down an origin server.

​​ Prevent volumetric attacks

Advanced Rate Limiting can mitigate many types of volumetric attacks, like DDoS attacks, mass assignment, and data exfiltration.

A common concern is to limit POST actions. For authenticated traffic, you can use API Discovery to identify a suitable rate of request per endpoint, and then create a rate limiting rule like the following:

SettingValue
Matching criteriaURI Path equals /endpoint1 and Request Method equals POST
Expressionhttp.request.uri.path eq "/endpoint1" and http.request.method eq "POST"
Counting characteristicsHeader (x-api-key)
Rate (Requests / Period)As suggested by API Discovery or assessed by analyzing past traffic.
ActionBlock

This example rule requires Advanced Rate Limiting.

The counting characteristic can be any header, key, token, cookie, query parameter, or even JSON body field, since some APIs include a session ID or user ID as part of the JSON body. Refer to the following sections for additional information:

​​ Protect resources

GET requests can also create excessive strain on an application or have an impact on costly resources, such as bandwidth. For example, consider an application with a large amount of stored files (such as images) where clients can download a file by accessing their specific URL:

GET https://api.store.com/files/<FILE_ID>
Header: x-api-key=9375

You probably wish to limit the number of downloads to avoid abuse, but you do not want to write individual rules for each file, given the size of the data storage. In this case, you could write a rule such as the following:

SettingValue
Matching criteriaHostname equals api.example.com and Request Method equals GET
Expressionhttp.host eq "api.example.com" and http.request.method eq "GET"
Counting characteristicsPath
Rate (Requests / Period)As suggested by API Discovery or assessed by analyzing past traffic.
ActionBlock

This example rule requires Advanced Rate Limiting.

The rule defines a limit of 10 downloads in 10 minutes for every file under https://api.store.com/files/*. By using Path as the rule characteristic, you avoid having to write a new rule every time there is a new uploaded file with a different <FILE_ID>. With this rule, the rate is computed on every request, regardless of their source IP or session identifier.

You could also combine Path with the x-api-key header (or IP, if you do not have a key or token) to set the maximum number of downloads that a specific client, as identified by x-api-key, can make of a given file:

SettingValue
Matching criteriaHostname equals api.store.com and Request Method equals GET
Expressionhttp.host eq "api.example.com" and http.request.method eq "GET"
Counting characteristicsPath and Header (x-api-key)
Rate (Requests / Period)As suggested by API Discovery or assessed by analyzing past traffic.
ActionBlock

This example rule requires Advanced Rate Limiting.

​​ Protecting GraphQL APIs

One of the biggest challenges posed by applications built on GraphQL is that a single path manages all queries to the server, and every request is usually a POST operation.

The purpose of the request is usually embedded in the body, which has information on what data the client wants to fetch or mutate (according to GraphQL’s terminology for server-side data modification), along with any additional data required to carry out the action.

The following examples are based on an application that accepts reviews for movies. A GraphQL request could look like the following:

POST https://moviereviews.example.com/graphql
Cookie: session_id=12345
Body:
{
"data": {
"createReview": {
"stars": 5,
"commentary": "This is a great movie!"
}
}
}

​​ Limit the number of operations

To limit the rate of actions, you could use the following rule:

SettingValue
Matching criteriaURI Path equals /graphql and Body contains createReview
Expressionhttp.request.uri.path eq "/graphql" and http.request.body.raw contains "createReview"
Counting characteristicsCookie (session_id)
Rate (Requests / Period)5 requests / 1 hour
ActionBlock

This example rule requires Advanced Rate Limiting and payload inspection.

​​ Prevent server overload

The complexity necessary to handle a GraphQL request can vary significantly. Since the API uses a single endpoint, it is difficult to figure out the complexity of each request before it has been served.

To protect the origin server from resource exhaustion, rather than limiting the number of requests you need to limit the amount of complexity necessary to handle a single client over a period of time. Cloudflare Rate Limiting allows you to create rules that track complexity over time and block subsequent requests after reaching a complexity budget or limit.

This type of rate limiting requires that the server scores every served request according to the request’s complexity. Additionally, the server must add this score to the response as an HTTP header. Then, the rate limiting mechanism will use this information to update the budget for that specific client.

For example, the following rule defines a total complexity budget of 1,000 per hour:

SettingValue
Matching criteriaURI Path contains /graphql
Expressionhttp.request.uri.path eq "/graphql"
Counting characteristicsCookie (session_id)
Score rate (score / period)1,000 / 1 hour
Score locationResponse header (score)
ActionBlock

This example rule requires Advanced Rate Limiting and payload inspection.

When the origin server processes a request, it adds a score HTTP header to the response with a value representing how much work the origin has performed to handle it — for example, 400. In the next hour, the same client can perform requests up to an additional budget of 600. As soon as this budget is exceeded, later requests will be blocked until the timeout expires.