Skip to content

Frontend Keys

When using a frontend (client) API key, you can configure per-IP rate limit rules and per-IP stream limits to control how each individual IP address can use your application. This helps prevent abuse from any single user.

Per-IP Rate Limit Rules

Per-IP limit rules let you define granular rate limits that apply to each IP address using your frontend key. Each rule specifies:

  • Scope: What requests the rule applies to (per upstream, specific upstream, etc.)
  • Limit Unit: How the limit is measured (compute units, request count)
  • Window: The time window for the limit (e.g. 5 minutes)
  • Limit: The maximum allowed in the time window (use 0 to block)

Rules are evaluated independently - a request must satisfy all applicable rules to be allowed.

Scope Types

Default per upstream

Creates a separate rate limit counter for each upstream service type. This means an IP gets the specified limit for each service they use.

Scope: Default per upstream
Limit: 50,000 Compute Units
Window: 5 minutes

With this rule, a single IP could use:

  • 50,000 CUs against the node API
  • 50,000 CUs against the indexer API
  • etc.

In other words, each upstream maintains its own counter.

Specific upstream

Applies a limit only to a specific upstream service (e.g., node API, indexer API). Other upstreams are unaffected by this rule. You can use this to grant a higher limit to particular upstream, or alternatively you could set the value to zero to block a particular upstream.

In most cases you should use this in conjunction with a “default per upstream” rule. You can find the node operation IDs by looking for operationId in the OpenAPI spec.

Default per node operation

Similar to “Default per upstream” but for node API operations. Each operation (like get_account, get_transactions) gets its own counter.

Specific node operation

Set a different limit for a specific node API operation.

Default per GraphQL table

Creates separate counters for each GraphQL table accessed through GraphQL APIs. These include the core indexer API as well as no code indexing APIs. See all GraphQL tables (e.g. account_transactions) for the core indexer API here.

Specific GraphQL table

Set a different limit for a specific GraphQL table.

Default vs specific scopes

Understanding the difference between “Default per X” and “Specific X” scopes is important for setting up effective rate limits.

Default scopes (like “Default per Upstream”) create a separate counter for each item in that category. If you set a limit of 50,000 CUs with “Default per Upstream”, each upstream type gets its own 50,000 CU allowance.

Specific scopes (like “Upstream: NodeApi”) apply only to that one item. You can combine a default scope with specific overrides:

Rule 1: Default per Upstream - 50,000 CUs / 5min
Rule 2: Upstream: NodeApi - 20,000 CUs / 5min

In this case:

  • Node API is limited to 20,000 CUs (the specific rule overrides the default)
  • All other upstreams get 50,000 CUs each

Example configurations

Simple protection

One rule giving each upstream its own limit:

ScopeLimitUnitWindow
Default per Upstream100,000Compute Units5 min

Service-Specific Limits

Different limits for different services. Note: you should always include a default rule.

ScopeLimitUnitWindow
Default per Upstream50,000Compute Units5 min
Upstream: NodeApi100,000Compute Units5 min
Upstream: IndexerApi30,000Compute Units5 min

Protect expensive tables

Limit specific expensive GraphQL tables:

ScopeLimitUnitWindow
Default per Upstream100,000Compute Units5 min
Default per GraphQL Table50,000Compute Units5 min
GraphQL table: token_activities5,000Compute Units5 min

This allows generous overall usage but restricts the expensive token_activities table.

Block all traffic except for specific tables

To express “block all upstreams except for specific indexer API tables”, you need multiple rules that work together:

ScopeLimitUnitWindow
Default per Upstream0Request Count5 min
Upstream: IndexerApi1,000,000Request Count5 min
Default per GraphQL Table0Request Count5 min
GraphQL table: coin_activities100Request Count5 min
GraphQL table: token_activities100Request Count5 min

How this works:

  1. Default per Upstream = 0: Blocks all upstreams by default.
  2. Upstream: IndexerApi = high value: Allows the indexer API (overrides the default).
  3. Default per GraphQL Table = 0: Blocks all GraphQL tables by default.
  4. Specific GraphQL tables = intended limit: Allows only the tables you specify with their intended rate limits.

This pattern lets you create allowlist-style rules where everything is blocked except what you explicitly permit.

Note: This kind of overriding behavior only works for rules with the same “key”, where key is unit (e.g. request count) + window (e.g. 5 mins).

Per-IP Concurrent Stream Limit

In addition to rate limits, you can configure a per-IP concurrent stream limit. This controls how many long-running streaming connections (such as WebSocket or gRPC streams) each IP address can have open simultaneously.

Why use stream limits?

Streaming connections are long-lived and consume server resources for their entire duration. Without limits, a single malicious or misbehaving client could:

  • Open hundreds of connections from one IP, exhausting your organization’s stream quota
  • Prevent legitimate users from establishing new connections
  • Cause unexpected costs

How it works

When you set a per-IP stream limit (e.g., 2), each IP address using your frontend key can only have that many concurrent streams open at once. If they try to open more, the connection will be rejected with an HTTP 429 (Too Many Requests) error. Setting the limit to 0 will block all streaming connections for frontend keys.

The per-IP stream limit works alongside your organization’s overall stream limit. Both limits are checked - a connection must satisfy both to be allowed.

Example

If you set:

  • Per-IP stream limit: 2
  • Organization stream limit: 100

Then:

  • Each individual IP can have at most 2 concurrent streams
  • Your organization can have up to 100 total streams across all IPs
  • If one IP opens 2 streams, they cannot open more until one closes
  • Other IPs are unaffected and can still open their own streams (up to 2 each)