# PB Tech Scraper - Products, Specs, Stock & Reviews (`abotapi/pbtech-co-nz-scraper`) Actor

Scrape pbtech.co.nz products with full specifications, price, brand, condition, per-store stock, image gallery, customer reviews and rating stats. Search by keyword and department with brand, price, rating and sort filters, or paste product / category / search URLs.

- **URL**: https://apify.com/abotapi/pbtech-co-nz-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Developer tools, Automation
- **Features:** Limited permissions
- **Stats:** 4 total users, 1 monthly users, 96.7% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 product results

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

## PB Tech Scraper: Products, Prices, Clearance Deals & Reviews

PB Tech Scraper turns pbtech.co.nz, New Zealand's electronics, computer and tech retailer, into a clean product data feed. Search by keyword or browse the clearance grid, or paste product, category, search and clearance URLs directly. Every product comes back as one flat record with identity, price, was-price and discount on clearance items, brand, condition, availability, per-store stock, full specifications, an image gallery, and native customer reviews with aggregate rating stats. Export to JSON, CSV or Excel, pull results through the API, or pipe them into the apps you already use.

### Why This Scraper?

- **Two ways in.** Keyword search with brand, price and rating filters plus sorting, or paste exact product, category, search or clearance URLs (paste a category link to browse a whole department).
- **Clearance as a first-class listing.** Browse PB Tech's clearance grid the same way as any category, either by setting the specials category to clearance or by pasting the clearance URL directly.
- **Genuine discounts only.** `originalPrice`, `discountPercent` and `savings` are populated only from a real reference price the store itself publishes next to a clearance item; an ordinary, non-discounted product always reports `originalPrice: null` rather than a guessed figure.
- **Rich product detail.** Name, brand, product code, SKU, manufacturer part number, barcode, price, condition, availability, breadcrumb categories, a full specification sheet and an image gallery.
- **Per-store stock.** Live unit counts across PB Tech branches, plus a total in-store stock figure.
- **Native customer reviews.** Title, body, author, date, verified-owner flag and helpful votes per review, plus the average rating, review count and a star-by-star breakdown.
- **Fails loudly when blocked.** If every connection to the store is refused before any page can load, the run stops with a clear, actionable message instead of finishing with a silent, empty dataset.

### Use Cases

- **Price and deal tracking:** watch the clearance listing and everyday prices to catch a genuine discount before it disappears.
- **Product research:** compare specifications, brand and price across laptops, monitors, peripherals and other categories before buying.
- **Retail intelligence:** benchmark assortment, pricing and stock levels against other electronics retailers.
- **Review analysis:** mine native customer reviews and rating breakdowns for a product line.
- **Content and merchandising:** pull specifications and images to build comparison pages or product feeds.

### Data You Get

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

| Field | Example |
| --- | --- |
| `code` | `"LPTDEMO123456"` |
| `sku` | `"LPTDEMO123456"` |
| `mpn` | `"KV-3350X"` |
| `gtin` | `"9412345000019"` |
| `name` | `"Kelvara SwiftBook 14 Laptop 16GB RAM 512GB SSD"` |
| `brand` | `"Kelvara"` |
| `price` | `1249.0` |
| `originalPrice` | `1479.0` |
| `discountPercent` | `15.6` |
| `savings` | `230.0` |
| `promotion` | `"Use promo code WINTERDEAL to save"` |
| `currency` | `"NZD"` |
| `availability` | `"In stock"` (also `"Out of stock"`, `"Pre-order"`, `"Back-order"`, `"Discontinued"`, `"Limited availability"`) |
| `condition` | `"New"` |
| `categories` | `["Computers", "Laptops", "Ultrabooks"]` |
| `specifications` | `{"CPU": "Kelvara N7 8-core", "RAM": "16GB", "Storage": "512GB SSD"}` |
| `images` | `["https://www.pbtech.co.nz/imgprod/L/P/LPTDEMO123456__1.jpg"]` |
| `rating` | `4.5` |
| `reviewCount` | `27` |
| `ratingBreakdown` | `{"5": 18, "4": 6, "3": 2, "2": 0, "1": 1}` |
| `storeStock` | `[{"branch": "Sample Store - North", "stock": 5}]` |
| `totalStoreStock` | `7` |
| `specialsCategory` | `"clearance"` (`null` for an ordinary search or category row) |
| `url` | `"https://www.pbtech.co.nz/product/LPTDEMO123456"` |

