Harvey Norman Scraper - Products, Prices, Specs & Reviews ยท Apify
Harvey Norman Scraper - Products, Prices, Specs & Reviews avatar

Harvey Norman Scraper - Products, Prices, Specs & Reviews

Pricing

from $1.00 / 1,000 product results

Go to Apify Store
Harvey Norman Scraper - Products, Prices, Specs & Reviews

Harvey Norman Scraper - Products, Prices, Specs & Reviews

Scrape Harvey Norman Australia products: name, brand, price, was-price / discount, specifications, image gallery, GTIN, department, stock, dimensions, rating and customer reviews. Search by keyword with brand, price and rating filters, or paste product / listing URLs.

Pricing

from $1.00 / 1,000 product results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

5

Total users

0

Monthly active users

11 days ago

Last modified

Features

Limited permissions

Share

Harvey Norman Australia Scraper: Products, Prices & Reviews

Harvey Norman Australia Scraper turns harveynorman.com.au into a clean product data API. Get canonical title, brand, current and was-price, discount amount and percent, specifications, image gallery, GTIN, department, stock status, dimensions, rating and customer reviews for electrical, computer, furniture and bedding products. Search by keyword with filters, scrape the Super Deals or Clearance collections directly, or paste product and listing URLs, then 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 and listing URLs directly. Pick one per run; keywords and a Specials category can be combined within search mode.
  • Store-wide specials on demand. Scrape the Super Deals or Clearance collections directly, alongside or instead of your keywords, or paste any department-scoped sale listing URL.
  • One flat record per product. Identity, price, discount, rating and review count come back on every product, list view included, with no detail fetch required.
  • Full detail on demand. Switch on full specifications, image gallery, description, department, dimensions and reviews per run, and pay the enrichment surcharge only for products actually enriched. Pasted product URLs always get full detail; the toggle there only adds reviews.
  • Reviews with an aggregate summary. Per-review rating, body, author, date, verified-purchase flag and helpful votes, plus a star distribution and recommended count.
  • Unlimited catalogue walks. Set both Max pages per listing and Max products to 0 to walk an entire department; the run stops naturally once the storefront's own result total is reached, never on an artificial page cap.
  • Built for schedules. Incremental mode tracks a search across runs and returns only new and updated products by default, and a fully refused run fails loudly instead of returning an empty dataset.

Use Cases

  • Price monitoring and deal alerts: track current and was-prices, discount amounts and the on-special flag across a department or the Clearance range.
  • Competitive and assortment research: compare specifications, stock status and ratings across brands within a category.
  • Review and reputation analysis: collect per-review ratings, pros and cons and verified-purchase flags to spot recurring product issues.
  • Catalogue monitoring: schedule Incremental mode against a department or keyword to get only new and updated products every day (and removed ones too, with Emit expired on and no caps).

Data You Get

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

FieldExample
productId481027
skuOLED55ACM2026
title"Acme 55-inch 4K OLED Smart TV"
name"Acme 55-inch 4K OLED Smart TV"
brand"Acme" (detail enrichment, or pasted product URLs; null otherwise)
url"https://www.harveynorman.com.au/acme-55-inch-4k-oled-smart-tv.html"
imageUrl"https://www.harveynorman.com.au/media/catalog/product/a/c/acme-55-oled-front.jpg"
price / currency2895.0 / "AUD"
wasPrice3295.0
discountAmount / discountPercent400.0 / 12.14
isOnSpecial / promotiontrue / "Save $400"
rating / reviewCount4.64 / 87
brandUrl"https://www.harveynorman.com.au/brands/acme" (detail enrichment, or pasted product URLs)
description / shortDescriptionfull copy / one-line summary (detail enrichment, or pasted product URLs)
specifications{ "Screen Size": "55 inch", "Resolution": "4K Ultra HD", "Barcode (GTIN)": "9312345678901" } (detail enrichment, or pasted product URLs)
imagesarray of image URLs on the retailer's own site (detail enrichment, or pasted product URLs)
stockStatus"IN_STOCK"
gtin"9312345678901" (detail enrichment, or pasted product URLs)
department / category / categoryPath"Audio Visual" / "OLED TVs" / "tv-audio/tvs/oled-tvs" (detail enrichment, or pasted product URLs)
dimensions{ "height": 82.6, "depth": 4.5, "width": 124.4, "weight": 21.3, "colour": "Black" } (detail enrichment, or pasted product URLs)
mainFeaturesarray of feature-bullet strings (detail enrichment, or pasted product URLs)
ratingDistribution / recommendedCount{ "5": 66, "4": 15, "3": 3, "2": 2, "1": 1 } / 80
reviewsCollected / reviews20 / array of per-review objects (when detail enrichment is on, capped by Max reviews per product)

