Connic can show which customers and product features drive model spend. Middleware writes an identifier such as customer_id into each agent run, and Connic groups token cost by that value on dashboards and the Token Usage page. This tutorial shows how to set the identifier, build a customer ranking and trend, and check what the totals leave out.
Tag each run with a customer or use case
Every agent run has a run context, a dictionary that middleware, tools, and tool hooks share during the run. Connic saves it with the run, and any key in it can group token cost later. The Run Context walkthrough covers the general mechanics; for cost attribution, one key per dimension is enough.
In this example, a SaaS backend sends requests for an in-app assistant to a webhook connector linked to the agent support-assistant. Each request carries the account that made it and the product feature it came from:
{
"customer_id": "acct_1042",
"use_case": "ticket-summary",
"message": "Summarize the open ticket for the support lead."
}The agent's middleware copies both values into context before the model call and passes only the message to the model:
from typing import Any
async def before(
content: dict[str, Any], context: dict[str, Any]
) -> dict[str, Any]:
payload = context["payload"]
context["customer_id"] = payload.get("customer_id") or "unattributed"
context["use_case"] = payload.get("use_case") or "unattributed"
return {"role": "user", "parts": [{"text": payload["message"]}]}Connic applies middleware/support-assistant.py to the agent named support-assistant and calls before() before the agent processes the request. The fallback unattributed gives requests without an ID their own visible group. Nested values work too: after context["customer"] = {"id": "acct_1042", "plan": "pro"}, the key customer.id groups by account.
The ID comes from the backend
The customer ID should come from a value the backend already trusts, such as the account behind the signed-in session. It should not come from the end user's message or from a tool argument the model fills in. The model can copy the wrong value, and a user's message can steer what the model writes. When middleware sets the ID from the payload, the model never handles it. The backend also sets use_case, based on the feature that sent the request.
Pass the ID to agents that other agents start
An agent started by another agent, through trigger_agent or as a step of a sequential agent, runs as its own run with its own context. It receives the input it is passed, not the caller's context. Its token cost is attributed only when that input carries the ID and the called agent's middleware copies it. The model fills in the payload of trigger_agent, so a tool hook is the reliable place to add the ID from context before the call. In a sequential agent, the first step receives the original request and each later step receives the previous step's output, so a later step only gets the ID if that output contains it.
Rank token cost by customer
Dashboards open from the Dashboards section of the project sidebar, and a dashboard in edit mode accepts new widgets. A Bar Chart configured like this ranks customers by spend:
- Group By: By Context
- Context Key:
customer_id - Metric: Token Cost
- Number of items to show: up to 20
The chart covers the dashboard's date range and the selected environment. A second Bar Chart with the key use_case ranks product features the same way. Token Usage as the metric ranks by tokens instead of cost, and Run Count by the number of runs. With Token Cost selected, the companion metric shows each value's token total next to its cost. The dashboard documentation lists the remaining widget options.
Include Judge Tokens is on by default. Connic counts each judge evaluation under the context value of the run it evaluated, so a customer whose runs are scored more often also carries that evaluation cost. With the option off, the chart leaves judge evaluations out.
Follow one customer over time
To see when one customer's spend changed, an Area Chart showing Token Cost with the filter expression context.customer_id == 'acct_1042' plots that customer's cost across the date range. A Stat Card with the Token Cost metric and the same filter shows the total.
To reuse these widgets for every customer, add an Input widget with the variable name customer and write the filter as context.customer_id == '{customer}'. Entering an account ID in the input then updates every widget that references it, and an empty input removes the condition. A select input can load its options from a project database collection, such as a list of customer accounts.
See monthly totals on the Token Usage page
For billing periods, the Token Usage page groups the same data by calendar month. Its By Context tab takes a context key, with dots for nested keys, and shows one bar per day, split by value. Below the chart, the ranking table lists every value for the month (the Bar Chart stops at 20) and splits each value's cost into Input, Output, Thinking, Cached, and Judge columns.
The same grouping is available outside the dashboard. The REST endpoints budgets/daily-cost and budgets/agent-ranking accept group_by=context.customer_id, which suits a monthly export into a separate billing system. Through Connic MCP, an AI client can ask which customers cost the most this month.
Check the numbers before acting on them
Before a ranking feeds a pricing decision or a customer conversation, a few checks show whether it covers the spend it should.
Unlabeled runs
A Bar Chart with Token Cost groups runs without the key as Unknown, and the Token Usage page shows them as (not set). With Token Usage or Run Count as the metric, the Bar Chart leaves those runs out. A large unlabeled share usually means an agent without the middleware, a called agent that never received the ID, or a key spelled differently between agents. With the unattributed fallback from the example, requests that arrive without an ID get their own label, so the remaining unlabeled share points to agents that never set the key.
Pricing coverage
When usage or pricing data is missing for some model calls, the widget shows a Cost unavailable marker. Its tooltip counts the calls with exact costs and names the affected models. A run that stops before the model sends its usage report can cause this. For BYOK models, the fix is a pricing entry in the project's Token Pricing settings. Connic recalculates recorded calls when pricing changes and prices each call with the entry that was valid when it ran, so an entry added later also covers earlier runs within its date range.
Currencies
connic/* models are priced in EUR, and BYOK models use the USD or EUR currency of their pricing entry. Connic keeps the two apart: a Bar Chart shows one ranking per currency, and the Token Usage table lists both amounts for each value. The Cost Display setting in Token Pricing, or a widget's Currency option, converts everything to EUR or USD with the European Central Bank's daily reference rate for each call date. Converted totals are estimates and can differ from provider invoices.
What token cost includes
Token cost covers model tokens, including those of judge evaluations unless Include Judge Tokens is off. Run starts, completed judge evaluations, runtime, web searches, extracted pages, browser sessions, storage, and retrieval are also debited from Project credit, but they appear on the Billing page, not in these reports. When a customer price has to cover the full cost of serving that customer, the token figure is the lower bound.
Deploy your agents on Connic, tag each run in middleware, and rank token cost by customer or use case on your own dashboards.
Start building with Connic