# How to Fix Rate Limiting Errors When Using the GitHub Readme Stats Public API

> Solve GitHub Readme Stats API rate limiting by deploying your own Vercel instance or adding stable query parameters to bypass shared quota limits and edge cache.

- Repository: [Anurag Hazra/github-readme-stats](https://github.com/anuraghazra/github-readme-stats)
- Tags: how-to-guide
- Published: 2026-02-28

---

**Deploy your own Vercel instance with multiple `PAT_*` environment variables to eliminate shared API quota constraints, or add stable query parameters to leverage the public service's 5-minute edge cache.**

The **GitHub Readme Stats** public API frequently encounters GitHub's GraphQL rate limits because it runs on a shared Vercel instance with a finite pool of personal access tokens. By understanding the token rotation logic in [`src/common/retryer.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/common/retryer.js), you can configure a self-hosted deployment that avoids the "maximum retries exceeded" error entirely.

## How the Token Rotation System Works

The service implements a **Retryer** class in [`src/common/retryer.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/common/retryer.js) to automatically cycle through available GitHub tokens whenever the API signals a rate limit.

At initialization, the system scans environment variables to count how many `PAT_*` tokens are defined (lines 9-12), setting this count as the maximum number of retries. When a GraphQL request returns `errorType === "RATE_LIMITED"` or an error message containing "rate limit" (lines 49-56), the retryer recursively re-attempts the request with the next token in the sequence. If all tokens exhaust their individual 5,000 requests-per-hour quotas, the library throws `CustomError.MAX_RETRY` and the badge renders a failure state.

## Why Rate Limit Errors Occur on the Public API

### Shared Token Pool Exhaustion

The public Vercel instance serves thousands of users from a small set of `PAT_*` tokens. Because GitHub grants only **5,000 GraphQL requests per hour per token**, heavy traffic from popular repositories can deplete the entire shared pool, causing the service to return errors for all users until the quota resets.

### Multi-Page Repository Fetching

By default, the public instance disables multi-page star counting to conserve API calls. The stats fetcher in [`src/fetchers/stats.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/fetchers/stats.js) checks `process.env.FETCH_MULTI_PAGE_STARS` at lines 47-55; when this value equals `"true"`, the `while (hasNextPage)` loop (lines 24-55) requests additional GraphQL pages for every repository, multiplying the API cost per profile by 10x or more.

## Methods to Fix Rate Limiting Errors

### Deploy Your Own Instance with Multiple PATs

Fork the `anuraghazra/github-readme-stats` repository and deploy it to your personal Vercel account. Generate several GitHub Personal Access Tokens (no special scopes required beyond `public_repo`) and configure them as environment variables:

```env
PAT_1=ghp_XXXXXXXXXXXXXXXXXXXX
PAT_2=ghp_YYYYYYYYYYYYYYYYYYYY
PAT_3=ghp_ZZZZZZZZZZZZZZZZZZZZ

```

The retryer automatically detects and uses all `PAT_*` variables it finds (lines 9-12 in [`src/common/retryer.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/common/retryer.js)), giving you 5,000 requests per token per hour. With three tokens, you handle 15,000 requests before hitting any limit.

### Configure Multi-Page Fetching Settings

Only enable `FETCH_MULTI_PAGE_STARS=true` if you require accurate star counts across paginated repositories. When disabled (the default), the fetcher stops after the first page, keeping requests well under the rate limit. If you must enable it, ensure you have at least three to five PATs configured to absorb the additional query cost.

### Leverage CDN Caching

The public service uses Vercel's edge network to cache rendered SVGs for approximately five minutes. To maximize cache hits and avoid triggering new GitHub API calls, use consistent, stable query parameters in your badge URLs:

```markdown
![GitHub stats](https://github-readme-stats.vercel.app/api?username=yourname&show_icons=true)

```

Identical URLs serve cached responses without consuming additional API quota.

### Implement Client-Side Fallbacks

Handle the inevitable "down" state gracefully by catching load errors and displaying a static placeholder:

```javascript
const img = document.getElementById('stats-badge');
img.onerror = () => {
  img.src = '/static/placeholder.svg';
};

```

This prevents broken images from displaying when the public API exhausts its token pool.

## Summary

- The public API shares a limited pool of GitHub tokens; when all tokens hit the 5,000 request/hour limit, the service returns errors for all users.
- **Self-hosting** with multiple `PAT_*` environment variables is the only guaranteed fix, leveraging the rotation logic in [`src/common/retryer.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/common/retryer.js).
- Disable `FETCH_MULTI_PAGE_STARS` unless necessary to reduce GraphQL query volume (see [`src/fetchers/stats.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/fetchers/stats.js) lines 47-55).
- Use consistent URL parameters to benefit from Vercel's 5-minute edge caching.
- Implement `onerror` handlers to hide broken badges when rate limits occur.

## Frequently Asked Questions

### What triggers the "maximum retries exceeded" error?

This error occurs when the retryer in [`src/common/retryer.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/common/retryer.js) exhausts all available `PAT_*` tokens without successfully fetching data. Each GitHub token allows 5,000 GraphQL requests per hour; when the shared public pool is empty, the library throws `CustomError.MAX_RETRY` at line 56.

### How many GitHub tokens should I configure for self-hosting?

For personal use with low traffic, one token is sufficient. If you enable `FETCH_MULTI_PAGE_STARS` or serve high-traffic pages, configure three to five tokens. The retryer automatically cycles through any `PAT_*` variables present in the environment.

### Can I fix rate limits without self-hosting?

You can reduce occurrences by using stable query parameters to maximize the 5-minute CDN cache window, but you cannot eliminate the hard limit on the shared public instance. The only permanent solution is deploying your own instance with private tokens.

### Does enabling multi-page stars always cause rate limits?

Only if you have insufficient tokens. The `while (hasNextPage)` loop in [`src/fetchers/stats.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/fetchers/stats.js) (lines 24-55) issues one additional GraphQL request per page of repositories. For users with hundreds of starred repos, this quickly exhausts a single token's hourly quota.