# JB Hi-Fi AU Scraper - Products, Prices, Stock & Reviews (`abotapi/jbhifi-com-au-product-scraper`) Actor

Scrape JB Hi-Fi Australia (jbhifi.com.au) products from the public storefront. Extract product listings, categories, prices, stock availability and customer reviews. Supports product search and category browsing.

- **URL**: https://apify.com/abotapi/jbhifi-com-au-product-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 product records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## JB Hi-Fi AU Product Scraper

Scrape JB Hi-Fi Australia product search results, categories, prices, availability and reviews from the public storefront. Search by keyword with server-side sorting, facet filters, price bounds and an on-sale filter, or paste product, collection and search links. Every record carries the full card surface: identity, brand, category, price with the GST split, was-price and savings, availability matrix, rating and review counts, image gallery, promotion flags and marketplace seller.

### Why This Scraper?

- **One actor instead of three.** Rival JB Hi-Fi actors split keyword discovery, product parsing and review parsing across three separate actors, each charging separately for the same data. This actor covers keyword search, product records and reviews in a single run.
- **Card-complete rows.** Each result ships 45+ fields straight from the store's own search index: pricing including the GST breakdown, was-price and save amount, delivery and click-and-collect status, store stock counts, release dates, promotion and clearance tags, and the marketplace seller.
- **Real search powers.** Facet filters (brand, seller, category, merchandising tags), minimum and maximum price, an on-promotion switch and four server-side sort orders narrow results at the source, not in post.
- **Reviews without a second actor.** Enable Fetch reviews and every product row carries its customer reviews as a nested list, with a one-row-per-review output tab for spreadsheets.
- **Built for schedules.** Resume past runs, or run incremental mode so a scheduled recurring run pushes only what is new or changed.

### Use Cases

- **Who:** Price trackers monitoring JB Hi-Fi AU catalogues for drops, promotions and clearance events.
- **Who:** Marketplace analytics teams following seller (Sold by) coverage and marketplace share.
- **Who:** Affiliate and comparison sites that need clean product records with prices, availability and images.
- **Who:** Review aggregators collecting customer reviews joined to their products.

### Data You Get

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

| Field | Example |
| --- | --- |
| `title` | Apple iPhone 18 Pro 512GB (Burgundy) |
| `brand` | APPLE |
| `category` | COMMUNICATIONS |
| `price` | 2499.0 |
| `wasPrice` | 2699.0 |
| `saveAmount` | 200.0 |
| `taxGst` | 227.18 |
| `availability` | InStock |
| `deliveryStatus` | InStock |
| `clickNCollectStatus` | InStock |
| `rating` | 4.5 |
| `reviewCount` | 8 |
| `onPromotion` | true |
| `model` | "MJRW4X/A" |
| `barcode` | "195951417325" |
| `keyFeatures` | bullet list from the product page's Key Features |
| `graphicAttributes` | spec-style icon attributes: "Network compatibility: 5G" |
| `condition` | "As New" (refurb and marketplace products) |
| `offerTiers` | one entry per marketplace seller: price, availability, shipping |
| `limitPerOrder` | 2 |
| `packagedDimensions` | height / width / depth / weight |
| `soldBy` | Hobbyco |
| `releaseDate` | 2026-10-18T02:00:00Z |
| `imageUrl` | https://cdn.shopify.com/... |
| `url` | https://www.jbhifi.com.au/products/apple-iphone-18-pro-512gb-burgundy |

### How to Use

Pick a mode: `search` browses the store by keyword with filters, sorting and pagination; `urls` walks the exact links you paste. Turn on `fetchDetails` for the long description, key features and specification table; turn on `fetchReviews` for customer reviews. Use `incrementalMode` for scheduled recurring runs so only new and changed products are pushed.

#### Example inputs

**Search by keyword (cheapest first):**

```json
{
  "mode": "search",
  "query": "iphone",
  "sortBy": "price-asc",
  "maxItems": 50
}
```

**Filtered browse (brand, price bounds, on promotion):**

```json
{
  "mode": "search",
  "query": "laptop",
  "facets": ["Brand:Apple"],
  "minPrice": 1500,
  "maxPrice": 4000,
  "onPromotionOnly": true,
  "fetchDetails": true,
  "maxItems": 100
}
```

**Walk pasted links (product, collection, search, bare SKU):**

```json
{
  "mode": "urls",
  "startUrls": [
    "https://www.jbhifi.com.au/products/apple-iphone-18-pro-512gb-burgundy",
    "https://www.jbhifi.com.au/collections/tvs",
    "https://www.jbhifi.com.au/search?query=sony",
    "922105"
  ],
  "fetchDetails": true,
  "fetchReviews": true,
  "maxItems": 100
}
```

