Loading page...Загружаем страницу...正在加载页面...
AtlasRepo

How to auto-categorise bank transactions with n8n and Gemini (free tier)

Description and use

A repeatable, safe, free workflow that auto-categorises bank transactions by merchant rather than by row, using Gemini free tier with structured output parsing and review flags for duplicates.

Problem

Manual monthly categorisation of 200+ bank CSV rows into categories like 'Software', 'Travel', 'Bank fees' is dull and error-prable.

Outcome

A repeatable, safe, free workflow that auto-categorises bank transactions by merchant rather than by row, using Gemini free tier with structured output parsing and review flags for duplicates.

Workflow

  • Upload CSV via n8n Form with currency and date format dropdown
  • Extract from File node reads CSV rows
  • Code node normalises transactions: guesses columns from header patterns, cleans merchant names, builds stable IDs per row
  • Code node groups unique merchants, batches at 40 merchants per call to stay on free tier
  • Basic LLM Chain with Gemini and Structured Output Parser categorises merchants
  • Code node maps categories back to rows and adds review flags for possible duplicates
  • Google Sheets node appends or updates by txn_id
  • Form completion page shows summary

Evidence

If you run a small business or freelance, you probably know the monthly ritual: export the bank statement as CSV, open it in a spreadsheet, and type 'Software', 'Travel', 'Bank fees' next to two hundred rows of CARD PAYMENT TO ADOBE *CREATIVE 12/09 REF 88812.

Source

This post walks through how I built an n8n workflow that takes any bank CSV, categorises every transaction with Google Gemini (free tier), and upserts the results into Google Sheets with review flags.

Source

Everything is built-in n8n nodes. No community nodes, no vector database, no paid API.

Source

Rather than asking users to map columns, a Code node guesses the columns from header patterns, collecting headers from every row (n8n's CSV reader drops empty cells, so the first row does not always have every key)

Source

The date format is the one thing you genuinely cannot guess (is 03/04/2026 March or April?), so the upload form asks for it in a dropdown.

Source

This is the trick that keeps it on the free tier. A typical month of 300 transactions might only have 60 unique merchants: Tesco ten times, Stripe payouts twenty times, AWS once. So instead of sending rows to the model, a Code node groups by merchant and sends 40 merchants per call

Source

CARD PAYMENT TO ADOBE *CREATIVE 12/09 REF 88812 becomes ADOBE. That cleaned name matters for the next step.

Source

If two rows are genuinely identical, the second gets a -2 suffix, which later becomes a 'possible duplicate' flag.

Source

  • Record date: 2026-10-23T15:26:17.555Z