Woolworths Australia Grocery Product & Reviews Scraper
Pricing
from $1.50 / 1,000 product results
Woolworths Australia Grocery Product & Reviews Scraper
Scrape Woolworths Australia (woolworths.com.au) grocery products and reviews. Search by keyword or paste product / search links. Returns name, brand, price, was price, unit price, pack size, specials, availability, images, category, nutrition, allergens, ingredients, rating and customer reviews.
Pricing
from $1.50 / 1,000 product results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
9
Total users
6
Monthly active users
1.8 hours
Issues response
9 days ago
Last modified
Categories
Share
Scrape woolworths.com.au grocery products and customer reviews at scale. Search by keyword with filters, browse a whole specials & offers category, or paste product / search / specials links (or bare product codes). Every product comes back as one flat record with price, was-price and discount, unit (cup) price, specials, pack size, availability, images, category, nutrition, allergens, ingredients, rating and - optionally - customer reviews.
What it does
- Three ways to start
- Search - one or more keywords, with sort, minimum-rating, price-range and specials-only filters, across all result pages.
- Specials & offers category - browse a whole Woolworths specials category (Half Price, Online Only Specials, Everyday Low Price, Seasonal Price, Buy More Save More, Lower Shelf Price, Bundles, or all specials at once), or sweep every currently-discounted product in one run - including the markdowns that never get a promotions-menu category.
- URL - paste product pages (
/shop/productdetails/<code>), search pages (/shop/search/products?searchTerm=...), category pages (/shop/browse/fruit-veg, including sub-categories like/shop/browse/fruit-veg/fruit), specials listing pages (/shop/browse/specials/half-price), or bare numeric product codes. Category pages walk the category's full catalog.
- Was-price & discount - on every discounted product you get the strike-through was-price, the savings amount and percentage, and the offer label (e.g. "Half Price", "Buy More Save More"), alongside the current price and unit (cup) price.
- Full product detail - collect each product's rich description, barcode (EAN/GTIN), department / category, country of origin, health-star rating, ingredients, allergens, dietary statement, storage instructions, the nutrition panel, images and sibling variants.
- Ratings & reviews - the aggregate rating (average score, rating count, review count and the 5-star-to-1-star distribution) plus customer reviews: star rating, review text, author display name and date.
Specials & offers
Pick a category under Specials & offers category (search mode) to walk a whole promotion, or paste a specials listing link in URL mode. The categories mirror Woolworths' own specials taxonomy:
| Category value | Covers |
|---|---|
all-specials-complete | Everything currently discounted. Sweeps every department for the products the store flags as on special, instead of walking the promotions menu. |
all-specials | Every promotions-menu category below, merged. |
half-price | Half Price. |
lower-shelf-price | Lower Shelf Price. |
online-only-specials | Online Only Specials. |
everyday-low-price | Everyday Low Price. |
seasonal-price | Seasonal Price. |
buy-more-save-more | Buy More Save More (multibuy). |
bundles | Bundles. |
Each product on a specials listing carries its was-price, savings and offer label; multibuy offers also carry the buy-more quantity and price.
Which one should you pick? The promotions menu is a curated selection, not an index of every markdown — a genuine discount (say a plain 40% off) can appear in none of its categories. If you need every currently-discounted product, pick all-specials-complete; it reads each department's on-special listing directly, so it also catches the offers that never get a promotions-menu category.
all-specials-complete returns only products whose price is actually reduced right now — you do not need to set specialsOnly yourself. It keeps markdowns (Half Price, percentage-off, seasonal), Buy More Save More multibuy offers and Everyday Rewards member prices.
It deliberately excludes Everyday Low Price, Lower Shelf Price and Bundles. Woolworths files those under /specials, but they are regular low shelf prices rather than offers — measured live, 0 of 44, 0 of 36 and 0 of 7 of their products are flagged on special and all have wasPrice equal to price with zero savings. If you do want them, browse those categories directly with specialsCategory or a /shop/browse/specials/... URL. It returns considerably more than all-specials does, so set Max products to bound the run. Marketplace items stay excluded unless includeMarketplace is on, and excludeCategories still drops whole departments before anything is fetched.
Skipping departments you don't want
To scrape a listing except certain departments, use excludeCategories:
{"specialsCategory": "half-price","excludeCategories": ["beer-wine-spirits", "everyday-market"]}
A product is skipped if it belongs to any listed department. This matters because the storefront files the same product under several departments at once — roughly half of the products in the specials catalogue are cross-listed — so a product carried under both an excluded and a kept department is still dropped. Accepts the name from a browse link (beer-wine-spirits), the display name (Beer, Wine & Spirits), or a pasted /shop/browse/<department> URL. The decision is made from the listing page, so skipped products are never fetched in detail and cost nothing.
Every record also carries departments and departmentIds listing every department the product sits under, plus departmentNames: the human-readable name for each entry, in the same order (departmentNames[0] is the display name for departments[0], and so on). A product with no browse-taxonomy department carries neither field.
Order is not a priority. Woolworths ships this list in a fixed order per product (the same stockcode returns the same order regardless of which department page you browse it from), but that order does not reliably identify a "primary" department: checked live across 96 cross-listed products in 4 departments, departments[0] matched the department the product was actually browsed under only 47/96 times (about 49%, no better than a coin flip). The actor preserves the storefront's own order as-is and does not reorder it or guess a primary. If your pipeline currently treats departments[0] as "the" department, that assumption is not supported by the data; there is no published primary, so pick your own tie-break rule (e.g. prefer a department from your own allow-list) instead of relying on array position.
Two different category systems: departments vs department/category/subCategory
This actor exposes two unrelated taxonomies, and they do not agree with each other because they come from different Woolworths systems:
departments/departmentIds/departmentNames: the storefront browse taxonomy (what you see under Shop > Browse on the website). Read from the listing card itself (AdditionalAttributes.piesproductdepartmentsjson), so it is present on every mode (search, browse and URL) with no extra request, and a product is usually filed under more than one entry.department/category/subCategory: Woolworths' internal SAP merchandising hierarchy (SapDepartmentName/SapCategoryName/SapSubCategoryName). This is a single-valued hierarchy (one department, one category, one sub-category), but it only comes from the product detail page, so it is present only whenfetchDetailsis on (defaulttrue), and it is genuinely blank on some products: the detail record still exists, but the SAP fields themselves come back empty. When absent,department/category/subCategoryare simply not in the record; nothing is guessed.
departments[0] is not a substitute for category. They are different systems that classify the same product independently, so they can disagree (e.g. a product's browse department might be "Cleaning & Maintenance" while its SAP category is "Garden Aids/Seeds/Bulbs"; both are genuine, they just answer different questions). If your baseline needs the merchandising hierarchy, use department/category/subCategory with fetchDetails on; if it needs the storefront navigation, use departments/departmentNames. Don't use one to fill a gap in the other.
Use excludeSpecialsCategories to do the opposite: drop products in the categories you list instead of collecting and paying to enrich them. It uses the same category values as above; excluding all-specials drops every on-special product. Applied to the Specials & offers category, a pasted specials URL, and keyword searches; a dedicated specials listing is skipped before any page is fetched, so an excluded category costs nothing. Dropped products are never pushed or charged.
URL mode: which links work
Set mode to url and paste any mix of these into urls. Listing links are walked across all their result pages, and every filter above still applies.
| Link shape | What you get |
|---|---|
/shop/productdetails/<code> — or just the bare code | That single product. |
/shop/browse/<department> | The department, walked in full. |
/shop/browse/specials/<category> | That specials category. |
/shop/productgroup/<id> | A curated collection — the merchandised landing pages such as "Discover and shop our newest range". These are hand-picked selections that are not part of the category tree, so they can only be reached by their own link. |
/shop/search/products?searchTerm=... | That keyword search. |
Ratings & reviews: what you get
Woolworths shows an aggregate rating (average score, rating count, review count and the 5-star-to-1-star distribution) and a customer review list on product pages. This actor captures both:
- The aggregate rating and star distribution are collected during detail enrichment (
fetchDetails), so every enriched product carriesrating,ratingCount,reviewCountandratingDistributionwhen it has ratings. - The review list is collected when
fetchReviewsis on, up to yourmaxReviewsPerProductcap. Each review carries star rating, text, author display name and date.
Note: many grocery lines carry few or no reviews. When a product has no ratings, the rating fields are omitted (not guessed) and
reviewscomes back empty. Products with reviews return them in full.
Input
| Field | Type | Description |
|---|---|---|
mode | select | search (keyword + filters) or url (paste links / product codes). |
queries | string[] | Search keywords (search mode). Each keyword is searched separately. |
specialsCategory | select | Browse a whole specials category: half-price, lower-shelf-price, online-only-specials, everyday-low-price, seasonal-price, buy-more-save-more, bundles, or all-specials. Use all-specials-complete to catch every currently-discounted product, including offers with no promotions-menu category. Leave blank to skip. |
excludeSpecialsCategories | select (multi) | Drop products in these specials categories instead of collecting them. Same values as specialsCategory (minus blank); excluding all-specials drops every on-special product. |
excludeCategories | string[] | Optional. Departments to skip entirely, e.g. beer-wine-spirits, everyday-market, pet. Skipped products are never collected, so they cost nothing. |
sortBy | select | relevance, price_asc, price_desc, name, savings. |
minRating | select | Keep products rated at least 3, 4 or 5 stars (requires details). |
specialsOnly | boolean | Keep only products currently on special / half price. |
includeMarketplace | boolean | Also include products shipped by third-party Everyday Market sellers. By default only products sold directly by Woolworths are returned, and they are excluded at the source — the third-party range dominates most departments (Home & Lifestyle lists 444,872 entries against 1,935 sold by Woolworths), so leaving it off makes a category walk both far faster and far more complete. Default false. |
minPrice / maxPrice | integer | Keep products within an AUD price range. |
urls | string[] | Product, category, specials, product-group or search URLs, or bare product codes (url mode). See URL mode for the link shapes. |
fetchDetails | boolean | Collect full product detail + aggregate rating. Default true. |
fetchReviews | boolean | Also collect customer reviews. Default false. |
maxReviewsPerProduct | integer | Cap reviews per product (0 = all). Default 20. |
maxItems | integer | Primary limit: max products for the whole run (0 = unlimited). Default 20. |
maxPages | integer | Optional bound on result pages walked per keyword/category/URL (36 products/page). Empty walks every result page (does not cap products; maxItems does). |
resumeFromRunId | string | Optional. ID of a previous run of this actor (or a dataset ID). Products already in that dataset are skipped, so this run returns only NEW products (a delta). Combine both runs' datasets for the full set. Max products then counts only the new products. |
proxy | object | Proxy configuration. Apify Proxy is used by default and works on every plan. |
Example input
{"mode": "search","queries": ["milk"],"sortBy": "relevance","specialsOnly": false,"minPrice": 1,"maxPrice": 20,"fetchDetails": true,"fetchReviews": true,"maxReviewsPerProduct": 20,"maxItems": 20,"proxy": { "useApifyProxy": true }}
Example input - specials category
{"mode": "search","specialsCategory": "half-price","sortBy": "savings","fetchDetails": true,"maxItems": 50,"proxy": { "useApifyProxy": true }}
Output
One record per product. Example (values below are illustrative):
{"stockcode": "100000","name": "Example Full Cream Milk 2L","displayName": "Example Full Cream Milk 2L","title": "Example Full Cream Milk 2L","brand": "ExampleBrand","url": "https://www.woolworths.com.au/shop/productdetails/100000/example-full-cream-milk","price": 3.1,"wasPrice": 3.9,"savingsAmount": 0.8,"savingsPercent": 21,"isOnSpecial": true,"isHalfPrice": false,"isEdrSpecial": false,"promoLabel": "Prices Dropped","savingsLabel": "Save $0.80","promotionType": "Special","cupPrice": 1.55,"cupMeasure": "1L","cupString": "$1.55 / 1L","packageSize": "2L","unit": "Each","currency": "AUD","barcode": "9300000000000","gtinFormat": 13,"isAvailable": true,"isInStock": true,"isNew": false,"isOnlineOnly": false,"variety": "Full Cream","offerId": "24000000","isMarketProduct": false,"image": "https://cdn0.woolworths.media/content/wowproductimages/large/100000.jpg","thumbnailImage": "https://cdn0.woolworths.media/content/wowproductimages/small/100000.jpg","images": ["https://cdn0.woolworths.media/content/wowproductimages/large/100000.jpg"],"departments": ["dairy-eggs-fridge", "lunch-box"],"departmentIds": ["1_C2FCE2B", "1_9E92C35"],"departmentNames": ["Dairy, Eggs & Fridge", "Lunch Box"],"richDescription": "A fresh Australian full cream milk, rich and creamy.","department": "Dairy, Eggs & Fridge","category": "Milk","subCategory": "Full Cream Milk","countryOfOrigin": "Made in Australia","healthStarRating": "4.5","ingredients": "Full cream milk.","allergenContains": "Milk","dietaryStatement": "Vegetarian","storageInstructions": "Keep refrigerated below 4C.","nutrition": { "servingsPerPack": "8", "servingSize": "250mL" },"rating": 4.6,"ratingCount": 128,"reviewCount": 54,"ratingDistribution": { "5": 96, "4": 20, "3": 7, "2": 3, "1": 2 },"reviews": [{"rating": 5.0,"body": "Fresh and creamy, our family buys it every week.","author": "sampleShopper","date": "2025-02-14T06:01:00.000Z","syndicatedFrom": "woolworths"}],"reviewsCollected": 1,"searchMode": "search"}
Field reference
| Field | Description |
|---|---|
stockcode | Woolworths product code (the SKU). |
name, displayName, title, brand, url | Product name, display name, fuller canonical title (includes pack size), brand, product page URL. |
price, wasPrice, savingsAmount, savingsPercent, isOnSpecial, isHalfPrice, isEdrSpecial | Current price, strike-through was-price, savings amount + percentage, and specials flags (including Everyday Rewards member specials). price and isInStock are captured independently and neither is derived from the other: the actor does not assume a price implies stock, or that being in stock implies a nonzero price; whatever the storefront publishes for each field is what you get. |
promoLabel, savingsLabel, promotionType, promotionInfo | Offer label (e.g. "Half Price"), savings tag (e.g. "Save $7.00"), promotion type and the human-readable promotion sentence. Present on discounted products. |
multibuy, memberPrice | Buy-more-save-more offer (quantity, price, cupString) and Everyday Rewards member price when applicable. |
cupPrice, cupMeasure, cupString, packageSize, unit, currency | Unit (cup) price, pack size and currency (AUD). |
barcode, gtinFormat | EAN/GTIN barcode and its GTIN format code. The dataset stores barcode as text (e.g. "9335390000141"), quoted correctly in both the JSON and CSV exports. If a long digit string like this looks truncated or turns into scientific notation (9.34E+12) after opening the CSV in Excel or Google Sheets, that is the spreadsheet app coercing the column to a number on import, not a data problem on our end. Import the CSV with that column set to Text (Excel: Data > From Text/CSV > change the column's data type to Text before loading; Sheets: paste with "Text" formatting, or add a leading apostrophe) to keep the full barcode intact. |
isAvailable, isInStock, isNew, isOnlineOnly, productLimit, isMarketProduct, vendor, variety, offerId | Availability, new/online-only flags, purchase limit, market-seller info, variety and the offer id. isOnlineOnly and isMarketProduct are independent flags, not a spectrum. isOnlineOnly means the product is only sold through the website (no physical store listing), while isMarketProduct means it is sold by a third-party Everyday Market seller rather than by Woolworths itself. A Woolworths own-brand product that is only sold online is still first-party: it has isOnlineOnly: true and isMarketProduct: false. If you are building a first-party-only dataset, filter on isMarketProduct/includeMarketplace, not on isOnlineOnly: excluding isOnlineOnly: true products will drop genuine first-party Woolworths SKUs, not just marketplace listings. |
image, thumbnailImage, images | Primary image, thumbnail and the image list. |
departments, departmentIds, departmentNames | Every storefront browse-taxonomy department the product is filed under (a product is commonly filed under more than one), their opaque node ids, and the matching human-readable name for each departments entry (same index). Present whenever the listing card carries this data, in search, browse and URL mode alike, with no detail fetch required. This is a different taxonomy from department/category/subCategory below; see Two different category systems above. |
richDescription, department, category, subCategory, countryOfOrigin | Description, and Woolworths' internal SAP merchandising hierarchy (single-valued: one department, one category, one sub-category). Present only when fetchDetails is on (needs the detail page), and even then some products' SAP fields come back genuinely empty, so department/category/subCategory are omitted for those (see Two different category systems). |
healthStarRating, ingredients, allergenContains, allergenMayContain, dietaryStatement, storageInstructions, nutrition | Grocery labelling and nutrition (with details). |
variants | Sibling products (flavours / sizes) with code, name, price and URL. |
rating, ratingCount, reviewCount, ratingDistribution | Aggregate rating and the 5★→1★ split (with details, when the product has ratings). |
reviews, reviewsCollected | Collected reviews and their count (present when reviews are enabled). |
Whenever a value is not published for a product, the field is omitted or null rather than guessed.
Marketplace records (includeMarketplace: true) carry isMarketProduct: true and name their third-party seller in vendor.
Proxy
Apify Proxy is used by default and works on every plan. Leave proxy enabled for the most reliable results.
Notes
- Prices, specials, ratings and stock are captured as shown on the storefront at scrape time.
- Filters (
minRating,minPrice,maxPrice,specialsOnly,includeMarketplace) are applied to each product's own values, so exact numeric ranges work independently of the on-site filters. - Department listings mix the supermarket's own range with a much larger third-party marketplace catalog (some departments list 50,000+ marketplace items), so an uncapped category walk can legitimately run for hundreds of pages. The page log shows how many unique products have been seen against the listing's own total. Marketplace items are excluded by default; set
includeMarketplace: trueto collect them too. - The run periodically checkpoints its progress, so if the platform restarts the run (a server migration, or you use Resurrect) it picks up where it left off instead of starting over, with no duplicate products and no double charges. No input is needed for this; it is automatic.