If your n8n workflow is calling an LLM and you want to track tokens and costs, extract the token usage object from the node output (usually at {{$json["usage"]}} for OpenAI style responses), normalise fields into top level JSON, then calculate cost using a price per 1k tokens and pass the result to subsequent nodes.
Why token usage arrives the way it does
Most LLM APIs return token metadata in a response field called usage containing prompt_tokens, completion_tokens and total_tokens. When you call a model via n8n the raw response becomes the node output. If you used the HTTP Request node to call OpenAI Chat Completions or the built in OpenAI integration, you will usually find the usage object at items[0].json.usage. Other integrations or vendors sometimes nest it under data or change names, which is why you must normalise before logging or costing.
n8n access token usage metadata: quick reference
Common JSON paths you will use in n8n expressions or the Code node:
- OpenAI / HTTP Request node standard response:
{{$json["usage"]["total_tokens"]}},{{$json["usage"]["prompt_tokens"]}} - If API returned an outer
dataobject:{{$json["data"]["usage"]["total_tokens"]}} - n8n OpenAI integration sometimes returns the full API JSON at
items[0].json, so use the same paths above
Use these expressions in a Set node to expose token fields as top level properties so subsequent nodes can read {{$json["llm_total_tokens"]}} or similar.
Step by step fix: extract, normalise, calculate, log
- Make the LLM call with the node you use, for example
HTTP Requestor your OpenAI/LLM node. Confirm a successful run and open the Execution view to inspect the raw JSON output. - Locate the token usage object. Look for
usageat the root or underdata. The usual OpenAI shape is:{ "usage": {"prompt_tokens": 10, "completion_tokens": 40, "total_tokens": 50} } - Add a
Codenode directly after the LLM node to normalise all possible shapes and compute cost. This keeps logic in one place and is reusable. See the sample Code node below. - Return a top level object with fields like
llm_model,llm_prompt_tokens,llm_completion_tokens,llm_total_tokens,llm_costandllm_currency. Subsequent nodes can reference them with expressions like{{$json["llm_total_tokens"]}}. - Use a Set node or a database write step to append the object to your usage log. Store the model, timestamp and cost per request to enable aggregation and monthly billing alerts.
Reusable subworkflow pattern and Code node snippet
Create a subworkflow or reusable workflow that takes the LLM node output and returns a single normalized item. Drop a Code node in and paste this snippet. It handles common shapes and calculates cost using a price-per-1000-tokens map you control.
// Code node (JavaScript)
const pricePerThousand = {
"gpt-3.5-turbo": 0.002, // set your own values
"gpt-4": 0.03,
"default": 0.01
};
function safeGet(obj, path) {
return path.reduce((o, k) => (o && o[k] !== undefined) ? o[k] : undefined, obj);
}
const out = [];
for (const item of items) {
const json = item.json;
// Try common places for usage and model
const usage = json.usage || safeGet(json, ["data", "usage"]) || safeGet(json, ["response", "usage"]);
const model = json.model || safeGet(json, ["data", "model"]) || safeGet(json, ["model"]) || "unknown";
const prompt_tokens = usage && usage.prompt_tokens ? usage.prompt_tokens : null;
const completion_tokens = usage && usage.completion_tokens ? usage.completion_tokens : null;
const total_tokens = usage && usage.total_tokens ? usage.total_tokens : null;
const priceKey = model in pricePerThousand ? model : "default";
const rate = pricePerThousand[priceKey];
const cost = (total_tokens && rate) ? (total_tokens / 1000) * rate : null;
out.push({
json: {
llm_model: model,
llm_prompt_tokens: prompt_tokens,
llm_completion_tokens: completion_tokens,
llm_total_tokens: total_tokens,
llm_cost: cost,
llm_currency: "USD"
}
});
}
return out;
Adjust pricePerThousand to current rates you want to use. This Code node returns a clean object other nodes can use directly.
Tool specific notes: n8n expressions and Set node wiring
In a Set node you can copy the values created by the Code node into fields you want to persist. For example add a field total_tokens with value {{$json["llm_total_tokens"]}}. If you call the LLM with the HTTP Request node and do not want JavaScript, map {{$json["usage"]["total_tokens"]}} directly in the Set node but be aware of nested shapes.
If you use Make.com or Zapier instead, the same principles apply: locate the usage object in the API response, normalise it to well named fields, compute cost using a small multiplier, and write to storage. In Make.com build a module to parse JSON and in Zapier use a Code by Zapier step with similar JS logic.
How to stop surprises and n8n track llm tokens reliably
1) Always normalise the usage data immediately after the LLM call. 2) Store each request row with model name, tokens and computed cost, so you can reconcile totals. 3) Add a weekly or daily aggregation workflow that sums llm_total_tokens and alerts when thresholds are reached. 4) Add a fallback in your Code node so if usage is missing you flag the row for manual review.
Use the Automation execution view to inspect raw responses for any vendor. If you see sudden token spikes, check for loops that re-send prompts or incorrect streaming behaviour. Community threads discuss sudden usage drops and spikes, see the n8n forum thread on extracting usage for context and the AI assistant spike thread for examples of unexpected billing changes.
When to get help
If the response JSON does not contain any usage object, check the API docs for your model or the integration you used. For OpenAI calls made through the HTTP Request node, verify you hit the Chat Completions or Responses endpoint that returns usage. If you still cannot find the metadata, post the trimmed JSON (hide keys) to the n8n community or the OpenAI developer forum with a clear question. Useful threads include the n8n forum request about accessing token usage metadata and the community discussion about sudden usage spikes.
Want a starter template? Save the Code node snippet above as a reusable workflow and reference it from new projects. That pattern makes it trivial to n8n calculate llm costs across multiple models and keep a simple ledger of spend.
Learn to build automations like this with Automate Naija.
Frequently asked questions
Where exactly do I find token usage in an n8n LLM node output?
Look for a JSON object called usage in the node output. With OpenAI style responses it is usually at items[0].json.usage and contains prompt_tokens , completion_tokens and total_tokens . Some integrations nest it under data so inspect the raw JSON in the Execution view.
How do I pass token counts to downstream nodes in n8n?
Normalize the usage fields immediately after the LLM call using a Code node or a Set node. Return top level keys like llm_total_tokens . Subsequent nodes can read them with expressions like {{$json["llm_total_tokens"]}} .
How do I calculate per-request cost for different models?
Store a price per 1000 tokens map for the models you use, then compute cost as (total_tokens / 1000) * pricePerThousand[model] . Put this logic in a reusable Code node so all workflows use the same rates and output a consistent llm_cost field.
What if the usage metadata is missing or suddenly spikes?
If usage is missing, confirm you are using an endpoint that returns it. If you see spikes, check for accidental loops, duplicated requests, or streaming settings that cause retries. If you cannot resolve it, share a redacted example in the n8n community thread for help.
Build it with us. The community is free and the build track teaches this kind of automation week by week: see pricing or join the community.