{
  "openapi": "3.0.1",
  "info": {
    "title": "ProductReview.com.au Scraper - Products, Businesses & Reviews",
    "description": "Scrape ProductReview.com.au products, businesses and customer reviews. Search by location, category or custom query with advanced filters. Extract business details, ratings, review content and structured review insights.",
    "version": "2.1",
    "x-build-id": "xXvIqjZ8lCSMQejRj"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~product-reviews-australia-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-product-reviews-australia-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/abotapi~product-reviews-australia-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-product-reviews-australia-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/abotapi~product-reviews-australia-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-product-reviews-australia-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "search",
              "url"
            ],
            "type": "string",
            "description": "How to discover listings. Filter mode = pick a category + filters; URL mode = paste explicit URLs (search/category/listing) and ignore filters.",
            "default": "search"
          },
          "outputType": {
            "title": "Output",
            "enum": [
              "listings",
              "reviews"
            ],
            "type": "string",
            "description": "What rows to emit. Applies to both Filter and URL modes. 'listings' = one row per listing with up to 10 preview reviews embedded. 'reviews' = one row per review with a sourceListing pointer (no listing rows).",
            "default": "listings"
          },
          "category": {
            "title": "Category (Filter mode only)",
            "type": "string",
            "description": "A ProductReview category slug ('home-garden-shops', 'air-fryers') or a plain category name ('Air Fryers'); a name is resolved to its slug via the site's own category search, and the run fails loudly if nothing matches. The actor builds /c/<slug>. If empty, defaults to 'home-garden-shops'. Filter mode only; ignored in URL mode.",
            "default": "home-garden-shops"
          },
          "searchQuery": {
            "title": "Search Query",
            "type": "string",
            "description": "Appended as ?q=. Narrows results within the chosen category."
          },
          "location": {
            "title": "Location Slug or Name",
            "type": "string",
            "description": "A ProductReview location slug ('victoria_au', 'sydney_nsw_au') or a plain location name ('Victoria', 'Sydney'); a name is resolved to its slug via the site's own location search, and the run fails loudly if nothing matches. Inserted as /c/<cat>/l/<loc>."
          },
          "showDiscontinued": {
            "title": "Show Discontinued",
            "type": "boolean",
            "description": "Include discontinued products/services in the results.",
            "default": false
          },
          "sortBy": {
            "title": "Sort Results By (Filter mode only)",
            "enum": [
              "",
              "relevance",
              "rating",
              "numberOfReviews",
              "popularity",
              "lowestPrice",
              "highestPrice",
              "newest",
              "oldest",
              "review_count"
            ],
            "type": "string",
            "description": "Sort key for category/search results in Filter mode. Values match productreview.com.au's own sort options: relevance, rating, number of reviews (review_count is accepted as an alias of numberOfReviews), popularity, lowest/highest price, newest and oldest. Filter mode only; URL-pasted sort parameters override this.",
            "default": ""
          },
          "brands": {
            "title": "Brands",
            "type": "array",
            "description": "Only listings from these brands. Type the brand name or its slug as it appears in productreview.com.au brand-filter URLs (e.g. `Breville`, `delonghi`, `philips-domestic-appliances`). Several brands are combined with OR. If the site does not recognise a brand, the run says so in the log and never returns unfiltered results in its place. Leave empty for all brands.",
            "items": {
              "type": "string"
            }
          },
          "minRating": {
            "title": "Minimum listing rating",
            "minimum": 1,
            "maximum": 4,
            "type": "integer",
            "description": "Only listings rated this many stars and up (1-4), using the site's own rating filter. This filters listings; to filter individual reviews by star rating use 'Only reviews with this rating' below. Leave empty for all ratings."
          },
          "urls": {
            "title": "URLs",
            "type": "array",
            "description": "Multi-URL list, one of: a listing (/listings/<slug>), a category (/c/<cat>), a category+location (/c/<cat>/l/<loc>), a category with a sort param (/c/<cat>?sort=<val>), a category with a search query (/c/<cat>?q=<text>), a category with a brand filter (/c/<cat>?brand=<slug>), a search page (/search?q=...), a listing with a review filter (/listings/<slug>?rating=<1-5>), a listing with a verified-reviews filter (/listings/<slug>?isVerified=true), a listing with a review page number (/listings/<slug>?page=N), a listing write-review link (/listings/<slug>/write-review) or a category with a page number (/c/<cat>?page=N). A /listings/<slug>/write-review link is normalized to the listing itself; a pasted page=N on a listing is ignored (reviews always start from the first page); a pasted page=N on a category is ignored too (the site serves its first page for it, so it is treated as page 1 of that category); a singular ?brand=<slug> on a category is rewritten to the site's own brands= filter; a literal \"&amp;\" between query params (pasted from rendered page source) is decoded to \"&\". Brand pages (/brands/*), /i/* and a listing's /questions sub-page are not supported and are skipped with a warning, never a silent empty result. Filter-mode fields are ignored when Mode = URL. Left untouched, URL mode scrapes the 12 example URLs of the default list (one per supported shape; the \"Prefill example\" shows the same 12 shapes), so clear the list or replace it with your own URLs to scrape only those.",
            "default": [
              "https://www.productreview.com.au/listings/the-lighting-outlet",
              "https://www.productreview.com.au/c/home-garden-shops",
              "https://www.productreview.com.au/c/home-garden-shops/l/victoria_au",
              "https://www.productreview.com.au/c/home-garden-shops?sort=rating",
              "https://www.productreview.com.au/c/home-garden-shops?q=lighting",
              "https://www.productreview.com.au/c/air-fryers?brand=breville",
              "https://www.productreview.com.au/search?q=lighting",
              "https://www.productreview.com.au/listings/the-lighting-outlet?rating=1",
              "https://www.productreview.com.au/listings/the-lighting-outlet?isVerified=true",
              "https://www.productreview.com.au/listings/beacon-lighting?page=2",
              "https://www.productreview.com.au/listings/bunnings-warehouse/write-review",
              "https://www.productreview.com.au/c/kitchenware-shops?page=2"
            ],
            "items": {
              "type": "string"
            }
          },
          "maxReviewsPerListing": {
            "title": "Max reviews per listing",
            "minimum": 1,
            "type": "integer",
            "description": "Caps how many reviews ONE listing contributes. Leave empty to use the mode default: in Listings output, 10 embedded preview reviews per listing (unchanged default; raise this to embed more); in Reviews output, no per-listing cap at all (only the overall Max Output Rows limit applies, so an existing single-listing task with a high limit is never silently truncated here)."
          },
          "reviewRating": {
            "title": "Only reviews with this rating",
            "minimum": 1,
            "maximum": 5,
            "type": "integer",
            "description": "Narrow reviews to one star rating (1-5). Live-confirmed site filter; applied as ?rating=<n> on the listing page. Leave empty for all ratings. A rating already present on a pasted URL (URL mode) always wins over this."
          },
          "reviewVerifiedOnly": {
            "title": "Verified purchases only",
            "type": "boolean",
            "description": "Only include reviews the site marks as a verified purchase (?isVerified=true). Off by default (all reviews).",
            "default": false
          },
          "reviewsWithAttachmentsOnly": {
            "title": "Only reviews with photos/attachments",
            "type": "boolean",
            "description": "Only include reviews that have at least one photo/attachment (?hasAttachments=true). Off by default (all reviews).",
            "default": false
          },
          "reviewSortBy": {
            "title": "Sort reviews by",
            "enum": [
              "",
              "overview",
              "newest",
              "ratingHighest",
              "ratingLowest",
              "mostLiked"
            ],
            "type": "string",
            "description": "Order of a listing's reviews. Live-confirmed site filter (?sortBy=<value> on the listing page, re-order verified against the site's own live response): 'overview' is the site's own default order, 'newest' = most recent first, 'ratingHighest'/'ratingLowest' = by star rating, 'mostLiked' = by helpful-vote count. Leave empty to keep the site's own default order. A 'sortBy' already present on a pasted URL (URL mode) always wins over this.",
            "default": ""
          },
          "limit": {
            "title": "Max Output Rows (applies to both modes)",
            "minimum": 1,
            "type": "integer",
            "description": "Universal cap on dataset rows. Applies to both Filter and URL modes. In Listings output: max listings (search/category pages cap at 30 per URL). In Reviews output: max review rows; the actor reads further review pages until this is reached, then stops.",
            "default": 20
          },
          "maxConcurrency": {
            "title": "Max Concurrency",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "Maximum number of in-flight requests. 2 is safe without proxy (the site throttles bursts from one IP).",
            "default": 4
          },
          "proxy": {
            "title": "Proxy Configuration",
            "type": "object",
            "description": "Apify proxy. Defaults to datacenter (groups-AUTO). If this account cannot open that tunnel, the run automatically escalates to Apify Residential, then a backup connection, before ever giving up; it never continues on a direct, unproxied connection. For higher throughput or harder runs, switch to residential yourself: apifyProxyGroups=['RESIDENTIAL'], apifyProxyCountry='AU'.",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": []
            }
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue a large crawl of listings/reviews without returning or charging for rows already collected there. Use this after an interrupted run, or when continuing a large pull in another run. For recurring monitoring of the same search or URL list, use Incremental mode below instead."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily or recurring monitoring. The first run returns everything as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED rows. Compared: every output field of the row, so a listing is UPDATED when its name, brand, rating or review counts, price, offers, specifications, business details or embedded reviews change, and a review row when its title, body, rating, votes, replies or author change; changedFields names what moved. Excluded from the comparison (still in every row): scrapedAt, searchUrl, and on review rows the parent listing's running counters sourceListing.rating and sourceListing.numberOfReviews, plus anything you add under \"Ignore fields when detecting changes\". A field this actor newly starts returning is never counted as a change. Turn on \"Emit unchanged\" or \"Emit expired\" only when you also want those rows returned (and billed). State is kept separately for each mode/category/query/location/sort/URL-list setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode only)",
            "type": "string",
            "description": "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/category/query/location/sort/URL settings; different searches then never mix state with each other."
          },
          "emitUnchanged": {
            "title": "Emit unchanged rows (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return rows 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 specifically want the full snapshot every run.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired rows (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return rows 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/URL list, not when Max output rows capped it, when Resume was used, or when the site's own pagination limit (this site does not page a category/search past its first ~30 results) cut a search short. This returns (and bills) extra synthetic rows, so leave it off unless you need expiry tracking.",
            "default": false
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Field names to exclude from change detection in Incremental mode, in addition to the ones this actor already ignores by default (currently \"scrapedAt\" the per-run scrape timestamp, \"searchUrl\" the search page a product was found on, and on review rows \"sourceListing.rating\" and \"sourceListing.numberOfReviews\", the parent listing's running counters; none is a real content change of the row). Use a nested field like \"sourceListing.rating\" to ignore it only at that exact path; a plain name like \"numberOfQuestions\" is ignored everywhere it appears, at any depth. An ignored field still appears in the output row, it just never causes UPDATED or shows up in changedFields. Changing this list does not re-flag your existing tracked records as UPDATED; only genuinely different fields do that.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "mcpConnectors": {
            "title": "Pipe results into your apps (optional)",
            "type": "array",
            "description": "Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON; the complete record stays in the dataset. Leave empty to skip. 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": {
            "title": "Notion parent page (Notion connector only)",
            "type": "string",
            "description": "URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors."
          },
          "maxNotifyListings": {
            "title": "Max items to export per connector",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on items written to each connector per run. Does not affect the dataset.",
            "default": 50
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}