How to Cut n8n AI Agent Costs with Filtering
Two bills, one cause: traffic that was never a real question.
- Duplicates ~18%, bursts ~27%, bot/junk ~7% of inbound — none worth a run.
- Filtering inside n8n saves tokens; the execution is already counted.
- Filtering in front cuts executions by ~43% on a projected 10k/mo agent.
The problem
- An n8n AI agent runs up two bills at once — n8n executions and LLM tokens.
- Both scale with how many messages hit the agent, not how many were worth answering.
- Duplicates, bursts and bot junk get paid for twice: once as an execution, once as tokens.
The solution
You can act in only two spots, and they save different things:
- Inside n8n: filter after the Webhook node → you save the tokens, not the execution.
- In front of n8n: filter before the Webhook URL → the execution never starts, so you save both.
Drop duplicates, merge bursts into one message, reject bots — then let only real intents reach the model.
Result: n8n runs, and your LLM reads, only clean, real events.
An n8n AI agent runs up two bills at once: the executions n8n charges for, and the tokens your LLM charges for. Both scale with how many messages hit the agent — not with how many were worth answering. Cut the junk that reaches the agent and you cut n8n AI agent costs on both lines. Here is how, and the two places you can do it.
Where n8n AI agent costs actually come from
Three kinds of traffic drive the waste:
- Duplicates. Senders retry on timeout, so one event triggers the agent two or three times — and the LLM re-reads the same message each time.
- Bursts. A user sends “hi”, “can you”, “help me”, “with my order” as four messages — four executions and four LLM calls for one intent.
- Junk. Bots and malformed payloads hit the Webhook node and, if you’re not careful, still reach the model.
The manual fix (Option 1)
Skip the model inside n8n. Add an IF or Switch node right after the Webhook and route junk and duplicates around the AI Agent node. Drop retries with the Remove Duplicates node, validate the payload, and only let real messages reach the model.
On a gateway, duplicates, bursts and junk are dropped before n8n triggers at all.
The catch: inside n8n only moves one of the two bills
Filtering inside n8n trims the token line but leaves the execution line untouched, and you rebuild the IF/Switch/Remove-Duplicates branch — plus burst buffering — in every workflow. To move the execution count, the filter has to live before the Webhook URL.
Place a gateway layer (Option 2) — faster
Point senders at a message gateway instead of the Webhook URL directly. It drops duplicates, merges a burst into one message, and rejects bots before forwarding. n8n only ever triggers on clean, real events — one execution, one LLM call, per actual intent.
The gateway POSTs a _portarus envelope to your Webhook URL, and the decision travels inside it. Here a four-message burst was merged into one delivery, so n8n sees one execution and the agent reads one clean message:
{
"_portarus": {
"user_id": "wa_5215512345678",
"message": "hi can you help me with my order #4471",
"timestamp": "2026-10-04T14:22:09Z",
"language": "eng",
"status": { "processed": true, "reasons": [] },
"security": {
"result": "pass",
"status": "analyzed",
"rate_limit": "pass",
"dedup": "pass",
"max_tokens": "pass",
"token_count": 11
},
"messages": {
"quantity": 4,
"time_window_seconds": 30,
"items": [
{ "content": "hi", "received_at": "2026-10-04T14:22:01Z" },
{ "content": "can you help me", "received_at": "2026-10-04T14:22:04Z" },
{ "content": "with my order", "received_at": "2026-10-04T14:22:07Z" },
{ "content": "#4471", "received_at": "2026-10-04T14:22:09Z" }
]
},
"keyword_routing": { "matched": false, "route": null },
"meta": { "v": 2, "trace_id": "b1f0…" }
}
}
The agent reads message and answers once: security.result: "pass" with every filter clean, and messages.quantity: 4 shows the burst it collapsed. Had a duplicate or token flood been caught, that filter would read "abuse" and result would flip to "blocked". By default blocked traffic stops at the gateway and never costs an execution, but you can opt to receive blocked messages too — the same envelope arrives with status.processed: false, so your agent decides what to do instead of paying to run on them blindly.
What you’d save — a projection
The numbers below are a projection, not a measured study. They apply the duplicate, burst, and junk rates documented across this cluster to a hypothetical agent receiving 10,000 inbound messages a month:
| Traffic type | Share | Fix 1 (inside) | Fix 2 (in front) |
|---|---|---|---|
| Duplicates | ~18% | ✅ Tokens saved, execution counted | ✅ Never triggers |
| Bursts (merged) | ~27% | ⚠️ One execution each, model skipped partially | ✅ Merged into one |
| Bot / junk | ~7% | ⚠️ Execution counted | ✅ Rejected at the edge |
| Executions/month | — | ~10,000 | ~5,700 (≈43% fewer) |
Fix 1 trims your token bill; only Fix 2 moves the execution line. Measure your own rates before trusting any percentage.
Option 1 (inside) vs Option 2 (in front)
| Filter inside n8n | Filter in front (gateway) | |
|---|---|---|
| LLM token cost | ✓Saved | ✓Saved |
| n8n execution count | ✕Already counted | ✓Never triggers |
| Bursts merged | ~Model skipped, 4 execs | ✓One execution |
| Bot / junk | ~Execution counted | ✓Rejected at the edge |
| Every workflow | ~Rebuild the branch each time | ✓One layer, all flows |
| Control of internals | ✓Full | ~Abstracted away |
Usually duplicates and bursts drive most of the cost — deduplicating and merging fragments cut both bills at once. It’s one piece of message quality for AI agents, and only a gateway reduces the execution count itself.
If option 2 sounds more like you, here’s the short version of how to set it up: filter the junk before n8n triggers →.
Either way — go make n8n run only on real questions.
Thanks for reading. 👋
Orlando. -
Orlando Quijada
Technologist with 15+ years of experience. Developer, SaaS tester, and AI collaboration & optimization specialist. Currently contributing at portarus.com.
Written on