Skip to content

How-To Apply Per-Domain Rate Limits

When scraping multiple domains, you often need to apply different rate limits for each. This recipe shows how to configure domain-specific limits with a fallback default.

import httpx
from httpx_limiter import (
    AbstractRateLimiterRepository,
    AsyncMultiRateLimitedTransport,
    Rate,
)
from httpx_limiter.pyrate import PyrateAsyncLimiter


DOMAIN_RATES: dict[str, Rate] = {
    "api.github.com": Rate.create(magnitude=30),
    "api.twitter.com": Rate.create(magnitude=15),
}
DEFAULT_RATE = Rate.create(magnitude=5)


class PerDomainRepository(AbstractRateLimiterRepository):
    """Apply preconfigured rate limits per domain."""

    def get_identifier(self, request: httpx.Request) -> str:
        return str(request.url.host)

    def create(self, request: httpx.Request) -> PyrateAsyncLimiter:
        host = str(request.url.host)
        rate = DOMAIN_RATES.get(host, DEFAULT_RATE)
        return PyrateAsyncLimiter.create(rate)


async def main() -> None:
    transport = AsyncMultiRateLimitedTransport.create(
        repository=PerDomainRepository(),
    )
    async with httpx.AsyncClient(transport=transport) as client:
        await client.get("https://api.github.com/users/octocat")
        await client.get("https://api.twitter.com/2/users/me")
        await client.get("https://other-api.example.com/data")

Of course, you may even combine this with the adaptive rate limiting technique.