Each record also carries a `basePrice` (the product page's own undiscounted list price), a `priceValidUntil` date, `seller`, `model`, a free-text `description` and a `specificationsText` summary, a plain `imageUrl` (the first image in the gallery), and `searchMode`/`source` provenance fields. With customer reviews switched on, a `reviews` array is added with one entry per review (`author`, `date`, `title`, `body`, `attributes`, `verifiedOwner`, `helpfulVotes`, `totalVotes`). No review photos are collected because the site exposes none, and no size or colour variant matrix or per-unit price is emitted because PB Tech's own product pages do not carry either.

### How to Use

1. Pick a **mode**: `search` (keyword, with filters) or `url` (paste product, category, search or clearance links).
2. In search mode, add keywords and optional brand, price and rating filters, or switch to the clearance listing instead.
3. Turn product detail and customer reviews on or off, and set **Max products** to control run size and cost.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

**Search with filters and sort:**

```json
{
  "mode": "search",
  "queries": ["laptop"],
  "brand": "ASUS",
  "minPrice": 800,
  "maxPrice": 2500,
  "sortBy": "priceAsc",
  "fetchDetails": true,
  "maxItems": 20
}
```

**Browse the clearance listing:**

```json
{
  "mode": "search",
  "specialsCategory": "clearance",
  "fetchDetails": true,
  "maxItems": 10
}
```

**Default URL list:** if you switch to `url` mode and leave the `urls` field untouched, the actor scrapes the 7 prefilled example links, one per distinct supported shape (category, sub-category, department, product, keyword search, clearance, brand page). Near-duplicate variants such as `pg=` or `sf=` parameters, the `/promotions/clearance` path, the non-www host or the http scheme resolve to the same listing as one of these and are accepted but not listed. Those examples are still capped by **Max products**. Replace the list with your own links to scrape only those. Category and brand pages return the full listing whatever `pg=` or `sf=` they carry (the site does not paginate or filter by those parameters; use the Brand filter instead). The defaults apply only in `url` mode; in `search` mode they are ignored.

**Paste a category URL to browse a whole department:**

```json
{
  "mode": "url",
  "urls": ["https://www.pbtech.co.nz/category/computers/laptops"],
  "fetchDetails": false,
  "maxItems": 10
}
```

**Search with full detail and customer reviews:**

```json
{
  "mode": "search",
  "queries": ["laptop"],
  "fetchDetails": true,
  "fetchReviews": true,
  "maxReviewsPerProduct": 10,
  "maxItems": 5
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/pbtech-co-nz-scraper").call(run_input={"mode": "search", "queries": ["laptop"], "maxItems": 10})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(product["name"], product["price"], product["availability"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/pbtech-co-nz-scraper').call({ mode: 'search', queries: ['laptop'], maxItems: 10 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

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

#### Incremental monitoring and resume

Turn on `incrementalMode` to run the same search on a schedule and get only what changed. The first run returns every matching product as NEW. Later runs return NEW, UPDATED (with `changedFields` naming what moved, for example `price`) and REAPPEARED products. Each row also carries `changeType`, `firstSeenAt` and `lastSeenAt`. State is stored per search, filter and detail setup (or per `stateKey`), so different searches never mix. Unchanged products are skipped and not returned or charged unless you turn on `emitUnchanged`; products that disappeared are returned as EXPIRED only when you turn on `emitExpired` and the run fully scanned the search (never when Max products capped it, a results page failed, or Resume was used). EXPIRED and UNCHANGED rows are dataset rows like any other, so they are charged as normal dataset items; the detail and review surcharges are only charged on rows that are actually returned. Customer reviews, images and the scrape time are not compared; a new review still shows through `reviewCount` and `rating`. A product whose detail page could not be read is skipped for that run and keeps its previous state. `resumeFromRunId` instead continues one interrupted run without returning or charging for products already collected there.

#### Dataset views

The run's dataset has five views in the Console: **Products** (price, brand, condition, rating, stock), **Product details** (identifiers, specifications, description, images), **Customer reviews** (one row per review, filled when **Fetch reviews** is on), **Store stock** (per-branch stock and the in-store total) and **Changes since the last run** (`changeType`, `changedFields`, `firstSeenAt` and `lastSeenAt`; filled in incremental mode).

#### Clearance discounts and pasted product URLs

A product's clearance discount lives on the listing grid (`originalPrice`, `discountPercent`, `savings`, `promotion`), because that is where the store publishes the "without promo code" reference price. When you paste a single product URL directly in URL mode, no listing page is ever visited for it, so it reports its plain list price only; `originalPrice` stays `null` even for a clearance item in that specific case. To see the discount fields, browse the clearance listing (`specialsCategory: "clearance"`, or paste the clearance URL) instead of pasting the individual product link.

#### Sorting and result size

A search or category listing returns its full matching result set in a single response. When a sort order is set, the whole result set is sorted before it is trimmed to **Max products**, so a capped run keeps the genuine top results for that order, not an arbitrary first batch (Highest rated sorts on the star rating shown on each listing card, then on review count, before the cap, and is refined by the product-page rating when details are on). Customer reviews are the one paginated resource on this source (about 12 per page, capped at 30 pages); **Max result pages per product** caps how many review pages are walked per product when reviews are switched on.

### 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 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. If the picker is empty, you have not 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

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` (keyword + filters) or `url` (paste links). |
| `queries` | array | (none; prefill `["gaming laptop"]`) | Search keywords (search mode). Each is searched separately. Ignored when `specialsCategory` is set. If empty and no `specialsCategory` is set, the run searches the example keyword `gaming laptop` (with `incrementalMode`, that run never reports EXPIRED rows; with your own `stateKey` it stops with an input message instead, so add a keyword, URL or specials category or clear the State key). |
| `specialsCategory` | string | \`\` (none) | Optional. `clearance` browses the clearance listing instead of a keyword search; overrides `queries` when set. |
| `urls` | array | one example link per supported shape (7 links) | Product, category, search or clearance URLs (url mode). |
| `brand` | string | (none) | Keep only products whose brand contains this text. |
| `sortBy` | string | `relevance` | `relevance`, `priceAsc`, `priceDesc`, `ratingDesc`, `reviewsDesc`, or `nameAsc`. |
| `minPrice` | integer | (none) | Only keep products priced at or above this amount (NZD). |
| `maxPrice` | integer | (none) | Only keep products priced at or below this amount (NZD). |
| `minRating` | integer | (none) | Only keep products with an average rating at or above this value (1 to 5). Uses the rating shown on the listing card, refined by the product page when details are enabled. |
| `fetchDetails` | boolean | `true` | Open each product page for full specifications, per-store stock, image gallery, brand, GTIN/MPN, condition, categories and rating breakdown. |
| `fetchReviews` | boolean | `false` | Also collect native customer reviews for each product. |
| `maxReviewsPerProduct` | integer | `20` | Cap on reviews collected per product (`0` = all available, at most 1000; the run also stops after 30 review pages). |
| `maxItems` | integer | `20` | Maximum number of products to return across the whole run (`0` = unlimited). |
| `maxPages` | integer | (none) | Safety cap on review pages walked per product when reviews are on. Leave empty and the run still stops on its own internal safety limit; category and search listings always return their full result set in a single page regardless of this setting. |
| `proxy` | object | Residential, country New Zealand (auto-rotating exits) | Connection settings. |
| `resumeFromRunId` | string | (none) | Run ID or dataset ID of an earlier run; products already in it are skipped and not charged again. |
| `incrementalMode` | boolean | `false` | Recurring monitoring: later runs return only NEW, UPDATED and REAPPEARED products. |
| `stateKey` | string | (none) | Names a monitoring campaign so its saved state stays stable or is shared on purpose. |
| `emitUnchanged` | boolean | `false` | Incremental mode only: also return products that did not change, marked UNCHANGED. |
| `emitExpired` | boolean | `false` | Incremental mode only: also return products no longer found after a complete scan, marked EXPIRED. |
| `ignoreFieldsForChanges` | array | (none) | Incremental mode only: extra fields whose changes do not count as an update. |
| `mcpConnectors` | array | (none) | Optional: send a summary of each product to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | (none) | Notion connector only: page under which item pages are created. |
| `maxNotifyListings` | integer | `50` | Cap 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.

```json
{
  "code": "LPTDEMO123456",
  "sku": "LPTDEMO123456",
  "mpn": "KV-3350X",
  "model": "KV-3350X",
  "gtin": "9412345000019",
  "name": "Kelvara SwiftBook 14 Laptop 16GB RAM 512GB SSD",
  "brand": "Kelvara",
  "description": "A 14 inch ultrabook with a 16GB/512GB configuration for everyday work and study.",
  "price": 1249.0,
  "originalPrice": 1479.0,
  "discountPercent": 15.6,
  "savings": 230.0,
  "basePrice": 1479.0,
  "promotion": "Use promo code WINTERDEAL to save",
  "currency": "NZD",
  "availability": "In stock",
  "condition": "New",
  "priceValidUntil": "2027-03-31",
  "categories": ["Computers", "Laptops", "Ultrabooks"],
  "specifications": {
    "CPU": "Kelvara N7 8-core",
    "RAM": "16GB",
    "Storage": "512GB SSD"
  },
  "specificationsText": "CPU: Kelvara N7 8-core processor. RAM: 16GB. Storage: 512GB SSD. Display: 14 inch FHD.",
  "images": [
    "https://www.pbtech.co.nz/imgprod/L/P/LPTDEMO123456__1.jpg"
  ],
  "imageUrl": "https://www.pbtech.co.nz/imgprod/L/P/LPTDEMO123456__1.jpg",
  "rating": 4.5,
  "reviewCount": 27,
  "ratingBreakdown": { "5": 18, "4": 6, "3": 2, "2": 0, "1": 1 },
  "storeStock": [
    { "branch": "Sample Store - North", "stock": 5 },
    { "branch": "Sample Store - South", "stock": 2 }
  ],
  "totalStoreStock": 7,
  "seller": "PB Tech",
  "reviews": [
    {
      "author": "SampleShopper",
      "date": "01/02/27",
      "title": "Great everyday laptop",
      "body": "Fast enough for work and the battery lasts all day.",
      "attributes": ["Colour: Silver"],
      "verifiedOwner": true,
      "helpfulVotes": 3,
      "totalVotes": 3
    }
  ],
  "url": "https://www.pbtech.co.nz/product/LPTDEMO123456",
  "searchMode": "search",
  "specialsCategory": "clearance",
  "source": "pbtech.co.nz"
}
```

### Plan Requirement

The input's default connection setting already selects a residential connection pinned to New Zealand, which this source needs for reliable results and correct local pricing, stock and availability. A datacenter connection is not recommended: the site's bot protection refuses most datacenter requests, and the actor logs a warning that datacenter connections are refused and may return no results. If the account is not entitled to a residential connection (Apify free plans do not include one), the run logs a notice and continues on a backup connection, then notes once that it was served over the backup connection; results may be more limited there because the store challenges datacenter ranges. If every connection is refused, or no results page can be loaded at all, the run ends FAILED with a clear message rather than finishing with an empty dataset. The **Pricing** tab shows the current per-event rates.

### FAQ

#### How much does it cost?

You pay a one-time start fee plus a per-product result event for every product returned. Detail enrichment (specifications, per-store stock, image gallery, rating breakdown) is on by default and adds a surcharge for each product it succeeds on; turn off **Fetch product details** to skip it for search and category results. A pasted single product URL is always detail-enriched and always charged that surcharge, regardless of the toggle, since the product page has to be read to build the record at all. Customer review collection is off by default and adds its own surcharge only once you switch it on, charged once per product row that is delivered with at least one review. Each event is charged at most once per row, at the moment that row is saved to the dataset (event `detail-enrichment` for the detail surcharge, `review-enrichment` for reviews), never for filtered or unsaved rows. Even with **Max reviews per product** set to 0 (all), at most 30 review pages are read per product. The **Pricing** tab shows the current rates, and **Max products** caps the size, and so the cost, of any run.

#### Is it legal to scrape PB Tech?

This actor collects only publicly available product listing data. You are responsible for how you use it: follow PB Tech's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Product names, images and descriptions may be subject to third-party rights.

#### How do I get only the clearance deals?

Set **Specials / offers category** to `clearance` in search mode, or paste `https://www.pbtech.co.nz/clearance` in URL mode. `originalPrice`, `discountPercent`, `savings` and `promotion` are populated only when the store publishes a genuine reference price for that item.

#### Why is `originalPrice` empty when I paste a single product URL?

Pasting one product link scrapes only that page, and the clearance discount is shown on the listing grid, not on the standalone product page. Browse the clearance listing instead to see the discount fields populated for that product.

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

If no connection can reach the store, or no results page loads at all (for example every request gets the store's security challenge), the run ends with a FAILED status and an actionable message: connection refused for the account, residential unavailable and the backup connection could not load the pages, or a general connection problem. A search-mode run with no keywords and no specials category is not an error: it searches the example keyword `gaming laptop`. Incremental mode with your own `stateKey` and no keyword, URL or specials category also stops with an input message, collecting and charging nothing. URL mode with an empty `urls` list fails with a clear input message (not a connection message). A genuinely empty search or filter combination still finishes successfully with a "no products matched" status message. A single listing or product page that fails after retries is skipped while the rest of the run continues. If the connection keeps timing out repeatedly, the run stops early instead of waiting out the platform time limit: the products already collected are kept and delivered, the status message says the result is incomplete, and an incremental run does not mark any product as expired after such a stop.

#### Can I schedule it to run automatically?

Yes, schedule the actor from the **Schedules** tab to re-run it at a fixed interval. Each run returns the current matching product set; there is no built-in change-tracking mode, so compare consecutive dataset exports yourself if you need to detect price or stock changes over time.

#### 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 electronics data?

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

<table>
<tr><td>🔌 <a href="https://apify.com/abotapi/dienmayxanh-scraper"><b>Dienmayxanh Scraper</b></a><br>Scrape dienmayxanh.com home appliances and electronics with full specifications, current...</td><td>🔌 <a href="https://apify.com/abotapi/darty-com-scraper"><b>Darty Scraper</b></a><br>Scrape Darty (darty.com) products: current price plus strike-through reference price and...</td></tr>
<tr><td>🔌 <a href="https://apify.com/abotapi/fnac-com-scraper"><b>Fnac Scraper</b></a><br>Scrape Fnac (fnac.com) products: current price plus strike-through discount, colour/model...</td><td>🔌 <a href="https://apify.com/abotapi/boulanger-com-scraper"><b>Boulanger.com</b></a><br>Scrape Boulanger (boulanger.com) electronics and home-appliance products: current price...</td></tr>
<tr><td>🔌 <a href="https://apify.com/abotapi/biccamera-com-scraper"><b>Bic Camera Scraper</b></a><br>Scrape Bic Camera (biccamera.com) products: JPY price, list price and discount, Bic Point...</td><td>🔌 <a href="https://apify.com/abotapi/currys-co-uk"><b>Currys UK Scraper</b></a><br>Scrape Currys UK products, including electronics, home appliances, computers, TVs and...</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/pbtech-co-nz-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`):

Choose 'search' to use keywords and filters, or 'url' to scrape specific product, category or search URLs you paste below.

## `queries` (type: `array`):

One or more keywords to search, for example 'gaming laptop' or 'usb c cable'. Each keyword is searched separately and returns the full matching product set. Ignored when 'Specials / offers category' below is set. If left empty (and no specials category is set), the run searches the example keyword 'gaming laptop'. With Incremental mode and your own State key, an empty list stops with an input message instead. To browse a specific department instead, switch to URL mode and paste its category link (for example https://www.pbtech.co.nz/category/computers/laptops).

## `specialsCategory` (type: `string`):

Optional. Browse a promotional listing instead of a keyword search, for example the clearance grid (products discounted via an auto-applied checkout promo code - see the originalPrice / discountPercent / promotion output fields). Overrides 'Search keywords' when set. To browse the same listing in URL mode, paste https://www.pbtech.co.nz/clearance.

## `urls` (type: `array`):

Product, category, search or specials URLs to scrape, for example https://www.pbtech.co.nz/product/NBKASU14046I, https://www.pbtech.co.nz/category/computers/laptops or https://www.pbtech.co.nz/clearance. Multiple URLs supported. Used in URL mode only; URL mode with an empty list fails with an input message.

## `brand` (type: `string`):

Optional. Keep only products whose brand contains this text, for example 'Apple', 'ASUS' or 'Logitech'.

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

Ordering applied to the collected results before the Max products cut. Highest rated sorts on the star rating shown on each listing card, then on review count.

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

Optional. Only keep products priced at or above this amount (NZD).

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

Optional. Only keep products priced at or below this amount (NZD).

## `minRating` (type: `integer`):

Optional. Only keep products with an average customer rating at or above this value (1 to 5). Uses the rating shown on the listing card, refined by the product page when details are enabled.

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

Open each product page for full specifications, per-store stock, image gallery, brand, GTIN/MPN, condition, categories and rating breakdown. Adds one request per product. originalPrice / discountPercent / savings are captured from the listing grid either way, for products with a genuine reference price.

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

Also collect native customer reviews for each product (review text, title, author, date, verified-owner flag, helpful votes). Adds requests per product.

## `maxReviewsPerProduct` (type: `integer`):

Cap on reviews collected per product when 'Fetch customer reviews' is on. Use 0 for all available reviews (at most 1000 per product; the actor also stops after 30 review pages).

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

Maximum number of products to return across the whole run. Use 0 for unlimited.

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

Safety cap on review pages walked per product when reviews are enabled (each page holds about 12 reviews). Leave empty for no page limit — the run stops at Max products, or when a product's reviews are exhausted. Category and search listings return their full result set in a single page.

## `proxy` (type: `object`):

Apify Proxy with residential access in New Zealand is required for reliable results and correct local pricing and stock. The run rotates fresh exits automatically. On the free plan, coverage may be limited and some runs may return no results.

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

Paste a previous run ID or dataset ID to continue a large pull without returning or charging for products already collected there. Use this after an interrupted run. For recurring daily monitoring of the same search, use Incremental mode below instead.

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

Turn this on for daily or recurring monitoring. The first run returns every matching product as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED products, which is how a price cut or a stock change is spotted. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately for each search, filter and detail setup; use State key to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

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

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the mode, searches or links, filters and detail setting, so different searches never mix state with each other.

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

Off by default. Turn on to also return products that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you want the full snapshot every run.

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

Off by default. Turn on to also return products that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, so never when Max products capped it or when Resume was used. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.

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

Incremental mode only. Fields whose changes do not count as an update: a change in them alone leaves the product UNCHANGED and they are not listed in changedFields. They are still returned in every row. Use a dotted path for a nested field. The image fields (images, imageUrl), customer reviews and the scrape time are always ignored; a new review still shows through reviewCount and rating. Add more field names here to ignore them as well, for example totalStoreStock.

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

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write/digest. Leave empty to skip; never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

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

URL or id of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

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

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "queries": [
    "gaming laptop"
  ],
  "specialsCategory": "",
  "urls": [
    "https://www.pbtech.co.nz/category/computers/laptops",
    "https://www.pbtech.co.nz/category/computers/laptops/gaming-laptops",
    "https://www.pbtech.co.nz/category/computers",
    "https://www.pbtech.co.nz/product/NBKASU14046I",
    "https://www.pbtech.co.nz/search?sf=laptop",
    "https://www.pbtech.co.nz/clearance",
    "https://www.pbtech.co.nz/brand/apple"
  ],
  "sortBy": "relevance",
  "fetchDetails": true,
  "fetchReviews": false,
  "maxReviewsPerProduct": 20,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "NZ"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

No description

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

No description

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

No description

## `stock` (type: `string`):

No description

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

No description

# 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",
    "queries": [
        "gaming laptop"
    ],
    "urls": [
        "https://www.pbtech.co.nz/category/computers/laptops",
        "https://www.pbtech.co.nz/category/computers/laptops/gaming-laptops",
        "https://www.pbtech.co.nz/category/computers",
        "https://www.pbtech.co.nz/product/NBKASU14046I",
        "https://www.pbtech.co.nz/search?sf=laptop",
        "https://www.pbtech.co.nz/clearance",
        "https://www.pbtech.co.nz/brand/apple"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "NZ"
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/pbtech-co-nz-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",
    "queries": ["gaming laptop"],
    "urls": [
        "https://www.pbtech.co.nz/category/computers/laptops",
        "https://www.pbtech.co.nz/category/computers/laptops/gaming-laptops",
        "https://www.pbtech.co.nz/category/computers",
        "https://www.pbtech.co.nz/product/NBKASU14046I",
        "https://www.pbtech.co.nz/search?sf=laptop",
        "https://www.pbtech.co.nz/clearance",
        "https://www.pbtech.co.nz/brand/apple",
    ],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "NZ",
    },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/pbtech-co-nz-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",
  "queries": [
    "gaming laptop"
  ],
  "urls": [
    "https://www.pbtech.co.nz/category/computers/laptops",
    "https://www.pbtech.co.nz/category/computers/laptops/gaming-laptops",
    "https://www.pbtech.co.nz/category/computers",
    "https://www.pbtech.co.nz/product/NBKASU14046I",
    "https://www.pbtech.co.nz/search?sf=laptop",
    "https://www.pbtech.co.nz/clearance",
    "https://www.pbtech.co.nz/brand/apple"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "NZ"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/pbtech-co-nz-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/pbtech-co-nz-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/8Qy9qaOMIHKU5ZPW1/builds/AxBxuMZeXBefLn9r8/openapi.json