Enriched products may also carry offerType, cashback and specialToDate when the source page has them, plus the internal searchMode and source fields recording how the record was found. Each review inside reviews[] carries its own reviewId, rating, title, body, author, location, date, verifiedPurchase, isRecommended, helpfulCount, notHelpfulCount, isSyndicated, pros and cons.

How to Use

  1. Pick a mode: search (keywords and filters) or url (paste product or listing links).
  2. In search mode, add keywords and/or pick a Specials / offers category, then narrow with brand, minimum / maximum price and minimum rating, and order with sort by.
  3. Turn on Fetch full product detail + reviews if you need specifications, images, description and reviews; set Max reviews per product and Max products to control cost.
  4. Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.

Search by keyword with filters:

{
"mode": "search",
"queries": ["oled tv"],
"brand": "Acme",
"minPrice": 1000,
"maxPrice": 6000,
"sortBy": "priceDesc",
"maxItems": 50,
"proxy": { "useApifyProxy": true, "apifyProxyCountry": "AU" }
}

Scrape the store-wide Clearance range with full detail and reviews:

{
"mode": "search",
"specialsCategory": "clearance",
"detailEnrichment": true,
"maxReviewsPerProduct": 10,
"maxItems": 50,
"proxy": { "useApifyProxy": true, "apifyProxyCountry": "AU" }
}

Supported URL shapes (URL mode):

ShapeExampleResult
Product page (.html).../lg-65-inch-g6-evo-ai-4k-oled-smart-tv-2026.htmlOne product, full detail
Department listing.../computers-tablets/computers/laptopsEvery page of the listing
Paginated listing.../laptops?p=2Starts at that page (partial scope for incremental mode)
Search results.../catalogsearch/result/?q=oled+tvHandled exactly like the keyword oled tv in search mode
Specials.../super-deals, .../clearanceThe specials collection

Any other link (another site, the home page) is skipped with a warning in the run log, and a search link whose keyword finds nothing logs a warning. Behaviour change: when urls is left out in URL mode, the input now defaults to one example per shape above instead of an empty list.

Paste a product URL and a department listing URL:

{
"mode": "url",
"urls": [
"https://www.harveynorman.com.au/acme-55-inch-4k-oled-smart-tv.html",
"https://www.harveynorman.com.au/computers-tablets/computers/laptops"
],
"detailEnrichment": true,
"maxItems": 100
}

Daily monitoring of a search, changes only (uncapped so a complete scan is possible):

{
"mode": "search",
"queries": ["oled tv"],
"incrementalMode": true,
"emitExpired": true,
"maxItems": 0
}

Run it from your code

Python:

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

JavaScript:

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

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

Walking a whole catalogue

Max pages per listing defaults to 0, which walks every page of a keyword's resolved department or a pasted listing URL, with no artificial page cap; the walk stops naturally once the storefront's own page or result total is reached, or once a page repeats with no new products. Max products still defaults to 20 and bounds the whole run separately, so set it to 0 as well if you actually want a full department. Set Max pages per listing to a positive number only to cap how deep an individual search goes.

