Skip to content
sentry-rate-limits logo

Sentry Rate Limits & Quota Optimization

sentry-rate-limits

Manage Sentry rate limits, quotas, and event volume optimization.

SKILL.md

Full skill instructions

Sentry Rate Limits & Quota Optimization

Overview

Manage Sentry rate limits, sampling strategies, and quota usage to control costs without losing visibility into critical errors. Covers client-side sampling, beforeSend filtering, server-side inbound filters, per-key rate limits, spike protection, and the usage stats API.

Prerequisites

  • Sentry account with a project DSN configured
  • SENTRY_AUTH_TOKEN with org:read and project:write scopes (Settings > Auth Tokens)
  • SENTRY_ORG and SENTRY_PROJECT slugs known
  • SDK installed: @sentry/​node (npm) or sentry-sdk (pip)
  • Current event volume visible at sentry.io/​stats/

Instructions

Step 1 — Understand Rate Limit Behavior

When your project exceeds its quota, Sentry returns 429 Too Many Requests with a Retry-After header. The SDK automatically stops sending events until the cooldown expires. Events generated during this window are permanently lost — there is no replay mechanism.

Rate limit tiers by plan:

PlanAPI Rate LimitNotes
Developer50 RPMShared quota, no reserved volume
Team1,000 RPMPer-organization, includes spike protection
Business10,000 RPMPer-organization, custom quotas available
EnterpriseCustomNegotiated per contract

Quota categories (billed separately):

  • Errors — exceptions and log messages
  • Transactions — performance monitoring spans
  • Replays — session replay recordings
  • Attachments — file uploads (crash dumps, minidumps)
  • Profiles — continuous profiling data
  • Cron monitors — scheduled job check-ins

Rate limit headers returned on 429:

HTTP/​1.1 429 Too Many Requests
Retry-After: 60
X-Sentry-Rate-Limit-Limit: 50
X-Sentry-Rate-Limit-Remaining: 0
X-Sentry-Rate-Limit-Reset: 1711324800

Step 2 — Configure Client-Side Sampling

Sampling is the first line of defense. Set sampleRate for errors and tracesSampleRate for performance transactions.

TypeScript / Node.js:

import * as Sentry from '@sentry/​node';

Sentry.init({
  dsn: process.env.SENTRY_DSN,

  // Error sampling: 0.0 (drop all) to 1.0 (capture all)
  sampleRate: 0.25, // Capture 25% of errors

  // Transaction sampling: 0.0 to 1.0
  tracesSampleRate: 0.1, // Capture 10% of transactions

  // Dynamic transaction sampling — route-aware cost control
  tracesSampler: (samplingContext) => {
    const { name, parentSampled } = samplingContext;

    // Respect parent sampling decision in distributed traces
    if (parentSampled !== undefined) return parentSampled;

    // Drop health checks and readiness probes entirely
    if (name === 'GET /​health' || name === 'GET /​readiness') return 0;
    if (name?.includes('/​health')) return 0;

    // High-value: payment and auth flows at 100%
    if (name?.includes('/​api/​payment') || name?.includes('/​api/​auth')) return 1.0;

    // Medium-value: API routes at 20%
    if (name?.startsWith('GET /​api/') || name?.startsWith('POST /​api/')) return 0.2;

    // Low-value: static assets — never trace
    if (name?.startsWith('GET /​static/') || name?.startsWith('GET /​assets/')) return 0;

    // Default fallback: 5%
    return 0.05;
  },
});

Python:

import sentry_sdk

def traces_sampler(sampling_context):
    tx_name = sampling_context.get("transaction_context", {}).get("name", "")

    # Drop health checks
    if "/​health" in tx_name or "/​readiness" in tx_name:
        return 0

    # High-value flows
    if "/​api/​payment" in tx_name or "/​api/​auth" in tx_name:
        return 1.0

    # API routes
    if tx_name.startswith(("GET /​api/", "POST /​api/")):
        return 0.2

    # Static assets
    if tx_name.startswith(("GET /​static/", "GET /​assets/")):
        return 0

    return 0.05

sentry_sdk.init(
    dsn=os.environ["SENTRY_DSN"],
    sample_rate=0.25,          # 25% of errors
    traces_sample_rate=0.1,    # 10% of transactions (fallback if no sampler)
    traces_sampler=traces_sampler,
)

Step 3 — Filter Noisy Errors with beforeSend

Use beforeSend to drop events before they count against your quota. This runs client-side, so filtered events never reach Sentry.

TypeScript / Node.js:

