Officeworks Scraper - Products, Prices, Stock & Reviews avatar

Officeworks Scraper - Products, Prices, Stock & Reviews

Pricing

from $1.00 / 1,000 product results

Go to Apify Store
Officeworks Scraper - Products, Prices, Stock & Reviews

Officeworks Scraper - Products, Prices, Stock & Reviews

Scrape Officeworks products by keyword, category, or URL. Extract names, brands, prices, GST, stock by state, images, specifications, identifiers, ratings, reviews, and star distributions. Supports brand, price, and rating filters.

Pricing

from $1.00 / 1,000 product results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

6 days ago

Last modified

Share

Officeworks Scraper: Products, Prices, Stock & Reviews

Officeworks Scraper turns officeworks.com.au into a clean product data feed. Search by keyword with brand, price and rating filters, browse the Deals and Clearance collections, or paste product, search or category links directly. Get the current price plus any genuine was-price, savings and discount, the canonical product title, the variant matrix, availability by Australian state, and optionally the full product description, specifications, image gallery and customer reviews with an aggregate rating summary and star-rating distribution. Export to JSON, CSV or Excel, or pull the results straight into your app through the API.

Why This Scraper?

  • Two ways to find products. Search by keyword with brand, price and rating filters, or paste product, search, category or specials links directly. No need to build URLs by hand.
  • Deals and Clearance, covered natively. Browse Officeworks' own promotional collections instead of (or alongside) a keyword search, with the same filters and sort still applying.
  • Genuine reductions only. Officeworks runs an every-day-low-price model; wasPrice, savingsAmount and savingsPercent are populated only when a product is genuinely reduced below its everyday price, never fabricated.
  • Full product detail on demand. Switch on detail enrichment for the complete description, feature bullets, specifications, identifiers, image gallery and variant matrix, or leave it off for a faster, cheaper listing-only run.
  • Ratings and reviews. Every product already carries the aggregate rating and review count; detail enrichment adds the star-rating distribution and individual customer reviews.
  • Availability by state. See which Australian states a product ships to and whether it is available in-store or online.
  • Built for schedules. Incremental mode returns only new and changed products on recurring runs, and Resume skips products a previous run already collected (see the limits under Resume and recurring updates).

Use Cases

  • Price monitoring and repricing tools: track price, was-price, savings and specials on a schedule to react to Officeworks' pricing moves.
  • Comparison shopping and catalog aggregators: build a structured Officeworks product catalog with identifiers, categories and images.
  • Review and reputation analytics: collect ratings, review counts and individual reviews to gauge customer sentiment per product or category.
  • Merchandising and market research: monitor the Deals and Clearance collections to track what Officeworks is promoting and when.
  • Availability tracking: watch stock by state and online availability for a specific set of SKUs.

Data You Get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
sku"SAMPLE0001"
name"Sample A4 Display Book 20 Pocket"
title (canonical, brand-prefixed)"Sample Brand A4 Display Book 20 Pocket"
brand"Sample Brand"
urlOfficeworks link to the product
price12.5
edlpPrice12.5 (the everyday price)
wasPrice / savingsAmount / savingsPercentnull unless the product is genuinely reduced below edlpPrice
isOnSpecial / promoLabeltrue / "Deal" (also "Clearance", "Low Price", "New", "Planet Positive")
isNew / isClearancefalse / false
currency / gstRate"AUD" / 10.0
gtin / manufacturerPartNumber / productTypeproduct identifiers
availableStates["NSW", "VIC", "QLD"]
isAvailableInStore / availableOnlinetrue / true
variants / variantAxes / variantCountthe variant matrix (per-variant sku, url, attributes, thumbnail)
category / categories / categoryHierarchy"Display Books" / breadcrumb path / full category chains
shortDescription / longDescription / featuresproduct copy and feature bullets (detail enrichment)
specifications / attributesname/value pairs (detail enrichment)
imageUrl / imagesprimary image / full gallery
rating / reviewCount4.3 / 42, present on every product
ratingDistribution / recommendedCountstar breakdown and recommended count (detail enrichment)
reviews[]per-review rating, title, body, author, ISO-8601 date, helpful count, pros/cons and purchase location (detail enrichment)
reviewsCollectedhow many reviews were actually collected for this product
changeType / changedFields / firstSeenAt / lastSeenAtincremental mode only, see below