Resume and recurring updates

  • Resume (resumeFromRunId) skips products already collected in a previous run's dataset, so you don't pay twice for them. It works best when the listing order has changed since that run, or for a pasted list of product URLs; because a fresh Resume run starts its walk again from page 1, and the repeat-page guard checks the same seeded set, a listing whose order hasn't changed can end the walk almost immediately without returning the products you were hoping to continue collecting. A separate, automatic same-run checkpoint also protects against a platform migration or a Resurrect of a failed run, continuing the same run without re-pushing already-collected products.
  • Incremental mode (incrementalMode) is for a schedule (for example, daily) over the same search, specials category or URL set. The actor remembers each search's state itself, keyed on your search, filter and detail-enrichment setup (or on stateKey if you set one), so you never paste a run ID. Every returned record then also carries changeType, changedFields, firstSeenAt and lastSeenAt. The first run returns everything as NEW. Later runs return NEW and UPDATED products by default; UNCHANGED products are suppressed and not billed unless emitUnchanged is on. REAPPEARED only fires for a product that a prior run had already tombstoned EXPIRED; EXPIRED itself is only produced once a run has fully scanned every keyword, specials category and URL in scope with emitExpired on, and that run was not capped by Max products or Max pages, did not use Resume, and did not continue from a saved checkpoint. With incremental mode off, output is exactly as before.

What counts as a change. Every output field is compared (price, was price, discount, special flag, stock status, name, brand, description, specifications, categories) except these always-ignored fields: rating, reviewCount, ratingDistribution, recommendedCount, reviews, reviewsCollected, imageUrl, images, smallImage, promotion, promotionData, cashback, offers, priceRange, startingFromText, hidePrice, callToAction, callToActionUrl, urlKey, urlSuffix, metaTitle, metaDescription, metaKeyword and searchMode. Those stay in the output but never create an UPDATED row or appear in changedFields. Use Ignore fields when detecting changes (incremental mode only) (ignoreFieldsForChanges) to leave more fields out; dotted paths such as specifications.Colour drop a nested key.

Price and stock monitoring (all optional, off by default). Set changeScope to priceAndStock so a product is UPDATED only when its price, was price, discount, special flag or stock status moves. Turn on compactUpdates for slim UPDATED and EXPIRED rows (ids, url, name, current price and stock status, and priceChanges with old and new values); compact UPDATED rows carry no detail or reviews, so they carry no detail-enrichment charge. expireAfterMissedScans (default 1) marks a product EXPIRED only after it was missing from that many consecutive complete scans. EXPIRED means the product dropped out of the scanned listing, which a delisting and a temporary drop both cause; read stockStatus for availability. EXPIRED is also never produced for a pasted listing URL that starts after page 1, or when filters are combined with a shared stateKey, and EXPIRED rows never exceed Max products. Changing changeScope or ignoreFieldsForChanges keeps the same saved state: the stored products are compared again under the new rules, so it does not re-return the whole catalogue as NEW.

Send results into your apps (MCP connectors)

Pipe results straight into the tools 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 product, 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.
  3. For Notion, also set notionParentPageUrl to the page where product pages 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 (keywords and filters) or url (scrape pasted URLs).
