Files
mintlify__docs/concepts/rate-limits.mdx
Mintlify Agent 65fd3621dc Add Spotify Web API documentation
- Created 111 MDX documentation files
- Added 89 API endpoint pages across 14 categories
- Included 11 concept guides and 7 tutorials
- Configured Mintlify with Spotify branding (#1DB954)
- All pages validated successfully
2026-02-07 11:47:26 +00:00

260 lines
6.0 KiB
Plaintext

---
title: "Rate limits"
description: "Understanding rate limiting in the Spotify Web API"
---
# Rate limits
The Spotify Web API uses rate limiting to protect service stability and ensure fair usage across all applications. Understanding and respecting these limits is crucial for building reliable applications.
## How rate limiting works
Rate limits restrict the number of API requests your application can make within a specific time window. When you exceed the limit, the API returns a 429 (Too Many Requests) error.
### Rate limit factors
Limits depend on:
- The specific endpoint being called
- Your app's quota mode (development vs extended)
- The authentication method used
- Current system load
<Note>
Rate limits are subject to change. Always implement adaptive rate limiting in your application.
</Note>
## Rate limit headers
Every API response includes headers with rate limit information:
<ResponseField name="X-RateLimit-Limit" type="integer">
The rate limit ceiling for the given endpoint
</ResponseField>
<ResponseField name="X-RateLimit-Remaining" type="integer">
Number of requests remaining in the current window
</ResponseField>
<ResponseField name="X-RateLimit-Reset" type="integer">
Time when the rate limit window resets (Unix timestamp)
</ResponseField>
Example response headers:
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1612137600
```
## Handling rate limit errors
When you receive a 429 error, the response includes a `Retry-After` header:
```json
{
"error": {
"status": 429,
"message": "API rate limit exceeded"
}
}
```
Response headers:
```
Retry-After: 30
```
This indicates you should wait 30 seconds before retrying.
### Retry strategy
Implement exponential backoff with jitter:
```javascript
async function makeRequestWithRetry(url, token, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${token}` }
});
if (response.status !== 429) {
return response;
}
// Rate limited
const retryAfter = response.headers.get('Retry-After');
const waitTime = retryAfter ?
parseInt(retryAfter) * 1000 :
Math.pow(2, i) * 1000; // Exponential backoff
// Add jitter
const jitter = Math.random() * 1000;
await new Promise(resolve => setTimeout(resolve, waitTime + jitter));
}
throw new Error('Max retries exceeded');
}
```
## Best practices
<AccordionGroup>
<Accordion title="Monitor rate limit headers">
Track `X-RateLimit-Remaining` and proactively slow down requests when approaching the limit.
```javascript
const remaining = response.headers.get('X-RateLimit-Remaining');
if (remaining < 10) {
await delay(1000); // Slow down
}
```
</Accordion>
<Accordion title="Use batch endpoints">
Reduce total requests by using endpoints that accept multiple IDs:
```bash
# Good: 1 request
GET /albums?ids=id1,id2,id3,id4,id5
# Bad: 5 requests
GET /albums/id1
GET /albums/id2
GET /albums/id3
GET /albums/id4
GET /albums/id5
```
</Accordion>
<Accordion title="Implement caching">
Cache responses for data that doesn't change frequently:
- Album metadata
- Artist information
- Track details
- Genre lists
Don't cache:
- User's current playback
- Queue information
- Recently played tracks
</Accordion>
<Accordion title="Use webhooks when available">
Instead of polling endpoints repeatedly, use webhooks or WebSockets where available.
</Accordion>
<Accordion title="Implement request queuing">
Queue requests and process them at a controlled rate:
```javascript
class RateLimiter {
constructor(requestsPerSecond) {
this.queue = [];
this.interval = 1000 / requestsPerSecond;
this.processing = false;
}
async enqueue(fn) {
return new Promise((resolve, reject) => {
this.queue.push({ fn, resolve, reject });
this.process();
});
}
async process() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
const { fn, resolve, reject } = this.queue.shift();
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
}
setTimeout(() => {
this.processing = false;
this.process();
}, this.interval);
}
}
```
</Accordion>
</AccordionGroup>
## Quota modes
Your app's quota mode affects rate limits:
### Development mode
- Default for new apps
- Limited API quota
- Suitable for testing with up to 25 users
- Lower rate limits
### Extended quota mode
- Request through Developer Dashboard
- Higher rate limits
- Required for production apps
- Requires app review
Learn more about [quota modes](/concepts/quota-modes).
## Monitoring rate limits
Track your rate limit usage:
```javascript
class RateLimitMonitor {
constructor() {
this.stats = {
totalRequests: 0,
rateLimitHits: 0,
currentRemaining: null,
resetTime: null
};
}
recordRequest(response) {
this.stats.totalRequests++;
if (response.status === 429) {
this.stats.rateLimitHits++;
}
this.stats.currentRemaining =
response.headers.get('X-RateLimit-Remaining');
this.stats.resetTime =
response.headers.get('X-RateLimit-Reset');
}
getStats() {
return {
...this.stats,
hitRate: this.stats.rateLimitHits / this.stats.totalRequests
};
}
}
```
## Next steps
<CardGroup cols={2}>
<Card title="API calls" icon="code" href="/concepts/api-calls">
Best practices for API calls
</Card>
<Card title="Quota modes" icon="gauge" href="/concepts/quota-modes">
Learn about quota modes
</Card>
<Card title="Making API calls" icon="book" href="/getting-started/making-api-calls">
API calls guide
</Card>
</CardGroup>