This guide is about sending events efficiently at scale: how to batch, how the limits compose, and how to retry without double-counting.

The limits, composed

Three limits apply to POST /v1-batch:

LimitValue
Events / request100
Bytes / request1 MiB (1,048,576)
Request rate100 requests / minute per (org, IP)

At the maximum batch size, the per-minute rate cap works out to ~10,000 events per minute per IP (100 requests × 100 events). The rate limit is keyed per (organization, IP): browser and mobile clients each have their own IP, so the cap is effectively per-client, while a single server sending from one IP shares one bucket.

On top of the per-IP limit, /v1-batch also enforces a coarse 2000 requests per minute per organization (aggregated across all IPs) as an anti-abuse backstop — an org fanning out across many IPs hits this ceiling and gets a 429 (Rate limit exceeded: max 2000 requests per minute per org, with Retry-After). Most integrations never approach it.

Batch, don't drip

Accumulate events client-side and flush them in batches rather than one request per event. Aim for batches of up to 100 events that stay under 1 MiB — flush on a size threshold, a time interval, or page unload, whichever comes first.

If a batch would exceed 1 MiB (fat properties / context payloads can get there well before 100 events), split it by bytes, not just count. The 413 response carries a machine-readable limit_bytes so you can resize programmatically — see Errors & rate limits.

Per-event limits

Beyond the per-request caps, two per-event limits matter at scale:

  • Event name ≤ 200 characters. A track event whose event name exceeds 200 chars is rejected on its own (event name too long) while the rest of the batch ingests. Keep names short and from a fixed vocabulary.
  • Property soft-caps (warn-only). Very large properties / traits — more than ~300 keys, a value over ~32 KiB, or nesting deeper than 8 levels — are still stored but emit a server-side warning. Trim fat payloads to keep events lean; only the 1 MiB body and 100-event batch caps are hard rejections.

Idempotent retries

Every event carries a unique messageId, and the server de-duplicates on it. So a retried request is safe: an event that already landed won't be counted twice.

  • Reuse the same messageId when you retry — don't mint a new one.
  • Retry the per-minute rate-limit 429 (honour Retry-After) and 5xx / network errors with exponential backoff and jitter. A monthly-quota 429 shouldn't be retried naively — see Rate limit vs. monthly quota below.
  • Don't retry other 4xx — fix the request instead.
  • If you use the Web SDK: it treats 429 as permanent and does not honour Retry-After today, so the rate-limit-retry advice above is for direct-REST clients. Heavy senders that need rate-limit retry should post to /v1-batch directly.

The full policy is on the Errors & rate limits page.

Rate limit vs. monthly quota

Two different 429s, two different causes:

  • Per-minute rate limit — you're sending too fast. Back off for the window (Retry-After tells you how long) and resume.
  • Monthly event quota — your plan's event allowance for the month is exhausted. Backing off won't help; ingestion resumes when the monthly counter resets or you upgrade.

Watch the failed / errors fields on every 200, too — a 200 with failed > 0 means some events in the batch were rejected even though the request succeeded.

Next

Last updated 2026-06-10

We use cookies for analytics — to understand how visitors use UMAP360 and improve the product. Essential cookies (session, forms) always run; analytics cookies wait for your call. See cookie policy.