Grocer.nz Public Price Data
SkillDatabases & dataQuery grocer.nz public NZ supermarket data — canonical product and barcode/GTIN lookup, cross-retailer product matching, store lookup, current per-store prices, and historical price rows from public DuckDB/parquet assets. Use for exact NZ grocery product matching or pricing across Woolworths, New World, PAK'nSAVE, Fresh Choice, and related stores. Read-only; no login or private user data.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Grocer.nz Public Price Data skill
What this skill tells your AI
The instructions your AI receives, as published by thecolab-ai/.skills in skills/grocer-nz/SKILL.md and read by ahel’s review.
Overview
This skill queries public data exposed by grocer.nz, a New Zealand grocery price comparison app. It is useful as a canonical product/GTIN crosswalk as well as for current supermarket price checks, per-store comparisons, and historical product price rows.
The CLI uses:
- Grocer public static assets:
https://assets-prod.grocer.nz/public/ - Public DuckDB base database:
base_v3.duckdb.br - Per-store current price parquet files:
prices_per_store_v3/public_prices_<store_id>.parquet - Per-product history parquet files:
price_history_v3/price_history_<product_id>.parquet - Grocer frontend Meilisearch product index for search.
Script path:
skills/grocer-nz/scripts/cli.py
The script bootstraps duckdb via uv when the active Python does not already have it.
When to Use
- Adam asks for historic supermarket pricing in NZ.
- Adam wants to compare prices across Woolworths, New World, PAK'nSAVE, Fresh Choice, Super Value, The Warehouse, etc.
- Adam wants a store id for a known store, e.g. Papakura.
- Adam wants price history for a known Grocer product id.
- Adam wants current prices for one product across selected stores.
- Adam wants the public DuckDB/parquet download URLs so another agent can download or analyse the raw files itself.
- Adam wants to identify the same exact product in the Woolworths, New World, or PAK'nSAVE skills.
- Adam has a UPC, EAN, or GTIN and needs the corresponding Grocer product id.
Do not use this for authenticated Grocer Pro features, private user lists, or anything requiring sign-in. This skill is read-only public data only.
Commands
Set a helper variable:
GROCER=skills/grocer-nz/scripts/cli.py
Get raw asset download URLs
Use assets when the caller wants the source files rather than parsed rows. This
command only constructs links from Grocer's fixed public asset layout. It makes
no network request, starts no DuckDB process, and does not download or parse any
file.
# Base catalogue DuckDB URL (also the default with no selectors)
python3 $GROCER assets --base --json
# Current-price parquet URLs for selected stores
python3 $GROCER assets --store-id 230 --store-id 307 --json
# Per-product history parquet URLs
python3 $GROCER assets --product 5452 --product 5461 --json
# Combine all three asset types
python3 $GROCER assets --base --store-id 230 --product 5452 --json
The result contains delivery: external_url and a resources array. Each
resource has a declared format, filename, and public url. Through The Colab
MCP, supported resources are also emitted as native MCP resource_link content,
so the client downloads directly from Grocer rather than through the MCP server.
The URLs are deliberately not probed; a nonexistent store or product id can
therefore produce a link that returns 403/404 when downloaded. At most 50 links
may be requested in one call.
List stores
python3 $GROCER stores --query Papakura
python3 $GROCER stores --vendor "PAK" --limit 20 --json
Useful known Papakura ids from live smoke:
118— Woolworths Papakura206— Fresh Choice Papakura230— PAK'nSAVE Papakura307— New World Papakura
Search products
Search only:
python3 $GROCER search "milk" --limit 5
Search plus current prices in matching stores:
python3 $GROCER search "milk" --store-query Papakura --limit 3
python3 $GROCER search "whittakers" --store-id 230 --store-id 307 --json
The search command returns Grocer product ids, canonical GTIN-14 barcodes, and compact retailer_search_terms. Use the product ids with prices and history; use the retailer search terms with the retailer-native skills.
Resolve a barcode
Grocer stores barcodes in zero-padded GTIN-14 form. The command accepts compact UPC/EAN forms too:
python3 $GROCER barcode 94152210
python3 $GROCER barcode 00000094152210 --json
For Anchor Blue Milk 2L, this resolves to Grocer product 5452, canonical GTIN 00000094152210, and retailer search term 94152210.
Match the exact product across retailers
- Search Grocer by product description and select the right brand/name/size candidate.
- Copy a returned
retailer_search_termsvalue. - Search each retailer skill with that value:
python3 skills/woolworths-nz/scripts/cli.py search 94152210 --json
python3 skills/paknsave-nz/scripts/cli.py search 94152210 --json
python3 skills/newworld-nz/scripts/cli.py search 94152210 --json
Woolworths search can include loosely related results, so keep only rows whose barcode, normalised to GTIN-14, equals Grocer's canonical barcode. Foodstuffs barcode search returns the matching New World/PAK'nSAVE product id; both banners use the same Foodstuffs product id for the same product. If barcode search returns no exact result, do not silently substitute a similar size or variant—fall back to brand/name/size matching and label it as a probable match.
Current prices for a product
python3 $GROCER prices 5461 --store-query Papakura
python3 $GROCER prices 5461 --store-id 230 --store-id 307 --json
--all-stores is supported but can be slow because it downloads many per-store parquet files:
python3 $GROCER prices 5461 --all-stores --limit 30
Price history for a product
python3 $GROCER history 5461 --store-query Papakura --limit 20
python3 $GROCER history 5461 --store-id 230 --json
History files are per product and include store-level rows when available.
Raw product metadata
python3 $GROCER product 5461 --json
Ad-hoc SQL query (guarded, read-only)
Run a single SELECT/WITH statement over the dataset for analysis the fixed
commands don't cover (cheapest-across-stores, vendor trends, joins, aggregates).
Always-available relations: products, barcodes, stores, vendors. Load extra data with
flags: --store-id/--store-query/--all-stores populate a prices table;
--product populates a history table (with a product_id column added).
# cheapest blue-top milk (product 5452) across Papakura stores
python3 $GROCER query "select s.name, p.original_price_cent from prices p join stores s on s.id=p.store_id where p.product_id=5452 order by 2" --store-query Papakura --json
# count products by vendor that stock a given product's price rows
python3 $GROCER query "with p as (select id,name,brand from products where lower(brand)='anchor') select * from p" --limit 20
# resolve compact retailer barcodes against Grocer's canonical catalogue
python3 $GROCER query "select b.barcode, p.* from barcodes b join products p on p.id=b.product_id where b.barcode='00000094152210'" --json
# price history rows for a product
python3 $GROCER query "select store_id, price_cent, updated_at from history order by updated_at desc" --product 5461 --limit 30 --json
Safety: the statement must be a single read-only SELECT/WITH (no ;, no
DDL/DML). Filesystem and network access are disabled (enable_external_access= false, lock_configuration=true) after the requested parquet are loaded, and
the base catalogue is attached READ_ONLY. An arbitrary query can therefore only
read the public grocery data exposed here — it cannot write, read other files,
reach the network, or change settings. Results are capped (--limit, max 5000).
Data Notes
See references/api-notes.md for the sniffed endpoints and file layout.
Important model fields:
- Products:
id,name,brand,unit,size,redirected_to - Barcodes: zero-padded GTIN-14
barcode,product_id - Stores:
id,vendor_id,name,is_enabled - Current prices:
updated_at,store_id,product_id,original_price_cent,sale_price_cent,club_price_cent,online_price_cent, multibuy fields - Price history:
updated_at,store_id,price_cent
Prices are stored in NZ cents. $5.50 is represented as 550.
Common Pitfalls
- No store selected = limited price context. Product search comes from Meilisearch. Current per-store pricing requires store ids or
--store-queryso the CLI can download the relevant parquet files. --all-storescan be noisy/slow. It may download hundreds of current price parquet files. Prefer targeted store ids for fast checks.- The
.brDuckDB file may arrive already decompressed. The CLI treats Grocer'sbase_v3.duckdb.brCDN response as a DuckDB file directly because Cloudflare/Caddy often transparently decodes it. - DuckDB DDL cannot use prepared parameters for
read_parquet(?). Quote local parquet paths explicitly beforecreate view ... as select * from read_parquet('<path>'); parameter binding works for normalselectfilters but not this statement shape. - History parquet schema is leaner than the app's local table. Per-product history files may only include
updated_at,store_id, andprice_cent; getvendor_idby joiningpublic_stores, and infer product id from the requested history file. - Historical availability varies. Some products/stores have no history parquet or no rows for a selected store.
- Effective price is conservative. The CLI reports
effective_price_centas the minimum of original/sale/club/online when present. Multibuy needs human interpretation because quantity matters. - Live smoke tests depend on upstream stock/history. Product
5461and Papakura stores were live-valid when added, but upstream catalogue changes can make the smoke fail without a code bug. - This is public read-only data. Do not try to bypass sign-in or scrape private Grocer user/list/pro features.
- Retailer barcode search has different shapes. Search Foodstuffs with the compact barcode (leading zero padding removed). Woolworths returns its own
barcode; normalise and verify that field because its text search may include unrelated rows. assetsconstructs but does not validate links. Use it for low-overhead handoff of raw public files. Use the parsed commands when the agent needs verified rows immediately.
Verification Checklist
Run these before relying on a fresh install:
python3 $GROCER stores --query Papakura --json
python3 $GROCER assets --base --store-id 230 --product 5452 --json
python3 $GROCER search "milk" --store-query Papakura --limit 2
python3 $GROCER prices 5461 --store-query Papakura --limit 10
python3 $GROCER history 5461 --store-query Papakura --limit 5
Expected smoke signal: Papakura stores include Woolworths/New World/PAK'nSAVE, and product 5461 returns Anchor 2L milk pricing/history rows for at least PAK'nSAVE/New World/Woolworths Papakura when current Grocer data includes them.
Signals
- GitHub stars
- 25
- Forks
- 6
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
grocer-nz- Source
- github.com/thecolab-ai/.skills