**Scheduled incremental monitoring (named baseline):**

```json
{
  "mode": "search",
  "query": "playstation 5",
  "incrementalMode": true,
  "stateKey": "ps5-monitor",
  "maxItems": 200
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("abotapi/jbhifi-com-au-product-scraper").call(run_input={
    "mode": "search",
    "query": "iphone",
    "sortBy": "price-asc",
    "maxItems": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["price"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('abotapi/jbhifi-com-au-product-scraper').call({
    mode: 'search',
    query: 'iphone',
    maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((i) => [i.title, i.price]));
```

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | select | `search` | `search` browses by keyword; `urls` walks pasted links. |
| `query` | string | `iphone` | Search keyword (an omitted keyword falls back to `iphone`). |
| `category` | string | (empty) | Restrict results to one collection handle, e.g. `tvs`. |
| `sortBy` | select | `relevance` | `relevance`, `price-asc`, `price-desc`, `rating-desc`. Server-side sort. |
| `facets` | list | (empty) | Facet tokens that narrow results, e.g. `Brand:Apple`, `Sold by:Hobbyco`, `tag:Red Hot Deal`. |
| `minPrice` | number | (empty) | Only products priced at or above this amount in AUD. |
| `maxPrice` | number | (empty) | Only products priced at or below this amount in AUD. |
| `onPromotionOnly` | boolean | `false` | Only products the store flags as on promotion. |
| `startUrls` | list | 3 live examples | URLs mode: product, collection and search links, or bare SKUs. |
| `fetchDetails` | boolean | `false` | Read description, key features, specifications, barcode and options per product. |
| `fetchReviews` | boolean | `false` | Read customer reviews per product into the nested `reviews` list. |
| `maxReviews` | number | `20` | Reviews fetched per product when Fetch reviews is on. |
| `maxItems` | number | `20` | The only cap that stops a run early. |
| `maxPages` | number | `0` | Page cap per scope; `0` walks to the scope's natural end and defers to Max items. |
| `resumeFromRunId` | string | (empty) | Skip products already in a previous run's dataset. |
| `incrementalMode` | boolean | `false` | Detect changes against a saved scope baseline. |
| `emitUnchanged` | boolean | `false` | Incremental mode: also push unchanged records with changeType UNCHANGED. |
| `emitExpired` | boolean | `false` | Incremental mode: push records absent from a complete scan with changeType EXPIRED. |
| `ignoreFieldsForChanges` | list | (empty) | Extra fields whose changes never mark a row UPDATED. |
| `mcpConnectors` | select | (empty) | Export results to your apps via managed connectors. |
| `notionParentPageUrl` | string | (empty) | Notion connector: parent page URL the results are written under. |
| `maxNotifyListings` | number | `50` | Cap on how many records the connector export writes per run. |
| `stateKey` | string | (empty) | Named baseline for incremental mode; empty derives one from the run scope. |
| `proxyConfiguration` | object | standard pool | Connection used for store requests; Residential recommended for long scheduled runs. |

### Output Example

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

```json
{
  "recordType": "product",
  "recordId": "0000000000000",
  "sku": "000000",
  "handle": "sample-brand-soundbar-300",
  "url": "https://www.jbhifi.com.au/products/sample-brand-soundbar-300",
  "title": "Sample Brand SoundBar 300",
  "brand": "SAMPLE BRAND",
  "category": "AUDIO",
  "currency": "AUD",
  "price": 299.0,
  "priceExGst": 271.82,
  "taxGst": 27.18,
  "availability": "InStock",
  "canBuyOnline": true,
  "rating": 4.6,
  "reviewCount": 12,
  "onPromotion": false,
  "isMarketplace": false,
  "imageUrl": "https://cdn.shopify.com/s/files/1/0024/9803/5810/files/sample.jpg",
  "changeType": "NEW",
  "firstSeenAt": "2026-10-24T12:00:00Z",
  "lastSeenAt": "2026-10-24T12:00:00Z"
}
```

**Caption:** one product record as pushed to the default dataset.

The `detail` output tab adds `description`, `keyFeatures`, `specs` (label and value pairs), `barcode` and structured `options` when Fetch product details is on. The `reviews` tab unwinds the nested review list to one row per review. The `changes` tab shows `changeType`, `changedFields` and baseline timestamps in incremental mode.

### Plan Requirement

This actor runs on any Apify paid plan at the standard connection pool. The store serves the standard pool reliably; Residential is recommended for the most reliable long scheduled runs and can be selected under Connection. Runs bill per product record, with optional per-product detail and review enrichment events when their toggles are on.