Sentry.init({
  dsn: process.env.SENTRY_DSN,

  beforeSend(event, hint) {
    const error = hint?.originalException as Error | undefined;

    // Drop browser extension errors (common in frontend SDKs)
    if (event.exception?.values?.some(e =>
      e.stacktrace?.frames?.some(f =>
        f.filename?.includes('extensions://') ||
        f.filename?.includes('moz-extension://') ||
        f.filename?.includes('chrome-extension://')
      )
    )) {
      return null; // Drop the event
    }

    // Drop known noisy browser errors
    if (error?.message?.match(/​ResizeObserver loop/)) return null;
    if (error?.message?.match(/​Non-Error promise rejection/)) return null;
    if (error?.name === 'AbortError') return null;
    if (error?.message?.match(/​Load failed/)) return null;

    // CRITICAL: Always capture payment errors regardless of sampleRate
    if (error?.message?.includes('PaymentError') ||
        event.tags?.['transaction.type'] === 'payment') {
      return event; // Force capture
    }

    return event;
  },

  // Pattern-based error filtering (faster than beforeSend for known strings)
  ignoreErrors: [
    'ResizeObserver loop completed with undelivered notifications',
    'Non-Error promise rejection captured',
    /​Loading chunk \d+ failed/,
    'Network request failed',
    'Failed to fetch',
    'AbortError',
    /^Script error\.?$/,
    'TypeError: cancelled',
    'TypeError: NetworkError when attempting to fetch resource',
  ],

  // Block errors originating from third-party scripts
  denyUrls: [
    /​extensions\//i,
    /^chrome:\/\//i,
    /^chrome-extension:\/\//i,
    /^moz-extension:\/\//i,
    /​hotjar\.com/,
    /​google-analytics\.com/,
    /​googletagmanager\.com/,
    /​intercom\.io/,
  ],
});

Python:

def before_send(event, hint):
    if "exc_info" in hint:
        exc_type, exc_value, _ = hint["exc_info"]

        # Drop known noisy exceptions
        if exc_type.__name__ in ("ConnectionResetError", "BrokenPipeError"):
            return None

        # Drop health check 404s
        msg = str(exc_value)
        if "health" in msg.lower() and "404" in msg:
            return None

    # Always capture payment errors
    if event.get("tags", {}).get("transaction.type") == "payment":
        return event

    return event

sentry_sdk.init(
    dsn=os.environ["SENTRY_DSN"],
    before_send=before_send,
    ignore_errors=[
        "ConnectionResetError",
        "BrokenPipeError",
    ],
)

Step 4 — Enable Server-Side Inbound Data Filters

Inbound filters run on Sentry's servers before quota counting. Filtered events do not consume quota — this is free filtering.

Configure at Project Settings > Inbound Filters:

FilterWhat it blocksRecommended
Legacy browsersIE 9/​10, old Safari, old AndroidEnable
Browser extensionsErrors from browser extension codeEnable
Localhost eventsEvents from localhost / 127.0.0.1Enable for production projects
Web crawlersBot-generated errors (Googlebot, etc.)Enable
Filtered releasesSpecific release versionsUse for deprecated releases
Error message patternsCustom regex patternsAdd known false-positive patterns

Configure via API:

# Enable legacy browser filter
curl -X PUT \
  -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
  -H "Content-Type: application/​json" \
  -d '{"active": true}' \
  "https://sentry.io/​api/​0/​projects/​$SENTRY_ORG/​$SENTRY_PROJECT/​filters/​legacy-browsers/"

# Enable browser extension filter
curl -X PUT \
  -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
  -H "Content-Type: application/​json" \
  -d '{"active": true}' \
  "https://sentry.io/​api/​0/​projects/​$SENTRY_ORG/​$SENTRY_PROJECT/​filters/​browser-extensions/"

# Enable web crawler filter
curl -X PUT \
  -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
  -H "Content-Type: application/​json" \
  -d '{"active": true}' \
  "https://sentry.io/​api/​0/​projects/​$SENTRY_ORG/​$SENTRY_PROJECT/​filters/​web-crawlers/"

Step 5 — Set Per-Key Rate Limits

Each DSN (Client Key) can have its own rate limit. This prevents a single project from exhausting the organization's entire quota.

Configure at Project Settings > Client Keys > Configure > Rate Limiting.

# Set rate limit to 1000 events per hour on a specific client key
# First, list client keys to find the key ID
curl -s -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
  "https://sentry.io/​api/​0/​projects/​$SENTRY_ORG/​$SENTRY_PROJECT/​keys/" \
  | python3 -m json.tool

