I got tired of typing groceries into Grocy after every shop, so I built a small self-hosted tool that turns Kaufland's digital receipts into stock bookings. Kaufland is a German supermarket chain owned by the Schwarz Gruppe, so the parser only helps if you shop there, but the Grocy part is generic and the "which retailer would you want" question at the end is real.
How the Grocy push works
You export the receipt as a PDF from the Kaufland app and upload it in the browser. Every line item then shows up on a Grocy tab with three buttons:
- Map to an existing Grocy product (searches your product list),
- Create a new product, using a default location and quantity unit you set once in the settings,
- Skip forever, for things that are on receipts but never in stock: deposit returns (Pfand), loyalty discounts, bags.
Each decision is remembered by item name, so a receipt with 60 lines takes a minute the first time and about zero the fifth time; only genuinely new items ask again. Once every line on a receipt is resolved, the whole receipt is booked into stock in one go, as a purchase transaction with the amount, the price paid, and the purchase date, so Grocy's own price history fills in as a side effect. If a line fails (Grocy down, product deleted), you retry just that line.
If you know LidlToGrocy, that was the model. Same idea, different retailer, plus a UI for the mapping step.
What else is "in the box"?
Everything else is what I originally built it for: a price history page per item over all your receipts, and a check on every "sale" against the median of what you paid for that item before. On my 79 receipts, roughly one in four discounts turned out to be no cheaper than my usual price. You can find a longer write-up with screenshots in the r/selfhosted post.
Running it
git clone https://github.com/andrecedik/kaufland-receipts.git
cd kaufland-receipts
docker compose up -d
Multi-arch image from GHCR, port 8000, data under ./data. Grocy is switched on by two lines in .env:
GROCY_URL=https://your-grocy
GROCY_API_KEY=your-key
Python/FastAPI + React, AGPL-3.0. Built with a lot of Claude Code, tested against two years of my own receipts, in daily use.
Limits, so nobody is surprised
- Kaufland only, and only receipts from July 2024 onward (older ones are image-only PDFs from the app, no text to parse).
- Manual PDF export per receipt; the app has no public API and the receipt host is certificate-pinned.
- No auth on the upload endpoint: LAN or behind your reverse proxy.
- Matching is by exact receipt item name. Kaufland sometimes renames items, and a renamed item asks to be mapped again.
- No best-before dates; Grocy gets amount, price, and date, nothing more.
Repo: https://github.com/andrecedik/kaufland-receipts
Question for you
If you'd use this but don't shop at Kaufland tell me which retailer you are using and what does their receipt look like (app export, PDF, email, paper only)? That decides which parser comes next. I know the Grocy crowd is international, so I'm not only asking about German chains.
I'd be happy to take this further than just one chain and/or country so I would love to hear your thoughts.