Usage metering
Neens records what every tenant is doing, feature by feature, as durable integer counters. This powers a per-workspace Usage view for admins.
Counters are integer aggregates only — a usage row is (company, project, feature, day, connection, count). No trace, prompt, or response content is ever stored or transmitted by
metering. That invariant is what lets the aggregates roll up for billing and fleet operations
while every byte of content stays inside the tenant.
At a glance
| Where (tenant) | Usage in the left nav — per-agent, per-feature counts and trends |
| Where (operator) | Usage in the operator console — the same counts, fleet-wide |
| Who can use it | Any workspace member sees their workspace’s usage; the operator sees every tenant |
| Key API routes | GET /usage, GET /usage/summary; operator: GET /admin/usage, GET /admin/usage/companies |
| What’s stored | Integer counts per (company, project, feature, day, connection) — never content |
| Rolls up | Nightly into the cross-tenant rollup table |
Metering is on by default and needs no configuration. The full tenant and operator Usage views work with nothing to set up.
What’s metered
Every metered feature belongs to one category. Ingestion and LLM counters are recorded on the hot path as traces arrive and models are called; compute, curation, and storage counters are recorded when the corresponding job runs or artifact is created.
| Category | Features |
|---|---|
| Ingestion | Traces, sessions, spans, and tool calls ingested |
| LLM | LLM calls, input tokens, output tokens, and spend — sliced per connection |
| Compute | Clustering runs, issue-classification jobs, eval runs, eval targets scored, pre-prod eval runs, enrichment runs, scenario generations, remediations generated, playground runs, chat messages, MCP calls |
| Curation | Annotations, judges, datasets, dashboards, prompt versions, and scores created |
| Storage | Storage used (a point-in-time level, not a running total) |
Spend is stored as integer micro-dollars (1 USD = 1,000,000) so it stays an integer aggregate like every other counter and can roll up and cross the operator boundary without ever becoming a floating-point or free-text field. The Usage view renders it back as dollars.
Most counters accumulate — each event adds to that day’s running total. Storage used is the exception: it’s a level metric, so each reading overwrites the day’s value (the latest reading is the truth, not the sum).
Tenant usage view
An admin (or any member) opens Usage to see their workspace’s activity. Behind it:
GET /usagereturns per-feature (or per-day, per-agent, per-connection) integer totals for a time window, scoped to the caller’s workspace.GET /usage/summaryreturns the per-feature totals plus a daily timeseries for the headline features (traces ingested, LLM calls, LLM spend).
The window defaults to the last 30 days; pass since/until (YYYY-MM-DD) to change it. Because
the store is scoped by tenant, one workspace can never see another’s counters.
Operator fleet view
An operator opens Usage in the operator console to see the same counts across every tenant — the usage-based cost basis for the fleet.
GET /admin/usagereads the cross-tenant rollup, grouped bycompany,feature,day, orproject(operator-gated; an agent key is always denied).GET /admin/usage/companieslists per-company totals with each company’s name, tier, and status.
The operator view reads the rollup table, which the nightly job keeps in sync (below) — so it’s fast and doesn’t fan out live queries across every tenant schema.
How it works
Counters are recorded locally
As traces are ingested, LLM calls run, jobs execute, and artifacts are created, Neens increments the matching counter in a durable per-tenant table. Recording is best-effort and never blocks or breaks the operation it’s counting.
The nightly rollup folds tenants into the operator view
Once a day, a leader-elected job reads each tenant’s counters and upserts them into the operator’s cross-tenant rollup table. The upsert is idempotent — re-running the same day’s rollup overwrites the same rows, so it never double-counts. This is what the operator fleet view reads.
The rollup runs under leader election, so a scaled deployment with several app replicas elects exactly one replica to run it — you never get N× rollups.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Operator Usage view lags the tenant view | The rollup runs nightly | Wait for the next nightly rollup, or re-check after it fires |
| Usage view is empty on a brand-new workspace | No activity has been metered yet | Ingest traces / run evals; counters accrue as you use the product |
See also: Cost & model pricing (the per-model prices behind every dollar figure — a separate signal from these feature counters) and Data retention and Erasure.