### FAQ

#### How much does it cost to run?

Each product record bills one dataset-item event; detail and review enrichment bill their own small events only when the corresponding toggles are on and rows are committed. A 20-item card-only run is a fraction of a cent of event charges plus platform compute.

#### Is it legal to scrape jbhifi.com.au?

The actor reads the same public product pages and search interfaces a browser loads, without logging in and without bypassing any protection. You remain responsible for complying with the store's terms and applicable law, and for what you do with the data.

#### Can I schedule recurring runs?

Yes. Use incremental mode with a fixed State key: each scheduled run classifies products as NEW, UPDATED, UNCHANGED or EXPIRED against the saved baseline and pushes only what changed by default. Resume from run id is the alternative when you simply want to skip what a previous run already delivered.

#### Why does a run finish with 0 items?

A run that finished with a clear status but no records usually means the keyword or filters genuinely matched nothing; try the same keyword on the site. A run that fails with a connection message means the store could not be reached that minute; retries and Residential under Connection usually resolve it.

#### Can I use the results with AI tools?

Yes. The dataset is plain JSON and works with any Apify MCP connector or vector pipeline; select a connector under the MCP section and the run exports automatically.

### Send results into your apps (MCP connectors)

Select one or more managed connectors under the MCP section and the run exports its dataset automatically. The Notion connector writes records under a parent page you choose (capped by the max export input), so a scheduled run can keep a Notion database in step with the store.

### 🔗 More scrapers you might like

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

<table>
<tr><td>🛒 <a href="https://apify.com/abotapi/officeworks-scraper"><b>Officeworks Scraper</b></a><br>Scrape Officeworks products by keyword, category, or URL. Extract names, brands, prices...</td><td>🛒 <a href="https://apify.com/abotapi/kmart-au-scraper"><b>Kmart Scraper</b></a><br>Scrape products and customer reviews from Kmart.com.au. Search by keyword or use...</td></tr>
<tr><td>🛒 <a href="https://apify.com/abotapi/target-au-scraper"><b>Target AU Scraper</b></a><br>Scrape products and customer reviews from Target.com.au. Search by keyword or use...</td><td>🛒 <a href="https://apify.com/abotapi/myer-au-scraper"><b>Myer Scraper</b></a><br>Scrape Myer (myer.com.au) department-store products: name, brand, price, was-price...</td></tr>
<tr><td>🛒 <a href="https://apify.com/abotapi/chemistwarehouse-com-au-scraper"><b>Chemist Warehouse AU</b></a><br>Scrape chemistwarehouse.com.au products with prices, RRP, discounts, stock, images...</td><td>🛒 <a href="https://apify.com/abotapi/costco-au-scraper"><b>Costco AU Scraper</b></a><br>Scrape Costco.com.au products by keyword or product, search and category URLs. Extract...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/jbhifi-com-au-product-scraper/issues/open). 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.

# Actor input Schema

## `mode` (type: `string`):

search: keyword browse with filters, sorting and pagination. urls: walk pasted product, collection or search links (bare SKUs also accepted).

## `query` (type: `string`):

Search mode: keyword to browse. An omitted keyword falls back to iphone at runtime.

## `category` (type: `string`):

Search mode: restrict results to one store collection handle, e.g. tvs or laptops.

## `sortBy` (type: `string`):

Search mode: result order. Server-side sort, not a client-side reorder.

## `facets` (type: `array`):

Search mode: repeatable facet tokens that narrow results server-side. Token shape is name:value, e.g. Brand:Apple, Sold by:Hobbyco, Category:Desktops, tag:Red Hot Deal, banner:Clearance.

## `minPrice` (type: `integer`):

Search mode: only return products priced at or above this amount in AUD.

## `maxPrice` (type: `integer`):

Search mode: only return products priced at or below this amount in AUD.

## `onPromotionOnly` (type: `boolean`):

Search mode: return only products currently flagged as on promotion by the store.

## `startUrls` (type: `array`):

URLs mode: product pages, collection pages and search-result links (one per line). Bare product SKUs are also accepted. The preloaded examples carry one live example of every accepted shape.

## `fetchDetails` (type: `boolean`):

Read each product's detail surfaces and fill description, keyFeatures, specs, barcode and options on the row. Off keeps the fast card-only record.

## `fetchReviews` (type: `boolean`):

Read customer reviews for each product (requires a known SKU). Reviews attach to the product row as a nested list; a Reviews output tab unwinds them to one row per review.

## `maxReviews` (type: `integer`):

