Guides
Rate limits
Public requests are limited to 60 a minute for each IP address.
How it works#
- The limit counts requests from your IP address in each calendar minute. When a new minute starts, the count starts again.
- Every
/v1request counts, including errors and the health check. Images (/v1/assets/…) do not count: they are cached at Cloudflare’s edge instead. - Counts are kept separately in each Cloudflare data centre and are approximate by design, so you may occasionally get a few more or a few fewer. Do not rely on the exact number.
When you hit it#
You get 429 Too Many Requests with a Retry-After header. Wait that many seconds before trying again.
429 Too Many Requests
HTTP/2 429
content-type: application/json
retry-after: 60
{"error":"rate limited"}The body’s shape differs from other errors: error is a string, not an object. See Errors.
async function rankd(path) {
for (let attempt = 0; attempt < 3; attempt++) {
const response = await fetch(`https://api.rankdmusic.app${path}`);
if (response.status !== 429) return response;
const wait = Number(response.headers.get('Retry-After') ?? 60);
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
}
throw new Error('Still rate limited');
}import time
import requests
def rankd(path):
for _ in range(3):
response = requests.get(f"https://api.rankdmusic.app{path}", timeout=10)
if response.status_code != 429:
return response
time.sleep(int(response.headers.get("Retry-After", 60)))
raise RuntimeError("Still rate limited")Staying under it#
- Cache responses. Charts are worked out weekly and profiles change slowly.
- Ask for the largest page the endpoint allows (
limit). - Use one request where one will do: a profile page is one call to Get a profile, which includes counts, pins and achievements.
- Poll the health check gently, if at all.
- Serve many users from one server? They share your server’s IP address and its limit. Cache aggressively.
Need more? The limit is not adjustable per client today.