queriesarrayprefill ["oled tv"]Keywords to search (search mode). Each keyword resolves to its best-matching department listing.
specialsCategorystring(none)Optional: scrape the super-deals or clearance collection instead of, or alongside, your keywords.
urlsarrayone example per URL shapeProduct or listing URLs to scrape (url mode).
brandstring(none)Keeps products whose name contains this text (case-insensitive substring match, not a structured brand field). Applied before detail enrichment, to both modes; dropped products are never collected or charged.
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 to 5).
sortBystringrelevance(relevance, priceAsc, priceDesc, ratingDesc, nameAsc, nameDesc; the aliases sort_by with values like price-ASC and keyword for queries are also accepted.) Ordering within each keyword or listing, not across the whole run. Any order other than relevance reads the whole listing first before applying the cap.
detailEnrichmentbooleanfalseOpen each product page for full specifications, image gallery, description and reviews. Adds one request per product and bills the detail-enrichment event for each row that reaches the dataset with its detail page read: one detail-enrichment unit per started block of 10 reviews delivered on the row, minimum 1 unit (the page read is included in the first block): 0 to 10 reviews = 1 unit, 11 to 20 = 2, 21 to 30 = 3. The count is the reviews actually returned on the row (capped by Max reviews per product), not the product's total review count. Rows that are suppressed, deduplicated, compact UPDATED or whose page could not be read add no units.
maxReviewsPerProductinteger20Cap on reviews collected per product when detail enrichment is on. 0 = all available, capped at 1000 per product.
maxItemsinteger20Maximum number of products to return across the whole run. 0 = unlimited.
maxPagesinteger0Cap on result pages walked per keyword or URL. 0 = unlimited: walk every page until the storefront's own total is reached or a page repeats with no new products.
resumeFromRunIdstring(none)ID of a previous run of this actor, or a dataset ID. Products already in that dataset are skipped. Best for a pasted list of product URLs, or a listing whose order has changed since that run, see "Resume and recurring updates" above.
incrementalModebooleanfalseTurn on for daily or recurring monitoring. Returns only new, updated and (when eligible) reappeared or expired products on later runs.
stateKeystring(none)Name this monitoring campaign, or deliberately share state across differently-configured runs. Leave empty to derive a key automatically from your search and filter setup.
emitUnchangedbooleanfalseIncremental mode only. Also return, and bill, products unchanged since the last run.
emitExpiredbooleanfalseIncremental mode only. Also return, and bill, products no longer found, once a run has fully scanned the tracked search.
changeScopestringallIncremental mode only. priceAndStock marks a product UPDATED only when price or stock status moves.
compactUpdatesbooleanfalseIncremental mode only. Slim UPDATED and EXPIRED rows with priceChanges.
expireAfterMissedScansinteger1Incremental mode only. Consecutive complete scans a product must be missing before it is EXPIRED.
ignoreFieldsForChangesarray(none)Incremental mode only. Fields (dotted paths allowed) left out of change detection.
proxyobjectApify Proxy (standard pool, AU)Connection settings. Residential (AU) is optional.
mcpConnectorsarray(none)Optional: send a summary of each product to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which product pages are created. Ignored by other connectors.
maxNotifyListingsinteger50Cap on items written to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live record. reviews is shown truncated to one entry for brevity; reviewsCollected reflects the full count.

{
"productId": 481027,
"sku": "OLED55ACM2026",
"title": "Acme 55-inch 4K OLED Smart TV",
"name": "Acme 55-inch 4K OLED Smart TV",
"brand": "Acme",
"url": "https://www.harveynorman.com.au/acme-55-inch-4k-oled-smart-tv.html",
"imageUrl": "https://www.harveynorman.com.au/media/catalog/product/a/c/acme-55-oled-front.jpg",
"price": 2895.0,
"wasPrice": 3295.0,
"discountAmount": 400.0,
"discountPercent": 12.14,
"isOnSpecial": true,
"promotion": "Save $400",
"currency": "AUD",
"rating": 4.64,
"reviewCount": 87,
"brandUrl": "https://www.harveynorman.com.au/brands/acme",
"description": "Key features: vivid OLED panel with deep blacks and wide viewing angles...",
"shortDescription": "A 55-inch 4K OLED television with smart features and low-latency gaming.",
"specifications": {
"Product Type": "OLED TVs",
"Screen Size": "55 inch",
"Resolution": "4K Ultra HD",
"Barcode (GTIN)": "9312345678901"
},
"images": [
"https://www.harveynorman.com.au/media/catalog/product/a/c/acme-55-oled-front.jpg",
"https://www.harveynorman.com.au/media/catalog/product/a/c/acme-55-oled-side.jpg"
],
"stockStatus": "IN_STOCK",
"gtin": "9312345678901",
"department": "Audio Visual",
"category": "OLED TVs",
"categoryPath": "tv-audio/tvs/oled-tvs",
"dimensions": { "height": 82.6, "depth": 4.5, "width": 124.4, "weight": 21.3, "colour": "Black" },
"ratingDistribution": { "5": 66, "4": 15, "3": 3, "2": 2, "1": 1 },
"recommendedCount": 80,
"reviewsCollected": 20,
"reviews": [
{
"reviewId": "700000001",
"rating": 5,
"title": "Great picture for the price",
"body": "Deep blacks and vivid colour, very happy with this TV.",
"author": "SampleShopper",
"location": "VIC",
"date": "2026-04-12T10:30:00.000+00:00",
"verifiedPurchase": true,
"isRecommended": true,
"helpfulCount": 3,
"notHelpfulCount": 0,
"isSyndicated": false,
"pros": ["Picture quality"],
"cons": null
}
]
}

Output views

