# How Nitter Handles Rate Limiting for Twitter API Requests: Session-Based Throttling Explained

> Discover how Nitter manages Twitter API rate limiting with session based throttling. Learn how it parses rate limit headers and halts traffic proactively to prevent quota exhaustion.

- Repository: [Zed/nitter](https://github.com/zedeus/nitter)
- Tags: internals
- Published: 2026-09-04

---

**Nitter prevents Twitter API quota exhaustion by parsing X-Rate-Limit headers on every request, storing counters in per-session state, and proactively halting traffic when fewer than 10 calls remain.**

Nitter, the open-source privacy frontend for Twitter written in Nim, implements a sophisticated rate limiting layer to protect both its infrastructure and upstream API access. Rather than relying solely on Twitter's rejection responses, the application continuously monitors rate limit headers and maintains granular state for each API endpoint. This article examines the implementation in the `zedeus/nitter` repository, covering how the system tracks limits, applies safety margins, and degrades gracefully when quotas are depleted.

## Session-Based Rate Limit State

Rate limit tracking begins in `src/auth.nim`, where the `Session` type maintains an `apis` map storing `RateLimit` records for each endpoint. This structure captures three critical values from Twitter's response headers:

- `remaining` — API calls left in the current window
- `reset` — Unix timestamp when the quota refreshes
- `limit` — Maximum calls allowed per window

The `setRateLimit` procedure (lines 200–212) populates these fields after every successful API interaction, ensuring the session object always reflects current Twitter-imposed constraints.

```nim

# src/auth.nim - RateLimit object definition and storage

type
  RateLimit* = object
    remaining*: int
    reset*: int
    limit*: int

  Session* = ref object
    apis*: Table[string, RateLimit]

```

## Monitoring X-Rate-Limit Headers

After each HTTP request, `src/apiutils.nim` inspects response headers to extract Twitter's official quota indicators. The code reads `x-rate-limit-remaining`, `x-rate-limit-reset`, and `x-rate-limit-limit`, then invokes `session.setRateLimit` to persist these values (lines 56–63).

```nim

# src/apiutils.nim - Header extraction after API calls

let remaining = parseInt(resp.headers["x-rate-limit-remaining"])
let reset = parseInt(resp.headers["x-rate-limit-reset"])
let limit = parseInt(resp.headers["x-rate-limit-limit"])
session.setRateLimit(req, remaining, reset, limit)

```

This passive monitoring ensures Nitter's internal state remains synchronized with Twitter's official counters, preventing drift and enabling accurate pre-flight checks.

## Proactive Throttling with Safety Margins

Before dispatching requests, Nitter applies a **10-request safety margin** to avoid edge-of-window rejections. The `isLimited` procedure in `src/auth.nim` (lines 58–61) returns `true` when `remaining` drops to 10 or fewer and the `reset` timestamp is still in the future.

```nim

# src/auth.nim - Safety margin check

proc isLimited*(session: Session, req: ApiReq): bool =
  let rate = session.apis.getOrDefault(req.endpoint)
  result = rate.remaining <= 10 and rate.reset > getTime().toUnix()

```

This conservative threshold ensures that even if multiple requests are in flight simultaneously, the system stops well before exhausting the official quota, leaving buffer room for Twitter's accounting variations.

## Error Handling and User Experience

When rate limits are exceeded—or when Twitter returns HTTP 429, a JSON `rateLimited` error, or Cloudflare protection—the system raises a custom `RateLimitError`. Defined in `src/auth.nim` (lines 39–40), this exception propagates through `fetchImpl` in `src/apiutils.nim` (lines 78–86 and 172–184), which catches upstream rejections and re-throws them for top-level handling.

The main application entry in `src/nitter.nim` (lines 18–22) maps this exception to an HTTP 429 response featuring a user-friendly error page with a link to alternative public instances:

```nim

# src/nitter.nim - Top-level error mapping

error RateLimitError:
  const link = a("another instance", href = instancesUrl)
  resp Http429, showError(
    &"Instance has been rate limited.<br>Use {link} or try again later.", cfg)

```

This three-tier strategy—**passive header monitoring**, **proactive client-side throttling**, and **graceful degradation**—ensures Nitter respects Twitter's infrastructure limits while maintaining transparency for end users.

## Summary

- **Per-session tracking**: Each `Session` object maintains granular `RateLimit` records per API endpoint in `src/auth.nim`, enabling precise quota accounting.
- **Real-time header parsing**: `src/apiutils.nim` extracts `x-rate-limit-*` headers after every request to synchronize internal counters with Twitter's official limits.
- **Conservative safety margins**: The `isLimited` check stops requests when fewer than 10 calls remain, preventing hard rate limit violations.
- **Unified error mapping**: `RateLimitError` propagates through the stack to `src/nitter.nim`, where it renders informative HTTP 429 pages suggesting alternative instances.

## Frequently Asked Questions

### What triggers a RateLimitError in Nitter?

A `RateLimitError` fires in three scenarios: when Twitter returns HTTP 429, when the JSON response contains a `rateLimited` field, or when Cloudflare protection blocks the request. The `fetchImpl` procedure in `src/apiutils.nim` detects these conditions and raises the exception to halt further processing.

### How does Nitter determine when to stop making requests?

Before each API call, the system checks `session.isLimited()` in `src/auth.nim`. This returns `true` when the stored `remaining` count drops to 10 or less and the `reset` timestamp is still in the future. This safety margin prevents requests that would likely be rejected by Twitter's servers.

### Can users configure the rate limit threshold?

The safety threshold of 10 requests is hardcoded in the `isLimited` procedure within `src/auth.nim`. Administrators wishing to adjust this margin must modify the source code and rebuild the application; there is no runtime configuration option for this parameter.

### What happens when all sessions are rate limited?

When every available session exhausts its quota, Nitter serves an HTTP 429 response through the error handler in `src/nitter.nim`. The response includes a hyperlink to a list of public Nitter instances, allowing users to redirect their traffic to alternative servers while the current instance waits for its quotas to reset.