Unofficial, agent-friendly CLI for online supermarkets, behind one interface. Pick a store, search the catalog, read prices, price a shopping list.
grocery is a single Go binary that talks to several online supermarkets through one set of commands. You choose a store with --store (or GROCERY_STORE), and every store is an adapter behind a common interface, so the commands never change. Every command supports --json (data to stdout, logs to stderr) and --toon (fewer tokens, for LLMs).
It's not a scraper for "any supermarket on earth" — it's an explicit registry of stores that each have a verified adapter, spanning several backend types (guest APIs, server-rendered catalogs, Algolia search, WooCommerce, and a few bespoke REST/HTML sources). Run grocery stores to see what's supported right now.
For a one-off shop, the store's own app is easier. grocery earns its place when you want to do things an app can't:
- Compare prices across stores. One query, same basket, across every chain in your area — "who's cheapest for my weekly list, Mercadona or Consum or DIA?" No single app shows you that; each only knows its own prices.
- Give an agent a clean primitive. The
--json/--toonoutput is there so an LLM can drive the shop: hand it a shopping list (or a photo of your fridge), have it price the items across your stores and, for stores with an account, fill your cart (see Shopping cart). - Track prices over time. Run it on a schedule, log what your regular items cost, and watch how prices move.
Reads need no account and work for every store. Several stores also support filling your own cart (Mercadona, Bonpreu, Continente, Pingo Doce, Auchan, Scotts, PAVI/PAMA, Tesco, Sainsbury's); the CLI never places the order. Matching "the same product" across chains is fuzzy — batch and compare score search hits against each term (token overlap, size proximity, penalties for obvious category mismatches) and pick the cheapest passing hit; terms with no plausible match come back as not-found. Use batch --candidates N --json when an agent wants the scored shortlist to choose from.
Run grocery stores for the live list. Currently 29 stores across 5 countries:
| Key | Store | Country | Backend | Supports |
|---|---|---|---|---|
mercadona |
Mercadona | ES | Algolia + REST | search, batch, total, product, categories, cart |
bonpreu |
Bonpreu i Esclat | ES | uTLS | search, batch, total, product, categories, cart |
ametller |
Ametller Origen | ES | SCAPI | search, batch, total, product, categories |
gadis |
Gadis | ES | REST | search, batch, total, product, categories |
aldi |
ALDI España | ES | Algolia | search, batch, total, product, categories |
makro |
Makro España | ES | REST | search, batch, total, product, categories |
consum |
Consum | ES | REST | search, batch, total, product |
dia |
DIA | ES | REST | search, batch |
eroski |
Eroski | ES | HTML | search, batch |
alcampo |
Alcampo | ES | SSR | search, batch |
masymas |
masymas | ES | SSR | search, batch |
lidl-es |
Lidl España | ES | REST | search, batch |
continente |
Continente | PT | SSR | search, batch, cart |
pingodoce |
Pingo Doce | PT | SSR | search, batch, cart |
auchan |
Auchan | PT | SSR | search, batch, cart |
lidl-pt |
Lidl Portugal | PT | REST | search, batch |
morrisons |
Morrisons | UK | REST | search, batch |
iceland |
Iceland | UK | Algolia | search, batch, total, product |
tesco |
Tesco | UK | cookie + GraphQL | search, batch, product, categories, cart (login) |
sainsburys |
Sainsbury's | UK | cookie + REST | search, batch, product, cart (login) |
edeka24 |
Edeka24 | DE | HTML | search, batch |
scotts |
Scotts | MT | WooCommerce | search, batch, total, product, categories, cart |
pavipama |
PAVI/PAMA | MT | REST | search, batch, categories, cart |
welbees |
Welbee's | MT | HTML | search, batch |
spar |
SPAR | MT | HTML | search, batch |
savemart |
Savemart | MT | HTML | search, batch |
convenienceshop |
The Convenience Shop | MT | REST | search, batch |
greens |
Greens | MT | REST | categories |
smart |
Smart Supermarket | MT | HTML | categories |
Two of the Spanish stores need reading differently from the rest:
aldi prices the catalog ALDI publishes online, which it does not sell online, so there is no cart. Prices differ by region; GROCERY_ALDI_REGION picks peninsula, Canarias or Baleares.
makro is cash-and-carry. It quotes its trade customers net prices, and it sells wholesale packs, so the adapter reports the gross (VAT-inclusive) price and works the per-unit price off the whole pack: "leche entera 1 L contiene 6 unidades" is priced as the six litres it is. Its descriptions are long and brand-first, so search finds more than compare and batch do.
Not included: some chains sit behind bot-management (Cloudflare/Akamai/DataDome) that a plain HTTP client can't clear — Carrefour, El Corte Inglés (ES/PT), Condis, Intermarché, ASDA, Waitrose, Ocado, REWE, Kaufland, Netto. Their catalogs would need a headed stealth browser, which is out of scope for this CLI. Lidl in some markets has no shoppable priced online catalog (weekly-flyer only).
go install github.com/jgalea/grocery-cli/cmd/grocery@latestOr from source:
git clone https://github.com/jgalea/grocery-cli.git
cd grocery-cli
go build -o grocery ./cmd/grocery
./grocery version# List stores and what each supports
grocery stores
# Ametller Origen (ES) — the default store
grocery search llet --cheapest --limit 5
grocery product 1251
# Continente (PT) — pick it with --store
grocery --store continente search leite --limit 5
printf 'leite\npão\novos\n' | grocery --store continente batch -f -
# Set a default store for the session
export GROCERY_STORE=continente
grocery search arroz --limit 3
# Compare a shopping list across stores and rank by basket total
printf 'leche\naceite\nhuevos\ncafe\npan\n' | grocery compare -f - --stores mercadona,consum,dia,alcampo
printf 'leite\novos\ncafe\n' | grocery compare -f - --country PT --detail| Command | Description |
|---|---|
grocery stores |
List supported stores, their country, backend and capabilities |
grocery search <term…> |
Full-text search. --limit N, --eco (where supported), --cheapest (rank by €/kg·L·u) |
grocery batch [-f file] |
Best matching hit per term (one per line, # comments ok; or positional). --candidates N with --json/--toon includes scored alternatives |
grocery compare [-f file] |
Price one shopping list across several stores and rank them (--stores a,b,c or --country ES, --detail) |
grocery total [-f file] |
Deterministic basket total from <id> [qty] lines, summed in integer cents |
grocery product <id> |
Product detail (price, brand, origin, ingredients, nutrition) |
grocery categories [--id N] |
Category tree, or one category's products with --id |
grocery usuals |
Regularly-bought items from local purchase history (--store, --min N, default 2) |
grocery usuals order --store <key> |
Refill the cart with usual items (--dry-run, --min N) |
Common flags (before or after the command): --store <key>, --lang <code>, --json, --toon.
Not every store supports every command yet — an SSR store without a product-detail path returns a clear "not supported for this store yet", and grocery stores lists each store's capabilities.
grocery can fill your own cart on stores that support it (grocery stores lists cart). It adds items and stops there — it never places the order; you review and pay in the browser.
Cart stores today, by login style:
- Continente, Pingo Doce, Auchan (PT) and Scotts (MT) — guest cart, no login needed (verified live); paste a cookie only if you want items in your own account cart. Pingo Doce needs a home-delivery postal code (defaults to Lisbon
1000-001; override withGROCERY_PINGODOCE_POSTAL). - Mercadona (ES) — email + password:
grocery --store mercadona login(password read hidden, never stored; only the token is cached). - Bonpreu (ES) — paste your browser Cookie header (SSO/cookie login):
grocery --store bonpreu login, then paste it from DevTools → Network → any request → Cookie. - PAVI/PAMA (MT) — paste your login token from a logged-in session:
grocery --store pavipama login. - Tesco, Sainsbury's (UK) — behind Akamai, so they need your logged-in browser Cookie even to search:
grocery --store tesco loginfirst, then search and cart work.
grocery --store mercadona cart add 4240 2 # add 2× a product by id
grocery --store mercadona cart # show the cart
grocery --store mercadona cart set 4240 0 # remove it
grocery --store mercadona cart clear # empty the cartcart add/set take a --max <eur> cap that refuses an over-budget line before writing.
Each successful cart add appends a line to ~/.grocery/history.jsonl (override with GROCERY_CONFIG_DIR). Use grocery usuals to see what you buy often, and grocery usuals order --store mercadona to refill the cart in one step.
The point of this is the agent flow: with the bundled grocery-shop Claude skill, you can say "add milk, eggs and coffee to my Mercadona basket" (or share a photo of a list) and the agent resolves each item, shows a priced plan, and fills the cart after you approve. Install it by copying .claude/skills/grocery-shop into your Claude skills directory. Only stores that list cart in grocery stores support this.
grocery mcp runs a stdio Model Context Protocol server in the same binary. Any MCP client can search catalogs, price a list across stores, and fill carts — no shell access needed. Cart tools fill the basket but never place an order; you review and pay in the browser.
Tools exposed: stores, search, batch, compare, product, categories, cart_get, cart_add, cart_set, cart_clear. Results are compact JSON (same shapes as --json). Logs go to stderr; stdout is the protocol channel.
Claude Code:
claude mcp add grocery -- grocery mcpClaude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"grocery": {
"command": "grocery",
"args": ["mcp"]
}
}
}Use the full path to grocery if it's not on your PATH. Cart stores still need a one-time grocery --store <key> login in a terminal before the MCP client can write to your cart.
Add an entry to internal/registry, pointing at either the SCAPI adapter (with the store's short code, org, guest client id and site id) or the SSR adapter (base URL, site id, locale). A store on a different platform (a custom API, a different commerce backend) gets a small new adapter implementing the store.Store interface.
| Env | Purpose |
|---|---|
GROCERY_STORE |
Default store key |
GROCERY_CONFIG_DIR |
Override ~/.grocery (per-store session cache) |
GROCERY_SCAPI_BASE |
Override the SCAPI host (debugging) |
GROCERY_GADIS_STORE |
Gadis assortment store id (defaults to the site's own default) |
GROCERY_ALDI_REGION |
ALDI price region: pen (default), can, bal |
GROCERY_MAKRO_STORE |
Makro depot id (defaults to 00001) |
MIT. See LICENSE.
Author: Jean Galea (@jgalea). Repository: github.com/jgalea/grocery-cli.
Inspired by bonpreu-cli and mercadona-cli.