# Then set the rate limit
curl -X PUT \
  -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
  -H "Content-Type: application/​json" \
  -d '{"rateLimit": {"window": 3600, "count": 1000}}' \
  "https://sentry.io/​api/​0/​projects/​$SENTRY_ORG/​$SENTRY_PROJECT/​keys/​$KEY_ID/"

Strategy for multi-environment setups:

  • Production DSN: 5,000 events/​hour (critical errors matter)
  • Staging DSN: 500 events/​hour (only need representative sample)
  • Development DSN: 100 events/​hour (prevent local debugging floods)

Step 6 — Enable Spike Protection

Spike protection is auto-enabled on Team and Business plans. It detects sudden event volume increases and temporarily rate-limits the project to prevent quota exhaustion from error storms.

Configure at Organization Settings > Spike Protection.

When spike protection triggers:

  1. Sentry detects volume exceeding 10x normal baseline
  2. Events are temporarily dropped (429 returned to SDK)
  3. An email notification is sent to organization owners
  4. Protection auto-disables after the spike subsides

For programmatic spike alerts, set up a Sentry alert rule:

  • Condition: Number of events in project exceeds threshold
  • Action: Send notification to Slack/​PagerDuty/​email
  • Frequency: Alert once per hour

Step 7 — Monitor Quota Usage via API

# Organization-wide usage stats for the last 7 days, grouped by category
curl -s -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
  "https://sentry.io/​api/​0/​organizations/​$SENTRY_ORG/​stats_v2/?field=sum(quantity)&groupBy=category&interval=1d&statsPeriod=7d" \
  | python3 -m json.tool

# Per-project usage breakdown
curl -s -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
  "https://sentry.io/​api/​0/​organizations/​$SENTRY_ORG/​stats_v2/?field=sum(quantity)&groupBy=project&category=error&interval=1d&statsPeriod=7d" \
  | python3 -m json.tool

# Outcome-based stats (accepted, filtered, rate_limited, invalid)
curl -s -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
  "https://sentry.io/​api/​0/​organizations/​$SENTRY_ORG/​stats_v2/?field=sum(quantity)&groupBy=outcome&category=error&interval=1d&statsPeriod=24h" \
  | python3 -m json.tool

Step 8 — Reduce Payload Size and Deduplicate

Reduce event size and improve grouping to lower quota consumption:

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  maxBreadcrumbs: 30,   // Default: 100
  maxValueLength: 500,   // Default: 250

  beforeSend(event) {
    // Truncate large request bodies
    if (event.request?.data && typeof event.request.data === 'string') {
      event.request.data = event.request.data.substring(0, 1000);
    }
    // Remove cookies
    if (event.request?.cookies) delete event.request.cookies;

    // Custom fingerprinting: normalize dynamic values for better grouping
    if (event.exception?.values?.[0]) {
      const { type, value } = event.exception.values[0];
      const normalized = value
        ?.replace(/\b[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\b/​gi, '<UUID>')
        ?.replace(/\b\d+\b/​g, '<N>') || '';
      event.fingerprint = [type || 'unknown', normalized];
    }
    return event;
  },
});

Output

After completing these steps, you will have:

  • Sampling rates configured (sampleRate, tracesSampleRate, tracesSampler) to reduce event volume while preserving visibility into critical paths
  • beforeSend filtering dropping noisy browser errors (ResizeObserver, AbortError, extension errors) before they count against quota
  • ignoreErrors and denyUrls patterns blocking known false positives
  • Server-side inbound filters enabled for free pre-quota filtering
  • Per-key rate limits set to prevent single-project quota exhaustion
  • Spike protection enabled and alert rules configured
  • Quota monitoring via the /​stats_v2/ API endpoint
  • Custom fingerprinting reducing event duplication

Error Handling

ErrorCauseSolution
429 Too Many RequestsQuota exhausted for current billing periodLower sampleRate and tracesSampleRate, add patterns to ignoreErrors, enable per-key rate limits
Events silently droppedClient SDK respecting Retry-After headerReduce volume at source; SDK auto-recovers after cooldown expires
Critical errors missedsampleRate too lowUse beforeSend to force-return critical errors regardless of sampling; never filter payment/​auth errors
Quota exhausted early in periodNo per-project rate limitsSet hourly rate limits per client key to spread quota evenly across the billing period
Spike consuming entire quotaSpike protection not enabled or threshold too highEnable spike protection in organization settings; set up volume alert rules
401 Unauthorized on stats APIInvalid or expired auth tokenRegenerate token at Settings > Auth Tokens with org:read scope
Inbound filter not reducing volumeFilter configured but wrong error typeVerify filter targets correct category; browser extension filter only works for JS SDK errors
tracesSampler not calledtracesSampleRate takes precedence in some SDK versionsRemove tracesSampleRate when using tracesSampler — they conflict