The dataset has four views in the Console: Products (price, was-price, stock, rating, change columns), Product details (specifications, gallery, dimensions, features, rating distribution), Reviews (one row per review, expanded from reviews[]) and Changes (incremental mode) (change type, changed fields, price changes). A summary of the run is saved to the key-value store under OUTPUT.

Plan Requirement

The storefront sits behind an anti-bot interstitial that answers with an ordinary 200 status instead of an error, so a plain datacenter connection is not reliable here and the run needs a clearance step for every connection it uses. Apify Proxy (AU) is selected by default under Connection; the run opens the standard pool first and, if the platform refuses that connection for your account, moves on to Apify Residential (AU) and then to a backup connection. Residential access requires a paid Apify plan; free plans do not include it. Custom proxy URLs are also supported, in which case no backup connections are used.

What you will see in the run log:

  • When the selected connection is refused: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable. For residential access, upgrade at https://apify.com/pricing or supply your own proxy URLs."
  • When the backup connection served data: "Served over the backup connection (the default connection was unavailable)."
  • When nothing could be read, the run fails with one of three messages instead of returning an empty dataset: the proxy connection was refused for this account and a paid plan is required (all connections refused); no results because residential proxies are unavailable on this run and the backup connection could not load the requested Harvey Norman pages (free plan); or "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

Pricing

Pay per event. Two events exist: one charge per product row delivered to the dataset, and the detail-enrichment charge for products whose full detail page was read and merged. Detail enrichment bills one detail-enrichment unit per started block of 10 reviews delivered on the row, minimum 1 unit (the page read is included in the first block): 0 to 10 reviews = 1 unit, 11 to 20 = 2, 21 to 30 = 3. The count is the reviews actually returned on the row (capped by Max reviews per product), not the product's total review count, only for rows actually pushed. Unchanged, suppressed, deduplicated and failed products are never charged. Current rates are on the Pricing tab. Cap any run with Max products.

FAQ

How much does it cost?

You pay per product returned, plus the detail-enrichment surcharge for each product whose page was actually read and merged into the dataset. That surcharge is one detail-enrichment unit per started block of 10 reviews delivered on the row, minimum 1 unit (the page read is included in the first block): 0 to 10 reviews = 1 unit, 11 to 20 = 2, 21 to 30 = 3. The count is the reviews actually returned on the row (capped by Max reviews per product), not the product's total review count, so a product with 25 reviews delivered bills 3 units and one with 8 bills 1, whatever its total review count; a product whose page could not be read is not charged for it. 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 Harvey Norman's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Product images, descriptions and customer reviews 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. Later runs then return only new and updated products; unchanged ones are neither returned nor billed unless you turn on Emit unchanged.

What's the difference between Resume and Incremental mode?

Resume (resumeFromRunId) continues one specific interrupted or earlier crawl by skipping products already in a pasted run or dataset. Incremental mode is for running the exact same search again and again on a schedule; it remembers the state itself, so you never paste a run ID.

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

If every request to Harvey Norman was refused, the run stops with a clear connection message instead of completing with zero products, so "no matches" is never confused with "nothing could be read". Run it again in a few minutes, or check the connection warnings in the run log.

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:

๐Ÿ›’ BIG W Marketplace Scraper
Scrape BIG W Marketplace seller listings from bigw.com.au: name, brand, price, was-price...
๐Ÿ›’ Target AU Scraper
Scrape products and customer reviews from Target.com.au. Search by keyword or use...
๐Ÿ›’ Amazon Australia Product & Reviews Scraper
Scrape Amazon Australia (amazon.com.au) products and customer reviews. Search by keyword...
๐Ÿ›’ Officeworks Scraper
Scrape Officeworks products by keyword, category, or URL. Extract names, brands, prices...
๐Ÿ›’ Costco AU Scraper
Scrape Costco.com.au products by keyword or product, search and category URLs. Extract...
๐Ÿ›’ Bunnings Scraper
Scrape bunnings.com.au products with full specifications, price, brand, stock, image...

๐Ÿ‘‰ Browse all abotapi scrapers

๐Ÿ’ฌ Support

  • ๐Ÿž 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 contact@abotapi.com.
  • โญ Enjoying it? A quick review on the actor page helps other users find it.