Usage and billing

Events per month per plan, exactly what is counted and when, what a quota answer looks like at ingest, and how to bring a Project back under its limit.

Analytics is metered on one number: events ingested per Project per month. Not users, not reports, not seats. This page says what counts, what does not, and what happens at the limit.

Figures verified 2026-09-28; plan limits can change, so read them from your Project rather than from here when the number matters.

Plans

A Project can also carry an explicit override in its settings (eventsPerMonth), which wins over the plan. null there means unlimited. That is how a bespoke arrangement is expressed without inventing a plan.

internal is the plan our own Projects run on.

What counts as an event

An event counts when it is committed to the Project's database, not when it is posted. The consequences are all in your favour:

  • Events dropped by validation (no identifier, a rejected name, a duplicate id) never count.
  • Events filtered as bot traffic never count.
  • A batch refused with 429 or 401 never counts.
  • A retry of an event you already sent, with the same id, does not count twice.

Imported events count, and are also tracked separately as imported, so a one-off backfill is visible as a backfill rather than as a sudden change in your traffic.

Every event counts once, whatever route it arrived on: /v1/ingest, /v1/import, the identity routes and the Mixpanel-compatible endpoint all share one counter. An identify with traits is two events, because it produces $identify and $set.

The month is calendar UTC. The counter resets at the start of each month; there is no rollover.

Reading your usage

curl -s https://t.intelligent.page/v1/projects/acme-shop/usage \
  -H 'Authorization: Bearer ipa_sec_REPLACE_ME'
{ "projectId": "acme-shop", "month": "2026-09", "events": 4821903, "imported": 1200000, "quota": 10000000 }

quota is null when the Project is unlimited. The same numbers are the bar in Project settings, and the full Project detail call (GET /v1/projects/:id) returns this month's usage alongside keys and members.

At the limit

Once the month's events reach the quota, keyed writes answer:

HTTP/1.1 429 Too Many Requests
{ "error": "quota_exceeded" }

Everything that follows is worth planning for before you meet it:

  • The refusal is at acceptance, so nothing is queued for you. An event refused here is gone unless your client retries it.
  • /v1/import stops at the first refused batch and returns what landed: { "accepted": 1500, "rejected": 500, "quota": { "exceeded": true }, "error": "quota_exceeded" }. Resume from the event after the accepted head.
  • The Mixpanel-compatible routes answer their own 429 shape, body 0, or {"status":0,"error":"rate limit exceeded"} with verbose=1.
  • Browsers of our own app stay silent with 204, because a quota problem must not become an error in a visitor's console.
  • Reads are unaffected. Every report you already have keeps working.

Do not confuse it with the other 429. rate_limited means 6 000 events a minute on one key and clears itself within the minute; quota_exceeded means the month and does not. See Limits and validation.

Bringing usage down

In the order that usually pays:

  1. Send the automatic events you actually use. Our SDKs send a $pageview per page() call and nothing else unless you ask: data-page="0" on the script tag suppresses the automatic first pageview, and a router that calls page() on every history change on a site with many small route changes can double your volume on its own. They are real events on your plan.
  2. Reconsider autocapture. autocapture: false turns it off. $autocapture on a busy application can outnumber every named event you have. It is the right default while you are learning what to instrument and an expensive habit afterwards.
  3. Drop the events nobody opens. Look at the event catalog for names with high volume and no report, board or funnel using them.
  4. Stop double-sending. A page view from both the SDK and your router, or an order from both the storefront pixel and the webhook, is the classic doubling. The connectors are built so the server-side event is authoritative.
  5. Batch on the server. Batching does not change the count, but it makes the rate limit far easier to live inside.

What does not help: sending fewer properties. Metering is per event, not per property or per byte.

Changing plan

Plan changes are made by us, not through the API: a plan change is a billing change. Ask through your usual contact with the Project id and the plan you want.

An override on a single Project (eventsPerMonth in settings) is also ours to set. Anyone managing a Project can read it back but should not expect to raise it themselves.

Growing past a plan

  • More keys, not a bigger limit. The 6 000 events a minute limit is per key. A key per service gives each one its own bucket and tells you which service is noisy.
  • One Project per product, not per environment mistake. Every Project has its own quota, and its own database. Splitting a product across Projects to dodge a quota also splits every report.
  • Import out of hours. A backfill competes with live traffic for both the rate limit and the quota. Run it when neither matters.

Next