Examples

Example 1 — Quota Monitoring Bash Script

#!/​usr/​bin/​env bash
# Monitor Sentry quota usage and alert if approaching limit
set -euo pipefail

ORG="${SENTRY_ORG:?Set SENTRY_ORG}"
TOKEN="${SENTRY_AUTH_TOKEN:?Set SENTRY_AUTH_TOKEN}"
THRESHOLD=${QUOTA_THRESHOLD:-80}  # Alert at 80% usage

accepted=$(curl -s -H "Authorization: Bearer $TOKEN" \
  "https://sentry.io/​api/​0/​organizations/​$ORG/​stats_v2/?field=sum(quantity)&groupBy=outcome&category=error&statsPeriod=1h&interval=1h" \
  | python3 -c "
import json, sys
data = json.load(sys.stdin)
for g in data.get('groups', []):
    if g['by'].get('outcome') == 'accepted':
        print(g['totals']['sum(quantity)']); break
else: print(0)")

echo "Accepted events (last hour): $accepted"
[ "$accepted" -gt "$THRESHOLD" ] && echo "WARNING: volume $accepted > threshold $THRESHOLD"

Example 2 — Enable All Inbound Filters via API

#!/​usr/​bin/​env bash
set -euo pipefail
BASE="https://sentry.io/​api/​0/​projects/​$SENTRY_ORG/​$SENTRY_PROJECT/​filters"
AUTH="Authorization: Bearer $SENTRY_AUTH_TOKEN"

for filter in legacy-browsers browser-extensions web-crawlers; do
  curl -s -X PUT -H "$AUTH" -H "Content-Type: application/​json" \
    -d '{"active": true}' "$BASE/​$filter/" && echo "Enabled: $filter"
done

Resources

Next Steps

  • Cost review: Query /​stats_v2/ weekly to track spend trends by category
  • Alert rules: Create Sentry alerts for volume spikes per project
  • Replay sampling: Apply replaysSessionSampleRate and replaysOnErrorSampleRate for session replay cost control
  • Server-side sampling: Explore Sentry Dynamic Sampling (server-side) for organization-wide policies
  • Audit ignoreErrors: Review quarterly — patterns may suppress real bugs as code evolves

More skills from jeremylongshore

openrouter-compliance-review logo
jeremylongshore/claude-code-plugins-plus-skills

openrouter-compliance-review

Review OpenRouter integration for regulatory compliance (SOC2, GDPR,

2.8K 0
View
maintainx-data-handling logo
jeremylongshore/claude-code-plugins-plus-skills

maintainx-data-handling

Data synchronization, ETL patterns, and data management for MaintainX.

2.8K 0
View
groq-core-workflow-a logo
jeremylongshore/claude-code-plugins-plus-skills

groq-core-workflow-a

Execute Groq primary workflow: chat completions with tool use and JSON

2.8K 0
View
validating-csrf-protection logo
jeremylongshore/claude-code-plugins-plus-skills

validating-csrf-protection

Validate CSRF protection implementations for security gaps. Use when

2.8K 0
View
api-contract logo
jeremylongshore/claude-code-plugins-plus-skills

api-contract

Configure this skill should be used when the user asks about "API contract",

2.8K 0
View
ideogram-incident-runbook logo
jeremylongshore/claude-code-plugins-plus-skills

ideogram-incident-runbook

Execute Ideogram incident response with triage, mitigation, and postmortem.

2.8K 0
View
gamma-sdk-patterns logo
jeremylongshore/claude-code-plugins-plus-skills

gamma-sdk-patterns

Reusable patterns for the Gamma REST API (no SDK exists).

2.8K 0
View
deepgram-sdk-patterns logo
jeremylongshore/claude-code-plugins-plus-skills

deepgram-sdk-patterns

Apply production-ready Deepgram SDK patterns for TypeScript and Python.

2.8K 0
View
openrouter-upgrade-migration logo
jeremylongshore/claude-code-plugins-plus-skills

openrouter-upgrade-migration

Migrate to OpenRouter from direct provider APIs or upgrade between SDK/model

2.8K 0
View
openrouter-common-errors logo
jeremylongshore/claude-code-plugins-plus-skills

openrouter-common-errors

Diagnose and fix common OpenRouter API errors. Use when encountering

2.8K 0
View
linear-cost-tuning logo
jeremylongshore/claude-code-plugins-plus-skills

linear-cost-tuning

Optimize Linear API usage, reduce unnecessary calls, and maximize

2.8K 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View