Guide

Discord API rate limits, explained

Most bots never think about rate limits because the library handles them. Then a bot does something in a loop, or shares an IP address with one that does, and suddenly nothing works for an hour.

7 minute read

The short version

  • Each kind of request has its own limit, shared per route and often per channel or server.
  • There is also a global cap of about 50 requests per second for a bot.
  • Go over and Discord answers 429 Too Many Requests with how long to wait.
  • Rack up too many failed requests (401, 403 and 429 responses) from one IP address, 10,000 in ten minutes, and Discord's Cloudflare blocks that address for a while. Everything stops.

discord.py, and most other libraries, read the headers and wait for you. The trouble comes from the patterns that make the library wait constantly, and from the invalid-request ban, which no library can undo once it happens.

Per-route limits

Every response includes headers describing the bucket that request used:

X-RateLimit-Limit: 5
X-RateLimit-Remaining: 0
X-RateLimit-Reset-After: 1.2
X-RateLimit-Bucket: abcd1234

Buckets are shared by routes that Discord groups together, and usually scoped to a channel, a server or a webhook. So sending messages to two different channels uses two buckets; sending ten messages to one channel in a second uses one bucket, and waits.

Discord does not publish exact numbers for most routes and changes them when it likes. Code against the headers, never against numbers you found online.

In discord.py you can see it happening in the logs:

We are being rate limited. Retrying in 1.23 seconds.

A few of those is normal. A steady stream means something in your code is doing too much.

The ones people hit

Editing a message in a loop

A progress bar or a live clock that edits the same message every second will spend most of its time waiting. Edit every five or ten seconds, or only when the value actually changes.

Renaming channels

"Member count" or "server time" channels that rename themselves are limited very tightly: in practice about two renames every ten minutes per channel. Updating one every minute just queues requests that pile up. Once every ten minutes is the most you should try.

Mass DMs and mass role changes

Adding a role to every member, or messaging every member, is thousands of requests. It works if you let the library pace it, and takes a long time. It also looks like spam to Discord, and mass DMs can get a bot flagged. Do these rarely, and never as a response to something any user can trigger.

Reactions

Adding several reactions to a message is one request each and has its own small bucket, so a poll with ten options takes a few seconds to set up. That is expected.

The invalid request limit, and the one-hour ban

This is the one that takes bots offline. Discord counts responses with status 401 (bad token), 403 (missing permission) and 429 (rate limited) per IP address. Over 10,000 in ten minutes and the address is blocked at Cloudflare, usually for about an hour. You see errors mentioning Cloudflare, HTML instead of JSON, or:

You are being blocked from accessing our API temporarily due to exceeding our rate limits frequently.

Common ways to get there:

  • A crash loop with a bad token. Every restart tries to log in and gets a 401. Restarting every second adds up fast. Put a delay between restarts.
  • Retrying on 403. If the bot lacks a permission, trying again will never work. Catch discord.Forbidden and stop, rather than retrying.
  • Your own retry loop around 429s, on top of the library's. Let the library handle it.
  • Someone else. On free hosting, hundreds of bots share an address. One of them misbehaving blocks all of them. You did nothing wrong and can do nothing about it, which is the most common reason people move bots off shared free platforms.

The gateway has limits too

The websocket connection your bot holds open is separate from the REST API:

  • A connection can send about 120 messages a minute. Changing the bot's status every second counts against this. Change it every minute or less often.
  • Each bot has a daily number of fresh logins (identifies), shown as session_start_limit. A crash loop can use it up, and when it runs out the bot cannot log in until it resets. Normal reconnects resume the old session and do not count.

How to be a good citizen

  1. Let the library handle 429s. Do not add your own retries on top.
  2. Never retry a 401 or 403. Fix the cause.
  3. Put a delay between restarts after a crash, so a broken bot fails slowly.
  4. Cache what you can. Use guild.get_member() instead of fetch_member() when the member is already cached; get_ methods do not make a request at all.
  5. Batch updates. One edit with the final value beats ten edits on the way there.

If your bot is being blocked because of a shared address, the fix is running it somewhere that address is not shared with strangers. Your options are here; on SnowServers, bots share one server's address with a handful of other paying customers rather than thousands of free accounts, and each server's new outbound connections are capped so one bot cannot flood Discord from it.