Arcjet rate limiting allows you to define rules which limit the number of
requests a client can make over a period of time.
Configuration options
Each rate limit is configured on an exact path with a set of client
characteristics and algorithm specific options.
Fixed window rate limit options
Tracks the number of requests made by a client over a fixed time window. Options
are explained in the Configuration
documentation. See the fixed window algorithm
description for more details about how
the algorithm works.
Fixed window example
Sliding window rate limit options
Tracks the number of requests made by a client over a sliding window so that the
window moves with time. Options are explained in the
Configuration documentation. See the sliding
window algorithm description for more
details about how the algorithm works.
Sliding window example
Token bucket rate limit options
Based on a bucket filled with a specific number of tokens. Each request
withdraws a token from the bucket and the bucket is refilled at a fixed rate.
Once the bucket is empty, the client is blocked until the bucket refills.
Options are explained in the Configuration
documentation. See the token bucket algorithm
description for more details about how
the algorithm works.
Token bucket example
See the token bucket example for how to specify the
number of tokens to request.
Identifying users
Rate limit rules use characteristics to identify the client and apply the
limit across requests. The default is to use the client’s IP address. However,
you can specify other
characteristics such as a user
ID or other metadata from your application.
In this example we define a rate limit rule that applies to a specific user ID.
The custom characteristic is userId with the value passed as a prop on the
protect function. You can use any string for the characteristic name and any
string, number or boolean for the value.
To identify users with different characteristics e.g. IP address for anonymous
users and a user ID for logged in users, you can create a custom fingerprint.
See the example in the custom characteristics
section.
Rules
The arcjet client is configured with one or more rules which take one or many
of the above options.
Example - single rate limit
Set a single rate limit rule on the /api/arcjet API route that applies a 60
request limit per hour per IP address (the default if no characteristics are
specified).
Example - dry run mode for new rules
Rate limits can be combined in the arcjet client which allows you to test new
configurations in dry run mode first before enabling them in live mode. You can
inspect the results of each rule by logging them or using the Arcjet
Dashboard.
Per route vs hooks
Rate limit rules can be configured in two ways:
Per route: The rule is defined in the route handler itself. This allows
you to configure the rule alongside the code it is protecting which is useful
if you want to use the decision to add context to your own code. However, it
means rules are not located in a single place.
Hooks: The rule is defined as a hook. This allows you to
configure rules in a single place or apply them globally to all routes, but
it means the rules are not located alongside the code they are protecting.
Per route
If you define your rate limit within an API route Arcjet assumes that the limit
applies only to that route. If you define your rate limit in hooks, you should
use event.url.pathname.startsWith.
Rate limit only on /api/*
Rate limit on all routes
Avoiding double protection with hooks
If you use Arcjet in hooks and individual routes, you need to be careful
that Arcjet is not running multiple times per request. This can be avoided by
excluding the individual routes before running Arcjet in the hook.
For example, if you already have a shield rule defined in the route
at /api, you can exclude it from the hook like this:
Decision
Arcjet provides a single protect function that is used to execute your
protection rules. This requires a RequestEvent property which is the event
context as passed to the request handler.
This function returns a Promise that resolves to an
ArcjetDecision object. This contains the following properties:
id (string) - The unique ID for the request. This can be used to look up
the request in the Arcjet dashboard. It is prefixed with req_ for decisions
involving the Arcjet cloud API. For decisions taken locally, the prefix is
lreq_.
conclusion (ArcjetConclusion) - The final conclusion based on evaluating
each of the configured rules. If you wish to accept Arcjet’s recommended
action based on the configured rules then you can use this property.
reason (ArcjetReason) - An object containing more detailed
information about the conclusion.
results (ArcjetRuleResult[]) - An array of ArcjetRuleResult objects
containing the results of each rule that was executed.
ip (ArcjetIpDetails) - An object containing Arcjet’s analysis of the
client IP address. See IP analysis in the
SDK reference for more information.
When using a token bucket rule, an additional requested prop should be passed
to the protect function. This is the number of tokens the client is requesting
to withdraw from the bucket.
Arcjet is designed to fail open so that a service issue or misconfiguration does
not block all requests. The SDK will also time out and fail open after 1000ms
when NODE_ENV or ARCJET_ENV is development and 500ms otherwise. However,
in most cases, the response time will be less than 20-30ms.
If there is an error condition, Arcjet will return an ERRORconclusion.
Arcjet runs the same in any environment, including locally and in CI. You can
use the mode set to DRY_RUN to log the results of rule execution without
blocking any requests.
We have an example test framework you can use to automatically test your rules.
Arcjet can also be triggered based using a sample of your traffic.
The example below shows how to configure a rate limit on a single API route. It
applies a limit of 60 requests per hour per IP address. If the limit is
exceeded, the client is blocked for 10 minutes before being able to make any
further requests.
Applying a rate limit by IP address is the default if no
characteristics are specified.
If you are building an AI application you may be more interested in the number
of AI tokens rather than the number of HTTP requests. Popular AI APIs such as
OpenAI are billed based on the number of tokens consumed and the number of
tokens is variable depending on the request e.g. conversation length or image
size.
The token bucket algorithm is a good fit for this use case because you can vary
the number of tokens withdrawn from the bucket with every request.
The example below configures a token bucket rate limit using the
openai-chat-tokens library to
track the number of tokens used by a gpt-3.5-turbo AI chatbot. It sets a limit
of 2,000 tokens per hour with a maximum of 5,000 tokens in the bucket. This
allows for a reasonable conversation length without consuming too many tokens.
You can test this code with a curl request from the terminal:
Rate limit by API key header
APIs are commonly protected by keys. You may wish to apply a rate limit based on
the key, regardless of which IPs the requests come from. To achieve this, you
can specify the characteristics Arcjet will use to track the limit.
The example below shows how to configure a rate limit on a single API route. It
applies a limit of 60 requests per hour per API key, where the key is provided
in a custom header called x-api-key. If the limit is exceeded, the client is
blocked for 10 minutes before being able to make any further requests.
Global rate limit
Using SvelteKit hooks allows you to set a rate limit that applies to every
route:
Response based on the path
You can also use the eventRequestEvent
object to customize the response based on the path. In this example, we’ll
return a JSON response for API requests, and a HTML response for other requests.
Rewrite or redirect
The
NextResponse
object returned to the client can also be used to rewrite or redirect the
request. For example, you might want to return a JSON response for API route
requests, but redirect all page route requests to an error page.