The Google Ads API enforces rate limiting by queries per second (QPS) on both customer
IDs and Google Cloud projects independently. In addition to requests per minute
(which measure the frequency of API calls), the Google Ads API also enforces limits on
operations per minute (which measure the total number of API operations across
requests). The Google Ads API uses a [token bucket](https://en.wikipedia.org/wiki/Token_bucket) algorithm to meter
requests and determine an appropriate QPS limit, so the exact limit varies
depending on the overall server load at any given time.

The purpose of imposing rate limits is to prevent one user from disrupting
service for other users by (either intentionally or unintentionally)
overwhelming the Google Ads API servers with a high volume of requests.

Requests that violate rate limits are rejected with the error:
[`RESOURCE_TEMPORARILY_EXHAUSTED`](https://developers.google.com/google-ads/api/reference/rpc/v26/QuotaErrorEnum.QuotaError#resource_temporarily_exhausted).

You can take control of your app and mitigate rate limits by both actively
reducing the number of requests and throttling QPS from the client side.

There are a number of ways to reduce the chances of exceeding the rate limit.
Becoming familiar with [Enterprise Integration Patterns](https://www.enterpriseintegrationpatterns.com/patterns/messaging/) (EIP)
concepts such as messaging, re-delivery, and throttling can help you build a
more robust client app.

The following recommended practices are ordered by complexity, with simpler
strategies at the top and more robust but sophisticated architectures after:

- [Exponential backoff](https://developers.google.com/google-ads/api/docs/productionize/rate-limits#backoff)
- [Limit concurrent tasks](https://developers.google.com/google-ads/api/docs/productionize/rate-limits#limit)
- [Batching requests](https://developers.google.com/google-ads/api/docs/productionize/rate-limits#batch)
- [Throttling and rate limiters](https://developers.google.com/google-ads/api/docs/productionize/rate-limits#throttle)
- [Queueing](https://developers.google.com/google-ads/api/docs/productionize/rate-limits#queue)

## Exponential backoff

When your application receives a
[`RESOURCE_TEMPORARILY_EXHAUSTED`](https://developers.google.com/google-ads/api/reference/rpc/v26/QuotaErrorEnum.QuotaError#resource_temporarily_exhausted) error, use an
exponential backoff policy with randomized jitter before retrying the failed
request. Exponential backoff progressively increases the wait time between
retries (for example, waiting 2 seconds, then 4 seconds, then 8 seconds, plus a
small random delay), allowing server load and quota buckets to recover while
preventing synchronized retry spikes across client instances.

## Limit concurrent tasks

One root cause of exceeding rate limits is that the client app is spawning an
excessive number of parallel tasks. While we don't limit the number of parallel
requests a client app can have, this can exceed the **requests per second**
limit at the Google Cloud project level.

Setting a reasonable upper bound for the total number of concurrent tasks that
are going to make requests (across all processes and machines), and adjusting
upward to optimize your throughput without exceeding the rate limit is
recommended.

Furthermore, you can consider throttling QPS from the client side (see
[Throttling and rate limiters](https://developers.google.com/google-ads/api/docs/productionize/rate-limits#throttle)).

## Batching requests

Consider batching multiple operations into a single request. This is most
applicable on `Mutate` calls for various services. For example, if you're
updating status for multiple instances of [`AdGroupAd`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupAd), you
can call [`MutateAdGroupAds`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupAdService/MutateAdGroupAds) once, and pass in
multiple `operations` instead of calling
[`MutateAdGroupAds`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupAdService/MutateAdGroupAds) once for each
[`AdGroupAd`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupAd). Refer to our
[batch operations guidance](https://developers.google.com/google-ads/api/docs/batch-processing/overview) for some additional
examples.

While batching requests reduces the total number of API calls and mitigates the
rate limits on **requests per minute** , it may trigger the **operations per
minute** rate limit if you perform a large number of operations against a single
account.

## Throttling and rate limiters

In addition to limiting the total number of threads in your application, you can
also implement rate limiters on the client side. This ensures all threads across
your processes, clusters, or both are governed by a specific QPS limit from the
client side.

See the [Guava RateLimiter](https://guava.dev/releases/snapshot/api/docs/com/google/common/util/concurrent/RateLimiter.html), or implement your own
[token bucket](https://en.wikipedia.org/wiki/Token_bucket) algorithm for a clustered environment. For example,
you can manage tokens in a distributed, low-latency in-memory datastore such as
Redis or Memcached, where each client acquires and consumes a token before
processing a request. If the tokens are exhausted, the client waits until the
next batch of tokens is replenished.

## Queueing

A message queue is the solution for operation load distribution, while also
controlling request and consumer rates. There are a number of message queue
options available---some open source, some proprietary---and many of
them can work with different languages.

When using message queues, you can have multiple producers pushing messages to
the queue and multiple consumers processing those messages. Throttles can be
implemented at the consumer side by limiting the number of concurrent consumers,
or by implementing rate limiters or throttlers for either the producers or
consumers.

For example, if a message consumer encounters a rate limit error, that consumer
can return the request to the queue with a standardized retry delay (using
exponential backoff) and update a shared rate-limiter feedback loop so that
all consumers automatically reduce their processing rate while recovering from
the error.