Reviews fetched per product when Fetch reviews is on. 0 skips review reads.

## `maxItems` (type: `integer`):

Maximum number of product records to push. This is the only cap that stops a run early.

## `maxPages` (type: `integer`):

Maximum result pages walked per search or collection scope. 0 means no page cap: the walk runs to the scope's natural end and Max items remains the only limit that stops a run early.

## `proxyConfiguration` (type: `object`):

Connection used for the store requests. The store serves the standard pool reliably; Residential is recommended for the most reliable long scheduled runs.

## `resumeFromRunId` (type: `string`):

Skip products already present in a previous run's dataset (its default dataset id or run id). Cannot be combined with incremental mode.

## `incrementalMode` (type: `boolean`):

Detect changes against a saved baseline keyed to this run's scope. New and changed products are pushed with changeType NEW or UPDATED; unchanged products are suppressed. The comparison covers every record field except the ignored list below.

## `stateKey` (type: `string`):

Named baseline for incremental mode. Leave empty to derive the baseline from the run scope automatically.

## `emitUnchanged` (type: `boolean`):

Incremental mode: also push unchanged products with changeType UNCHANGED.

## `emitExpired` (type: `boolean`):

Incremental mode: push products seen in a previous complete scan but absent from this one with changeType EXPIRED. Skipped when the run was capped, resumed or a page read failed.

## `ignoreFieldsForChanges` (type: `array`):

Incremental mode: field names whose changes never mark a row UPDATED (in-store availability counts change without the product changing). The built-in defaults are inStockStoreCount plus the bookkeeping fields.

## `mcpConnectors` (type: `array`):

Send results into your apps (MCP connectors). Pick one or more managed connectors and the run exports the dataset to them at the end.

## `notionParentPageUrl` (type: `string`):

When the Notion connector is selected: the parent page URL the results are written under.

## `maxNotifyListings` (type: `integer`):

Cap on how many records the connector export writes per run.

## Actor input object example

```json
{
  "mode": "search",
  "query": "iphone",
  "sortBy": "relevance",
  "onPromotionOnly": false,
  "startUrls": [
    "https://www.jbhifi.com.au/products/apple-iphone-18-pro-512gb-burgundy",
    "https://www.jbhifi.com.au/collections/tvs",
    "https://www.jbhifi.com.au/search?query=iphone"
  ],
  "fetchDetails": false,
  "fetchReviews": false,
  "maxReviews": 20,
  "maxItems": 20,
  "maxPages": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

One row per product with the card surface: identity, brand, category, price and GST split, availability, rating, promotion and marketplace flags.

## `detail` (type: `string`):

Products joined with their detail surfaces: long description, key features, specification pairs, barcode, structured options and the review rating distribution.

## `reviews` (type: `string`):

Customer reviews unwound to one row per review, joined with the product they belong to.

## `changes` (type: `string`):

Incremental mode view: every record with its change type, changed fields and baseline timestamps.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "search",
    "query": "iphone",
    "sortBy": "relevance",
    "startUrls": [
        "https://www.jbhifi.com.au/products/apple-iphone-18-pro-512gb-burgundy",
        "https://www.jbhifi.com.au/collections/tvs",
        "https://www.jbhifi.com.au/search?query=iphone"
    ],
    "maxReviews": 20,
    "maxItems": 20,
    "maxPages": 0,
    "proxyConfiguration": {
        "useApifyProxy": true
    },
    "maxNotifyListings": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/jbhifi-com-au-product-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "search",
    "query": "iphone",
    "sortBy": "relevance",
    "startUrls": [
        "https://www.jbhifi.com.au/products/apple-iphone-18-pro-512gb-burgundy",
        "https://www.jbhifi.com.au/collections/tvs",
        "https://www.jbhifi.com.au/search?query=iphone",
    ],
    "maxReviews": 20,
    "maxItems": 20,
    "maxPages": 0,
    "proxyConfiguration": { "useApifyProxy": True },
    "maxNotifyListings": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/jbhifi-com-au-product-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "search",
  "query": "iphone",
  "sortBy": "relevance",
  "startUrls": [
    "https://www.jbhifi.com.au/products/apple-iphone-18-pro-512gb-burgundy",
    "https://www.jbhifi.com.au/collections/tvs",
    "https://www.jbhifi.com.au/search?query=iphone"
  ],
  "maxReviews": 20,
  "maxItems": 20,
  "maxPages": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50
}' |
apify call abotapi/jbhifi-com-au-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/jbhifi-com-au-product-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/C50hTuaYGqMZfM1kC/builds/H4iWI2x7U0RvZGhZe/openapi.json
