woolworths-nz
Query Woolworths NZ product search, specials, category browse, and SKU details, plus a user's own past orders, favourites, saved lists, and trolley when they explicitly provide account credentials. Ma
Files14
View on GitHubSKILL.mdskills/woolworths-nz/SKILL.md
GitHubWoolworths NZ
Goal
Query live Woolworths NZ product data, optionally retrieve the authenticated user's own account history, and perform explicit saved-list or trolley changes through one CLI.
Use this when
- A user asks for Woolworths NZ product prices, specials, keyword search, or SKU details
- A user explicitly wants their own past Woolworths orders, favourites, or saved lists
- A user wants their own Woolworths tax-invoice PDF enriched with the matching past-order SKUs
- A user explicitly asks to create/delete a saved list or add, update, or remove a list product
- A user explicitly asks to inspect their trolley or add, update, remove, or clear its products
Do not use this for
- Woolworths Australia or another retailer
- Checkout, ordering, payment, delivery-slot, fulfilment, account, or Everyday Rewards changes
- List or trolley mutation the user has not explicitly requested
- Reading another person's account or using credentials not supplied by the account holder
- Redistributing Woolworths product or account data as a dataset
- Historical pricing claims unless another source provides history
Preferred workflow
- Run
scripts/cli.pywith the narrowest command that answers the task - Use public
search,specials,categories,browse, andproductcommands without credentials - Use account commands only after the user supplies their own credentials as environment variables
- Run saved-list or trolley mutations only for the exact change the user requested
- Preserve every
--yesdeletion/removal guard - Use
--jsononly for private structured workflows; treat account JSON as personal data - For invoice enrichment, use the local tax-invoice PDF and its matching order ID; inspect unmatched or ambiguous joins before relying on them
- Never use this skill to place an order or perform checkout/payment actions
Authentication and privacy
Public product commands need no account. Personal commands require:
export WOOLWORTHS_USERNAME='member@example.nz'
export WOOLWORTHS_PASSWORD='...'
woolworths auth login
WOOLWORTHS_EMAILis accepted as an alias forWOOLWORTHS_USERNAME.- The CLI registers and displays account commands only when both a username/email and
WOOLWORTHS_PASSWORDexist in its environment. - The password is passed only to Woolworths' browser login and is never written to disk.
- The cookie cache stores a SHA-256 hash of the normalised username and is reused only when it matches the currently supplied username. Changing accounts invalidates the old cache instead of silently reusing it.
- Woolworths' login page uses a browser challenge. Install the optional helper with
python3 -m pip install camoufox, then runpython3 -m camoufox fetchonce. - A reusable cookie cache is written to
~/.local/state/woolworths-nz/cookies.jsonwith file mode0600. - Authenticated responses can refresh Woolworths session/Akamai cookies; the CLI persists only cookies scoped to
woolworths.co.nzback into the same private, account-bound cache. - Override the cache location with
WOOLWORTHS_SESSION_FILE. - If a hidden browser login cannot complete a challenge, retry
auth login --headed. auth statusnever emits cookies or account details.auth logoutremoves only the local cookie cache; it does not sign out other devices or mutate the account.- Orders, list names, favourites, item history, addresses, and raw account JSON are personal data. Do not paste them into shared logs, issues, or pull requests.
- Tax invoices and enriched invoice output are personal financial/order data. Never add a user's PDF or parsed rows to fixtures or source control.
CLI
Run with:
python3 skills/woolworths-nz/scripts/cli.py <command> [flags]
Public commands are always available:
search <query> [--limit N] [--page N] [--size text] [--json]specials [query] [--limit N] [--page N] [--json]categories [parent-category-key] [--json]browse <category-key> [--limit N] [--page N] [--json]product <sku...> [--json]
The following appear only when the credential environment variables are set:
auth login [--headed]auth status [--json]auth logoutorders [--page N] [--date-filter value] [--json]order <order-id> [--json]order-items <order-id|all> [--page N] [--limit N] [--sort value] [--json]invoice-items <order-id> <invoice.pdf> [--min-confidence 0..1] [--json]favourites [--page N] [--limit N] [--sort value] [--json]lists [--json]list <list-id> [--page N] [--limit N] [--sort value] [--json]list-create <name> [--source empty|trolley|favourites|list|order|all-orders] [--source-id id] [--json]list-delete <list-id> --yes [--json]list-add <list-id> <sku> [--quantity N] [--json]list-update <list-id> <sku> --quantity N [--json]list-remove <list-id> <sku> --yes [--json]cart [--json]cart-add <sku> [--quantity N] [--unit Each|Kg] [--json]cart-update <sku> --quantity N [--unit Each|Kg] [--json]cart-remove <sku> --yes [--unit Each|Kg] [--json]cart-clear --yes [--json]
Examples:
python3 skills/woolworths-nz/scripts/cli.py search milk --limit 10
python3 skills/woolworths-nz/scripts/cli.py categories
python3 skills/woolworths-nz/scripts/cli.py product 705692 --json
woolworths auth login
woolworths orders --json
woolworths invoice-items <order-id> ~/Downloads/invoice.pdf --json
woolworths lists
woolworths list-create "Weekly shop"
woolworths list-add <list-id> 705692 --quantity 2
woolworths cart-add 705692 --quantity 2
Trolley SKU commands resolve --unit Each|Kg to the exact purchasing variant
before mutating. Pass the exact variant key when a product has other ambiguous
purchasing variants.
list-create defaults to --source empty. Woolworths currently implements
that safely by saving the current trolley as a list, so the CLI first reads the
trolley and refuses to create the list unless it is empty. Use
--source trolley explicitly only when the user wants the trolley contents
copied into the new list.
Resources
- CLI entrypoint:
scripts/cli.py - Current GraphQL documents and parsers:
scripts/graphql_api.py - Browser login helper:
scripts/browser_auth.py - Invoice parser and SKU matcher:
scripts/invoice_parser.py - Live and deterministic smoke tests:
scripts/smoke_test.py - API and stability notes:
references/api-notes.md
Notes
- Public commands use Woolworths' current GraphQL product service, remain stdlib-only, and do not launch a browser.
- Account reads/writes use the saved Woolworths session directly; a 401/403 triggers one browser refresh and retry.
invoice-itemsparses supplied/paid invoice rows from a text-based Woolworths tax-invoice PDF, verifies its Order Confirmation/Invoice Number against the requested order ID, fetches the matching past-order product list, and performs a one-to-one confidence-scored name join to SKUs.- Invoice parsing has one additional optional dependency:
python3 -m pip install pdfplumber. It is imported only byinvoice-items; public product commands remain standard-library-only. - A match below
--min-confidenceis left unmatched. Close runner-up candidates are marked ambiguous rather than silently accepted. - Safe reads may refresh an expired session once. Mutations are never replayed after an indeterminate non-JSON response; inspect the current list or trolley state before retrying.
- Saved-list item writes use Woolworths' current
{itemsToAdd: [{sku, quantity}]}request. - Trolley reads and writes use the current
CustomerCart,SetCartLineItemQuantity, andClearCartGraphQL operations. Woolworths writes target a product variant key; callers may still pass a catalogue SKU and the CLI resolves its current variant key first.cart-addreads then increments;cart-updatesets the target. Eachquantities must be whole numbers. Use--unit Kgfor explicit weights.- List deletion, list item removal, trolley item removal, and trolley clearing require
--yes. - Endpoint shapes can change; retry with a fresh session before assuming account data is unavailable.
- This is an unofficial integration and deliberately excludes checkout/order placement.