Get Help

Rate Limiting for Stellar Horizon

As a user of Stellar Horizon, you may run into rate limits from time to time. Stellar Horizon rate limits are intelligently designed to allow for burstable access. They do not naively enforce a rate limit via a raw quota mechanism or an average distribution over unit time.

Stellar Horizon includes uea default rate limit of 3600 req/hour for dedicated node customers. We are of course happy to raise this limit if you encounter limiting as outlined in this document. Contact Support for help.

For our shared node customers, the rate limit is 2000 req/hour. This limit is the current Blockdaemon policy and cannot be adjusted per user. Additionally, there is a rate limit set in nginx that enforces a hard cap of 20 requests in any second.

It may be helpful to understand that Horizon’s rate limiting algorithm is the GCRA rate limit – while this may feel like unnecessarily technical details, it will aid in understanding if you want to understand the limit more completely.

Maintain Visibility with Headers

You can maintain visibility on your available quota for the current time period. If you adjust your request velocity based on the returned header values, you can ensure you never exhaust your rate limit.

Blockdaemon passes through headers without alteration as defined in the official Stellar documentation on rate limiting.

  • X-RateLimit-Limit – The Stellar documentation refers to this as “The maximum number of requests that the current client can make in one hour.”, but observation indicates this is the limit of calls in a given “window”. We can easily observe this in practice by paying attention to the header return values.
  • X-RateLimit-Remaining – The Stellar documentation refers to this as “The number of remaining requests for the current window.” This is accurate to observed use. This is the most important number for you to watch, as it indicates how many calls you may make until you encounter a rate limit.
  • X-RateLimit-Reset – The Stellar documentation refers to this as “Seconds until a new window starts.” This is also accurate to observed use. If you wanted to wait to have a full call quota, you would want to delay by the window this indicates. However, the quota is dynamic and this is more easily understood as a cooldown rather than a hard lockout.

If you exceed your rate limit — X-RateLimit-Remaining reaches 0 — you will receive an HTTP 429 response code and the additional header retry-after which will also specify a value in seconds that you should delay further requests.

Understanding Limits in Practice

The rate limit in practice effectively acts like a leaky bucket that slowly drains when water isn’t being added to it. Every request you make adds water to the bucket. If you add water faster than the bucket drains, you will overfill the bucket — you will hit your rate limit.

If you make 50 requests and then wait three seconds before your next request, you will see the X-RateLimit-Remaining counter begin increasing and the X-RateLimit-Reset decrease. Therefore if you use enough requests in a time period to reach 0 remaining, you don’t need to wait the full duration until a Reset.

This is easily understood from a terminal window. 

In a terminal window, enter the following command:


Where MY_BLOCKDAEMON_NODE_ADDRESS is the node address given to you on the node card, and MY_AUTH_TOKEN is everything after “auth=” in your node address.

You will get a response that looks something like this:

server: nginx/1.18.0
date: Thu, 20 Aug 2020 20:53:01 GMT
cache-control: no-cache, no-store, max-age=0
vary: Origin
x-ratelimit-limit: 101
x-ratelimit-remaining: 100
x-ratelimit-reset: 2
access-control-allow-origin: *

If you run the command several times in rapid succession, you will see the remaining count decrease and the reset period increase, as below:

server: nginx/1.18.0
date: Thu, 20 Aug 2020 20:18:31 GMT
cache-control: no-cache, no-store, max-age=0
vary: Origin
x-ratelimit-limit: 101
x-ratelimit-remaining: 99
x-ratelimit-reset: 4
access-control-allow-origin: *
server: nginx/1.18.0
date: Thu, 20 Aug 2020 20:18:31 GMT
cache-control: no-cache, no-store, max-age=0
vary: Origin
x-ratelimit-limit: 101
x-ratelimit-remaining: 98
x-ratelimit-reset: 5
access-control-allow-origin: *

Similarly, if you wait a few seconds, you will see the reset period refresh to 0 and you will have a full quota again.

If you want to understand it interactively with a shell script, you can run this on his local machine:

while [ $counter -le 150 ]
curl -I <a class="c-link" href="https://my_blockdaemon_node_address/fee_stats?auth=MY_AUTH_TOKEN" target="_blank" rel="noopener noreferrer">https://MY_BLOCKDAEMON_NODE_ADDRESS/fee_stats?auth=MY_AUTH_TOKEN</a>


Stellar Horizon rate limits are dynamic and are not a simple quota or a naive division of available calls across the time period. By reading and implementing response headers into your code, you can ensure that you don’t burst over the available dynamic limit in a period of time.