Every record also carries seoPath, urlKeyword, colour, multipackSize, unitsPerPack, brandUrl, itemsPerUnit, totalUnits, categoryPath, metaDescription, hasBusinessPrice, ratingScale, searchMode ("search" or "url") and source ("officeworks.com.au"). Products with no reviews leave rating, reviewCount, ratingDistribution and reviews absent rather than faked; reviewsCollected then reads 0.

How to Use

  1. Pick a mode: search (keyword and filters) or url (paste product, search, category or specials links).
  2. In search mode, add one or more keywords, or pick a Specials / offers collection (Deals or Clearance) instead of (or alongside) your keywords. Apply Brand, price, rating and sort filters as needed.
  3. Turn Fetch full product detail + reviews on (the default) for the complete description, specifications, gallery and customer reviews, or off for a faster, listing-only run.
  4. Set Max products to control run size and cost, then click Start.

Search by keyword with filters:

{
"mode": "search",
"queries": ["notebook"],
"brand": "Sample Brand",
"minPrice": 20,
"maxPrice": 200,
"minRating": 4,
"detailEnrichment": true,
"maxItems": 50
}

Browse the Clearance collection, cheapest first:

{
"mode": "search",
"queries": [],
"specialsCategory": "clearance",
"sortBy": "priceAsc",
"maxItems": 100
}

Paste a single product link:

{
"mode": "url",
"urls": ["https://www.officeworks.com.au/shop/officeworks/p/sample-product-sku"],
"detailEnrichment": true,
"maxReviewsPerProduct": 30
}

Paste a category link and track it on a schedule:

{
"mode": "url",
"urls": ["https://www.officeworks.com.au/shop/officeworks/c/office-supplies/pens/ballpoint-pens"],
"incrementalMode": true,
"maxItems": 0,
"maxPages": 0
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/officeworks-scraper").call(run_input={"mode": "search", "queries": ["notebook"]})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
print(product["name"], product["price"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/officeworks-scraper').call({ mode: 'search', queries: ['notebook'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Multiple keywords and specials in one run

Every keyword (and a specials collection, if chosen) is searched as its own target within the run, one after another, sharing the same overall dedup set. Pasted search and category links in url mode work the same way. That shared set has three real, confirmed side effects worth knowing:

  • Overlap is returned once. A product returned by an earlier target is never returned again by a later one in the same run, so the run total can be lower than the sum of each target searched on its own.
  • A later target can stop on its very first page. A target stops walking as soon as it reaches a page on which every product has already been handled. That check uses the run-wide set, so if a later target's first page is made up entirely of products an earlier target already handled (two near-synonymous keywords such as "pen" and "pens", for example), that target stops right there and its later pages, including products no earlier target returned, are never read in that run.
  • Products skipped by a cap still count as handled. When a page has more candidates than the remaining room (see below), the ones beyond the room are marked as handled without being returned. A later target in the same run then silently skips those products too, and can stop early on them as described above.

In incremental mode with emitExpired on, a target that stopped early this way still counts as fully scanned, so tracked products on its unread pages can be returned (and billed) as EXPIRED even though they are still listed; they come back as REAPPEARED on a later run that reads them. If you need every target's own complete result set, or you use emitExpired, run overlapping searches as separate actor runs (each with its own automatic state) instead of combining them into one queries or urls list.

How Max products and Max pages shape a run

Max products (maxItems) stops the whole run once that many products have been returned; Max pages (maxPages) caps how many result pages are walked per keyword or URL (0 = walk every page). On a capped run, a page's worth of candidates beyond the remaining room is not inspected in this run.

Incremental-mode tip: the remaining room for a page is computed before incremental mode knows which candidates will turn out UNCHANGED and get suppressed. Suppressed products still use up slots, so with a result page of up to 48 products and a maxItems below that (the default is 20), a new or changed product later on the same page can be skipped in this run even though the run ends well under maxItems. Worse, with emitExpired on: because suppressed products are not returned, such a run can still finish under maxItems and count as a complete scan, and then every tracked product that was skipped this way is returned (and billed) as EXPIRED even though it is still listed. Those products come back as REAPPEARED (billed again) on a later run that reaches them. Set maxItems to 0 (and leave maxPages at 0) for incremental runs, especially with emitExpired on.

Resume and recurring updates

There are two different things here, pick the one that matches what you're doing:

NeedUse
A crawl stopped and should continueresumeFromRunId
Run the same search every day and receive only changesincrementalMode
Keep separate daily campaigns for similar searchesdistinct stateKey values
Run a normal full snapshotleave both off

Resume (resumeFromRunId) continues one specific interrupted or previous crawl: paste a run ID or dataset ID and this run skips products already collected there, returning only the remaining new products. Two real, confirmed limits:

  • It can return nothing if the earlier run collected a whole first page. The resumed walk starts again from page 1, and a page on which every product was already collected ends that search or link. So if the earlier run returned every product on the first result page of a keyword or link (up to 48 products), the resumed run stops there and returns nothing for it, with a "No products matched" status, even though later pages were never collected. Resume works as intended only when the earlier run stopped part-way through the first page; otherwise re-run the search with a larger Max products instead.
  • Pasted product links are not skipped. In url mode, a pasted product link (/p/...) is matched by its link text rather than by its SKU, so resuming a run that already returned it fetches and returns (and bills) that product again. Remove already-collected product links from urls before resuming.

Incremental mode (incrementalMode) is for a schedule (for example, daily): the actor remembers the previous run of the same search by itself, so you never paste a run ID. The first run returns everything as NEW. Later runs return only NEW, UPDATED and REAPPEARED products by default; unchanged products are suppressed and not billed unless emitUnchanged is on. Turn on emitExpired to also get a tombstone row for a product that was tracked before but is no longer found; this only happens once a run counts as having fully scanned the tracked search (not when Max products or Max pages capped it, and not on a Resume run). A run can count as complete while still having skipped some listed products, so read the tips below and under Multiple keywords and specials in one run and How Max products and Max pages shape a run before relying on EXPIRED.

State is isolated per mode/search/URL/specials/brand/sort/price/rating/stock/detail setup automatically; set stateKey to name a campaign, or to deliberately share state across differently-configured runs.

Tips (real, confirmed behavior worth knowing before you rely on this):

  • emitExpired is not capped by Max products. Once a run proves it scanned the tracked search completely, every previously-tracked product that is no longer found is returned as EXPIRED in one batch, regardless of maxItems. If a monitored search shrinks a lot between runs (a big Clearance collection selling out, for example), the EXPIRED batch on that run can be much larger than your usual maxItems, and is billed accordingly. Turn emitExpired off, or expect and budget for an occasional larger run, if this matters to your costs.
  • Combining resumeFromRunId with a brand-new incrementalMode campaign bills one phantom UPDATED per resumed product on the very next scheduled run. Resuming into a fresh (first-ever) incremental baseline seeds that baseline from the resumed dataset without re-fetching those products, so their stored fingerprint is not yet known. The next scheduled run then reports every one of those products as UPDATED with every field listed under changedFields, even if nothing actually changed. It happens exactly once per product, right after that bootstrap; from then on comparisons are against a real fingerprint. If you don't want this, run a plain (non-incremental) resume first, then start incremental mode fresh from a normal full run.
  • Reusing the same stateKey for a materially different search is a real feature, but it can bill unrelated products as EXPIRED. If you deliberately point the same stateKey at a new keyword, URL or filter set, every product tracked under the old configuration that isn't rediscovered by the new one looks exactly like a product that disappeared, and (with emitExpired on) is billed as EXPIRED the moment a run under the new configuration completes a full scan. Only share a stateKey across scopes that are meant to be tracked together; leave it empty for anything else so each distinct search gets its own isolated, auto-derived state.
  • A run restarted by the platform (server migration or Resurrect) can report false EXPIRED rows. The restarted run continues from its saved position and skips the keywords, links and pages it had already finished, so it never re-checks the products handled before the restart. With emitExpired on, if the rest of the run completes, those products are returned (and billed) as EXPIRED, and come back as REAPPEARED on the next scheduled run. If an incremental run was migrated or resurrected, treat its EXPIRED rows with caution.

Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (keyword + filters) or url (scrape pasted URLs).
queriesarray["laptop"]One or more keywords to search (search mode). Each keyword is searched separately.
specialsCategorystring(none)Browse deals or clearance instead of (or alongside) your keywords.
urlsarraysample category URLProduct, search or category URLs to scrape (url mode).
brandstring(none)Keep only products whose brand matches this value.
sortBystringrelevancerelevance, newest, nameAsc, priceAsc, priceDesc, ratingAsc, or ratingDesc.
minPriceinteger(none)Only keep products priced at or above this amount (AUD).
maxPriceinteger(none)Only keep products priced at or below this amount (AUD).
minRatinginteger(none)Only keep products with an average rating at or above this value (1-5).
includeOutOfStockbooleantrueInclude products not currently available in-store or online.
detailEnrichmentbooleantrueFetch full product detail, specifications, gallery and reviews (one extra request per product).
maxReviewsPerProductinteger20Cap on reviews collected per product when detail enrichment is on (0 = all available).
maxItemsinteger20Maximum number of products to return across the whole run (0 = unlimited).
maxPagesinteger0Safety cap on result pages walked per keyword / URL (0 = walk every page).
resumeFromRunIdstring(none)ID of a previous run (or dataset) to continue from; already-collected products are skipped.
incrementalModebooleanfalseReturn only new and changed products on scheduled runs.
stateKeystring(none)Name or share an incremental-mode state. Left empty, a key is derived automatically from the search/filter setup.
emitUnchangedbooleanfalseAlso return (and bill) unchanged products (incremental mode only).
emitExpiredbooleanfalseAlso return (and bill) products no longer found (incremental mode only).
proxyobjectApify ProxyConnection settings.
mcpConnectorsarray(none)Optional: send a summary of each record to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which records are created.
maxNotifyListingsinteger50Cap on items written to each connector per run.

Output Example

Sample shape: values are illustrative placeholders, not from a live record.

{
"sku": "SAMPLE0001",
"name": "Sample A4 Display Book 20 Pocket",
"title": "Sample Brand A4 Display Book 20 Pocket",
"brand": "Sample Brand",
"url": "https://www.officeworks.com.au/shop/officeworks/p/sample-a4-display-book-sample0001",
"price": 12.5,
"edlpPrice": 12.5,
"wasPrice": null,
"savingsAmount": null,
"savingsPercent": null,
"isOnSpecial": true,
"promoLabel": "Deal",
"isNew": false,
"currency": "AUD",
"gstRate": 10.0,
"gtin": "9300000012345",
"manufacturerPartNumber": "SB-DB20",
"productType": "Display Books",
"availableStates": ["NSW", "VIC", "QLD"],
"isAvailableInStore": true,
"availableOnline": true,
"isClearance": false,
"category": "Display Books",
"categories": ["Office Supplies", "Folders & Filing", "Display Books"],
"categoryHierarchy": [["Office Supplies", "Folders & Filing", "Display Books"]],
"variantAxes": { "Colour": ["Blue", "Black"] },
"variantCount": 2,
"variants": [
{
"sku": "SAMPLE0001",
"url": "https://www.officeworks.com.au/shop/officeworks/p/sample-a4-display-book-sample0001",
"attributes": { "Colour": "Blue" },
"imageUrl": "https://www.officeworks.com.au/images/sample-thumb.jpg"
}
],
"shortDescription": "A durable display book for everyday filing.",
"features": ["20 pockets", "A4 size", "Reinforced spine"],
"specifications": { "Brand": "Sample Brand", "Pockets": "20" },
"imageUrl": "https://www.officeworks.com.au/images/sample.jpg",
"images": ["https://www.officeworks.com.au/images/sample.jpg"],
"rating": 4.3,
"reviewCount": 42,
"ratingDistribution": { "5": 20, "4": 12, "3": 6, "2": 2, "1": 2 },
"recommendedCount": 35,
"reviews": [
{
"reviewId": "SAMPLE-REVIEW-1",
"rating": 5,
"title": "Handy for the office",
"body": "Good quality and holds up well.",
"author": "SampleReviewer",
"date": "2026-03-01T09:00:00.000+00:00",
"helpfulCount": 2
}
],
"reviewsCollected": 1
}

Plan Requirement

The default proxy setting works out of the box, and the connection rotates and escalates automatically when a request is refused. For large or frequent runs, the residential proxy group gives more headroom; pick it under Connection.

FAQ

How much does it cost?

You pay per product returned, with detail enrichment billed only when you switch it on. The Pricing tab shows the current rates. Use Max products to cap the cost of any run.

This actor collects only publicly available product data. You are responsible for how you use it: follow Officeworks' terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices and specifications are generally facts, but product photos and review text may be subject to third-party rights.

Can I get only new or changed products on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and reappeared products, and unchanged ones are not billed by default.

Why did my run return fewer products than Max products, or a very large batch when Emit expired is on?

Max products stops a run once that many products have been returned; a capped page or a capped run does not go back for more. A run with several keywords or links can also stop a later one early when its first page overlaps products already handled, and an incremental run spends slots on unchanged products it then suppresses; see Multiple keywords and specials in one run and How Max products and Max pages shape a run. Separately, emitExpired is not limited by Max products: once a run fully scans the tracked search, every previously-tracked product no longer found is returned as EXPIRED in one batch, which can be larger than your usual Max products if the tracked search shrank a lot since the last run. See the tips under Resume and recurring updates.

Why does a product I resumed show up as UPDATED on the very next incremental run, even though nothing changed?

This happens exactly once, only when resumeFromRunId is combined with a brand-new incrementalMode campaign (no prior state for that stateKey). The resumed products are added to the new baseline without a real fingerprint yet, so the first comparison against them reports every field as changed. It does not repeat on later runs. See the tips under Resume and recurring updates.

Why did my run fail instead of returning an empty dataset?

If the connection is refused before any data could be read, the run stops with a clear message so "no products found" is never confused with "nothing could be read". Run it again in a few minutes. Separately, starting Incremental mode with Resume when that state key already has tracked products also fails on purpose, with a message telling you to drop Resume or pick a different State key, rather than silently mixing the two.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

🔗 Want more e-commerce data?

Pair this actor with these related scrapers from the same team:

👗 Myer Scraper
Scrape Myer (myer.com.au) department-store products: name, brand, price, was-price...
🛒 Harvey Norman Scraper
Scrape Harvey Norman Australia products: name, brand, price, was-price / discount...
🛒 Kmart Scraper
Scrape products and customer reviews from Kmart.com.au. Search by keyword or use...
🛒 BIG W Marketplace Scraper
Scrape BIG W Marketplace seller listings from bigw.com.au: name, brand, price, was-price...
🛒 Amazon Australia Product & Reviews Scraper
Scrape Amazon Australia (amazon.com.au) products and customer reviews. Search by keyword...
🛒 Bunnings Scraper
Scrape bunnings.com.au products with full specifications, price, brand, stock, image...

👉 Browse all abotapi scrapers

💬 Support & custom scrapers

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.