2026-07-28T14:37:37.994Z
n8n AI Agent Token Usage: Build a Call Ledger
Aggregate every n8n model call with stable identities, retry accounting, nested-work attribution, and explicit usage coverage.
The reliable way to measure n8n AI Agent token usage is to create one ledger row for each model invocation, then aggregate those rows by verified outcome. Do not recursively add every tokenUsage object in an execution export. That can count a repeated execution snapshot twice, count usage mirrored by a parent node again, or mix estimated tokens into a provider reported total. A useful default has four rules: 1. collect usage only from model call output; 2. identify an observation with execution, node, run, item, and provider call fields; 3. keep retries and nested calls as real usage, but group them under one logicalOutcomeId ; 4. report provider usage and estimates in separate columns, with coverage beside the total. That design answers the operational question behind the search: not merely “where is the number?”, but “what did this successful workflow really consume, and how much of that number is known?” Use a call ledger, not a recursive sum Current n8n source makes the first accounting boundary visible. Its TokenUsage type contains promptTokens , completionTokens , and totalTokens , with optional cache read, reasoning, and provider specific metadata. In the current LangChain tracing implementation, n8n writes tokenUsage when the provider supplied counts. If it cannot obtain actual completion usage, it writes tokenUsageEstimate instead. Those fields are not interchangeable. An estimate can help with a warning threshold, but it is not provider reported usage or a billing receipt. The tracing implementation also writes model output on the AI language model connection. That gives a collector a safer starting point than searching every property beneath the AI Agent node. Use a row shaped like this: The identifiers solve different problems. n8n documents $execution.id as the unique workflow execution ID and $runIndex as the zero based count of times the current node ran. nodeName and itemIndex separate calls inside that execution. A provider response ID, when available, makes the identity stronger. Build the deduplication key from the observation identity: If a provider does not expose a call ID, retain an explicit providerCallId: null and use the strongest stable local identity available. Do not hash the prompt or response as the primary key: identical prompts can be legitimate separate calls, and storing content creates an avoidable privacy problem. The event key answers “have I already recorded this call?” It does not answer “which user visible result did this call contribute to?” That requires a second key. Generate logicalOutcomeId at workflow ingress, preserve it through retries, and pass it into every sub workflow. The value can be an opaque job or request ID; it should not contain a prompt, email address, or other sensitive content. Keep retries, but deduplicate repeated observations Retries are not duplicate usage. A failed attempt that reached a model consumed tokens even when the later attempt succeeded. Dropping it makes an unreliable workflow look cheaper precisely when retry waste is growing. Repeated observations are different. Suppose a polling collector fetches execution 811 , then fetches the same completed execution again. Those are two snapshots of the same calls. Likewise, a parent AI Agent output may contain a diagnostic copy of model usage that already exists in the model node’s AI language model output. Those copies should not create new ledger rows. The rule is narrow: same eventKey seen again: update freshness or provenance, but do not add tokens; different provider call in the same node run: keep it; different run index: keep it; a retry execution with a different execution ID: keep it; a nested execution with a different execution ID: keep it; the same call mirrored under a non model connection: ignore the mirror. I tested that rule with a synthetic detailed execution fixture. It contains four snapshots: a failed execution, the same failed snapshot a second time, a successful retry, and a nested child execution. Parent nodes mirror actual usage, and one model call exposes only an estimate. Measurement Result : Visible tokenUsage objects found by recursive search 12 Naive recursive actual token sum 6,020 Unique provider reported model calls 4 Actual prompt tokens 1,670 Actual completion tokens 280 Actual total tokens 1,950 Estimate only calls 1 Estimated tokens, reported separately 120 Actual call coverage 80% The recursive result was 3.09× the semantic ledger total. It counted the duplicated execution snapshot and parent node mirrors. The ledger did not discard the failed attempt: that attempt contributed 1,060 of the 1,950 actual tokens for the eventual outcome, or 54.4% in this fixture. That distinction matters. Calling the first attempt a duplicate would understate real usage by more than half. Calling every visible copy a new invocation would overstate usage by more than three times. Identity resolves both errors. The nested child contributed another 350 actual tokens. It retained its own execution ID and event key, so it could not collide with its parent. Sharing logicalOutcomeId: support ticket 42 attributed that work to the same intended result. The estimate only call stayed outside the actual total. Adding it would produce 2,070 tokens, but that more precise looking number would hide a weaker fact: one of five calls lacked provider reported usage. The dashboard should show actualTotalTokens: 1950 , estimatedTotalTokens: 120 , and actualCoveragePct: 80 , not one unlabeled sum. You can reproduce the comparison by saving the execution shape above as a fixture and running the ledger loop shown below. The important part is the decision rule, not these synthetic percentages; production ratios depend on the workflow, model nodes, providers, retry policy, and data retention. Extract detailed execution data with coverage controls n8n’s public API contract for retrieving one execution accepts includeData . The related execution schema says detailed data is included only when that flag is true. A collector can therefore fetch a completed execution with a request shaped like: Keep the key server side, request the minimum required execution data, and do not copy prompts or response bodies into the token ledger. The collector needs identifiers, status, run structure, usage fields, and coverage evidence—not conversation content. Then walk data.resultData.runData node by node: Treat this as a versioned adapter, not a timeless parser. Validate the actual output of every model node type you deploy. A newer n8n source snapshot can expose tracing metadata such as llm.tokens.in , llm.tokens.out , llm.tokens.total , and an estimated flag, but older or provider specific nodes may differ. Preserve unknown fields for diagnosis and fail coverage visibly when a model run has no recognized usage. Detailed data can also be unavailable. n8n’s execution endpoint documents a configured display size limit, and the product supports execution data redaction. Retention settings can remove old execution bodies. A missing body therefore means “usage unavailable,” not “zero tokens.” Record coverage counters for every collection window: The denominator must include recognized model invocations without usage. Otherwise a broken collector can report 100% coverage over the few calls it happened to parse. Aggregate per verified outcome A token total is useful only beside the work it bought. For each logicalOutcomeId , aggregate: actual input, output, cache, reasoning, and total tokens when those fields exist; estimated tokens in separate columns; distinct call and execution counts; failed attempt tokens; nested execution tokens; collection coverage and last seen time; one deterministic outcome receipt. The receipt depends on the workflow. A support workflow might require a ticket update with the expected status and destination ID. A document workflow might require an object at a known storage key plus a content hash. A deployment workflow might require tests, deployment state, and a public health response. “The last n8n execution succeeded” is activity evidence; it does not prove the requested external effect. Use three views rather than one overloaded number: 1. Invocation view for debugging an individual model call. 2. Execution view for node runs, status, and retry relationships. 3. Outcome view for all attempts and nested work that produced—or failed to produce—the deliverable. Only the outcome view supports a statement such as “this verified ticket update used 1,950 provider reported tokens, plus 120 estimated tokens, across five model calls with 80% actual call coverage.” It also exposes a failed outcome with high usage instead of averaging it into apparently healthy traffic. If you later calculate money, join the ledger to a dated model price table using provider, model, region or service tier when relevant, and token class. Do not infer historical cost from today’s price. Do not price estimate only rows as if they were reconciled billing data. Label the result estimated until it matches a provider invoice or authoritative cost record. Promote the dashboard only when the audit passes Before trusting an n8n AI Agent token dashboard, run a controlled workflow with one known model call, one repeated node run, one forced retry, and one nested sub workflow. Inspect the detailed execution data and require these checks: every expected invocation produces exactly one ledger row; fetching the same execution twice does not change totals; a failed attempt remains in the outcome total; the child execution appears once under the parent outcome; actual, estimated, and missing usage remain separate; deleting or redacting execution data lowers coverage instead of producing zeros; the outcome receipt fails when the external deliverable is absent. The fixture here passed those accounting checks, but it does not prove compatibility with every n8n node or provider. That is the boundary: the ledger design is reusable; the adapter is version specific. Sidewisp is intended to make time and budget efficiency part of AI agent health alongside availability, execution, memory, tools, and outcomes. Token usage and estimated cost analytics are planned, but that capability is not shipped today. Sidewisp is currently in private preview. Until such a health layer is connected, keep the ledger close to n8n, collect the minimum metadata needed, and promote no optimization unless both usage and the verified outcome improve.