Rate limits

Stream applies rate limits to protect both your application and our infrastructure. Rate limits prevent:

  • Integration issues or abuse from degrading your app's performance (excessive API calls trigger client-side events)
  • Resource consumption beyond what is provisioned for your plan
  • Common integration mistakes, such as opening multiple WebSocket connections per user

Rate limits work the same way across every Stream product. They are applied per API endpoint and platform on a 1-minute window. Different platforms (iOS, Android, Web, Server) have independent counters for each endpoint.

If 6,000 iOS users and 6,000 Android users connect within one minute, no rate limit is triggered. The 10,000/minute connect limit applies independently to each platform.

Dynamic Rate Limiting: Rate limits may be adjusted based on overall platform load and your application's individual usage patterns for query endpoints. During periods of high demand, the platform may temporarily reduce rate limits to ensure stability and fair resource allocation for all users. Monitor the X-RateLimit-* headers in API responses to track your current limits.

Types of Rate Limits

User Rate Limits

Each user is limited to 60 requests per minute per endpoint and platform. This prevents a single user from consuming your entire application quota. Your server is not subject to user rate limits.

App Rate Limits

App rate limits apply per endpoint and platform combination. Stream supports four platforms:

PlatformSDKs
ServerNode, Python, Ruby, Go, C#, PHP, Java
AndroidKotlin, Java, Flutter, React Native
iOSSwift, Flutter, React Native
WebReact, Angular, JavaScript

Rate limits are not shared across platforms. If a server-side script hits a rate limit, your mobile and web applications are unaffected.

App rate limits are enforced both per minute and per second. The per-second limit equals the per-minute limit divided by 30 to allow for bursts.

When a rate limit is exceeded, all calls from the same app, platform, and endpoint return HTTP status 429.

Rate Limit Headers

All API responses include rate limit information in headers.

HeaderDescription
X-RateLimit-LimitTotal limit for the requested resource (e.g. 5000)
X-RateLimit-RemainingRemaining requests in current window (e.g. 4999)
X-RateLimit-ResetWhen the current window resets (Unix timestamp)

Inspecting Rate Limits

Check your current rate limit quotas and usage in your app's dashboard, or via the API.

// Server-side platform only
const limits = await client.getRateLimits({ serverSide: true });

// All platforms
const limits = await client.getRateLimits();

// Specific platforms
const limits = await client.getRateLimits({ ios: true, android: true });

// Specific endpoints
const limits = await client.getRateLimits({
  endpoints: ["QueryUsers", "UpdateUsers"],
});

The response includes the 1-minute limit, remaining quota, and window reset timestamp.

Handling Rate Limit Errors

When you receive a 429 status code, implement exponential back-off retry logic. Use the X-RateLimit-Reset header to determine when to retry.

Catching 429s in backend SDKs

The Go, Python, Java, PHP, Ruby, and .NET SDKs surface 429s as a dedicated rate-limit exception that carries the parsed Retry-After header. Catch the rate-limit subclass first if you want to react to throttling, then fall through to the broader API-error catch for other 4xx/5xx responses. Each SDK documents its exception class hierarchy for this purpose. In Node.js, check the response code and rate limit information on the error's metadata instead.

try {
  await client.queryUsers(...);
} catch (error) {
  const rateLimit = error.metadata?.rateLimit;
  if (error.metadata?.responseCode === 429) {
    // Wait until rateLimit.rateLimitReset, then retry
  }
}

Retry-After parsing supports both forms documented in RFC 7231 §7.1.3: an integer number of seconds (Retry-After: 30) or an HTTP-date (Retry-After: Fri, 31 Dec 2026 23:59:59 GMT). Past dates clamp to zero. If the header is absent or unparseable, the exception's retryAfter field is null/None/zero so your code does not have to guard against parse errors.

Automatic retries

Instead of catching 429s yourself, you can let the SDK retry them for you. Automatic retries are opt-in and disabled by default; enable them when you construct the client and set the attempt budget and the maximum wait between attempts.

from getstream import Stream, RetryConfig

client = Stream(
    api_key="your_api_key",
    api_secret="your_api_secret",
    retry=RetryConfig(enabled=True, max_attempts=3, max_backoff=30.0),
)

When enabled, the SDK retries only idempotent GET and HEAD requests, and only when the response is a 429 that the backend has not marked unrecoverable, or a transport-level failure (connection reset, timeout, DNS, or TLS). Writes (POST, PUT, PATCH, DELETE), 5xx responses, and other 4xx responses are never retried. maxAttempts counts the initial request, so the default of 3 means one request plus up to two retries. Between attempts the SDK waits for the Retry-After header when present (clamped to maxBackoff), otherwise a full-jitter exponential backoff capped at maxBackoff. If every attempt fails, the last error is surfaced unchanged, so the exception handling above still applies.

Avoiding Rate Limits

  1. Add delays to scripts - The most common cause of rate limits. Add timeouts between successive API calls in batch scripts or cronjobs.

  2. Use batch endpoints - Instead of 100 individual calls, use batch endpoints to update multiple resources in one request.

  3. Check client-side rendering logic - Infinite pagination bugs or other client-side issues can trigger excessive API calls.

  4. Avoid redundant queries - Many of Stream's endpoints have upsert behavior. Do not query to check whether an entity exists before creating it.

Each product's rate limits page lists practices specific to that product, such as livestream chat messaging volume.

Requesting Higher Limits

  • Standard plans - Stream may increase limits after reviewing your integration to confirm optimal usage of default limits.
  • Enterprise plans - Stream reviews your architecture and sets appropriate limits for your production application.

Default Limits by Endpoint

Default limits for endpoints shared by all Stream products are listed below. Product endpoints are documented with each product:

Common endpoints

Operation IDRate limit (req/min)
BlockUsers300
CheckExternalStorage60
CheckPush60
CheckSNS60
CheckSQS300
CreateBlockList60
CreateDevice300
CreateExternalStorage60
CreateGuest1,000
CreateImport300
CreateImportURL300
CreateImportV2Task1,000
CreatePoll300
CreatePollOption300
CreateRole60
Connect10,000
DeactivateUser60
DeactivateUsers60
DeleteBlockList60
DeleteDevice60
DeleteExternalStorage60
DeleteFile60
DeleteImage60
DeleteImportV2Task1,000
DeletePoll60
DeletePollOption60
DeletePushProvider60
DeleteRole60
DeleteUsers6
ExportUser60
ExportUsers60
GetApp10,000
GetBlockList60
GetBlockedUsers300
GetImport300
GetImportV2Task1,000
GetOG1,000
GetPermission60
GetPoll1,000
GetPollOption1,000
GetPushTemplates60
GetRateLimits1,000
GetTask300
GetUserLiveLocations1,000
ListBlockLists60
ListDevices60
ListExternalStorage60
ListImportV2Tasks1,000
ListImports300
ListPermissions60
ListPushProviders60
ListRoles60
LongPoll10,000
QueryPollVotes1,000
QueryPolls1,000
QueryUsers1,000
ReactivateUser60
ReactivateUsers60
RestoreUsers1,000
UnblockUsers300
UpdateApp60
UpdateBlockList60
UpdateExternalStorage60
UpdateLiveLocation1,000
UpdatePoll300
UpdatePollOption300
UpdatePollPartial300
UpdatePushNotificationPreferences300
UpdateUsers300
UpdateUsersPartial300
UploadFile1,000
UploadImage1,000
UpsertPushProvider60
UpsertPushTemplate60

All endpoints also enforce the user rate limit of 60 requests per minute per user. Rate limits can be adjusted based on your use case and plan.