# Google Shopping Product Matcher & Price Monitor (`olliolli/google-shopping-product-matcher`) Actor

Match catalog products to Google Shopping offers across eight European markets. Check variants for electronics, appliances, tools, monitors and printers; track competitor prices.

- **URL**: https://apify.com/olliolli/google-shopping-product-matcher.md
- **Developed by:** [Tom J](https://apify.com/olliolli) (community)
- **Categories:** E-commerce
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $30.00 / 1,000 live product checks

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Google Shopping Product Matcher & Price Monitor

Match your catalog to Google Shopping offers, compare competitor prices and monitor changes in one Actor. Automatic category routing and optional seller-page detail checks support five category profiles covering **electronics, household appliances, power tools, monitors and printers**. The product matcher checks manufacturer identifiers and variant evidence before including an offer in a price comparison. Available Shopping markets: the Netherlands, Belgium, Germany, France, Austria, Ireland, Spain and Italy.

**No separate Google API key or AI subscription is needed.** Results export through the standard Apify dataset/API as JSON, CSV or Excel.

**Built for retailers and competitor price-monitoring workflows.** This is an explainable, rule-based product matcher for branded products with precise identifiers. It does not identify arbitrary products from images or guarantee that a merchant listing is correct.

### Quick start

1. Enter your own SKU, brand, complete manufacturer part number (`mpn`) and optionally a `category`: `auto` (default), `electronics`, `appliances`, `power_tools`, `monitors` or `printers`. You can mix categories within a run.
2. Add package and battery information when known. Set `variantSpecificMpn: true` only when the code identifies a precise manufacturer variant, such as DHP484Z, rather than a model family.
3. Select your country and language, then run. Review the dataset and `OUTPUT.complete`.

```json
{
  "products": [{
    "sku": "MAK-DHP484Z", "brand": "Makita", "mpn": "DHP484Z",
    "variantSpecificMpn": true, "package": "bare", "batteryCount": 0,
    "voltage": 18, "price": 129, "currency": "EUR"
  }],
  "country": "nl", "language": "nl", "maxOffersPerProduct": 20
}
```

### Category profiles and variant matching

| Category | Typical products | Additional checks |
| --- | --- | --- |
| `electronics` | SSDs, headphones, phones, tablets, laptops, televisions | `storageGB`, `ramGB`, `screenInches`, `color`, `region`, `connectivity` |
| `appliances` | Air fryers, washing machines, vacuum cleaners and other precisely coded appliances | `capacityL`, `capacityKg`, `color`, `region` |
| `power_tools` | Cordless drills and drivers | `package`, `batteryCount`, `batteryAh`, `voltage`, `case` |
| `monitors` | Precisely coded computer monitors | `screenInches`, `resolution`, `refreshHz`, `color`, `region` |
| `printers` | Precisely coded printers | `printTechnology`, `color`, `region`, consumable/bundle warnings |

All profiles check identifiers, brand, condition and detected multipacks (`packCount`). They share retrieval, monitoring, output and pricing. Brands are not restricted to a whitelist; matching still requires explicit brand evidence. Omitted categories now use automatic routing. Existing explicit categories are unchanged. Legacy catalogs that need the old behavior should set `category: "power_tools"`.

```json
{
  "products": [
    {"sku":"SSD-2TB","category":"electronics","brand":"Samsung","mpn":"MZ-V9P2T0BW","variantSpecificMpn":true,"storageGB":2000},
    {"sku":"HEADPHONES-BLACK","category":"electronics","brand":"Sony","mpn":"WH-1000XM5","variantSpecificMpn":true,"color":"black"},
    {"sku":"AIRFRYER","category":"appliances","brand":"Philips","mpn":"HD9252/90","variantSpecificMpn":true,"capacityL":4.1}
  ],
  "country":"nl", "language":"nl"
}
```

**Supply the characteristics that distinguish your SKU.** If you specify a color or capacity, missing or ambiguous evidence goes to REVIEW even when the model code matches; conflicting values are rejected. For electronics, appliances, monitors and printers, automatic matching requires an exact full variant MPN explicitly marked `variantSpecificMpn: true`, or matching valid GTINs, with no detected conflicts or uncertainties. A family name such as “iPhone 15” alone is not a variant identifier. Search results often omit full part numbers, especially for grouped SSD listings and older appliances: these may produce zero automatic matches. The Actor returns those candidates as REVIEW rather than guessing their identity.

Canonical colors: `black`, `white`, `silver`, `grey`, `blue`, `red`, `green`, `pink`, `purple`, `gold`. Region values: `EU`, `UK`, `US`, `JP`; connectivity: `wifi` or `cellular`. Storage uses manufacturer decimal units: 1 TB = 1,000 GB. RAM and storage are separated only when the title labels them unambiguously. Region and Wi-Fi-only claims need explicit text. Supplier offer objects may also provide these structured fields; contradictory title information is never silently overwritten.

Selected Dutch, English, French, German, Spanish and Italian terms are recognized. Capacity text can describe something other than the relevant product specification, so these checks remain conservative. Not every subtype or brand has been tested live. Clothing, furniture, cosmetics, unidentified generic products and image-only matching are outside this release's scope.

### What counts as a match?

| Status | Meaning | Included in price summary? |
| --- | --- | --- |
| MATCH | Exact identifier and sufficient variant evidence, consistent brand and stated/source-reported condition; no detected conflict | Only with a valid price in your currency |
| REVIEW | Missing identifiers, bundle evidence, brand or condition | No |
| REJECT | A detected mismatch, accessory, incompatible bundle or condition | No |

Every row includes `evidence`, `reasons`, `warnings` and the extracted attributes. There is no invented confidence percentage. A full part number can establish variant identity if you explicitly mark it variant-specific, but contradictory variant information still rejects it. Do not mark a family/model prefix as variant-specific. Listing text can omit seller-added extras; read warnings before acting. A detected extra charger, battery, bit set or other bundle is not silently treated as an equivalent single product. Explicit “+” bundles go to REVIEW or REJECT. A match is evidence from the listing and, where reported, the linked seller page; it is not verification of the physical product. Existing MATCH rows are not automatically revisited on seller pages.

Used-condition phrases such as “nette staat”, “zo goed als nieuw”, “B Grade” and “refurbished” are checked before treating an offer as new. New condition may be a default in Google Shopping's source parser: these rows carry `new_condition_assumed_by_source`. Unknown condition stays in REVIEW. GTINs supplied as structured data are checksum-checked; a Google product ID is never treated as a GTIN.

### Google Shopping integration

Live mode reuses the retrieval/parser route of [Google Shopping Price Monitor](https://apify.com/olliolli/google-shopping-prices). It performs its own bounded search; it does not start that Actor or charge its offer event. At most two requests per SKU, no browser, login, customer cookies or CAPTCHA solving. A blocking page stops the run.

You can also reuse a **snapshot dataset** already obtained with that Actor:

```json
{
  "source": "dataset", "datasetId": "YOUR_DATASET_ID",
  "products": [{"sku":"MAK-DHP484Z","brand":"Makita","mpn":"DHP484Z","variantSpecificMpn":true}],
  "country":"nl"
}
```

Searches in that dataset must be named exactly `Makita DHP484Z` (brand + space + mpn), or each row must provide your `sku`. Select the dataset in the input picker. The Actor requests READ access only to that selected dataset; it keeps Limited permissions. Prior Shopping runs retain their own costs. Imported datasets are limited to 2,000 rows and are not a substitute for a fresh availability check.

Alternatively, use `source: "offers"` and supply `offers` with `sku`, `title`, `seller`, numeric `price`, `currency` and `condition`. Optional fields: `mpn`, `gtin`, `shippingCost`, `offerId`. In the catalog, `case: false` rejects explicitly advertised cases such as Makpac or TSTAK. This makes it possible to check your own candidate data without a live Google request.

### Competitor price monitoring

Use `mode: "monitor"` with your own `stateName` to output new or changed comparisons. Unchanged comparisons create no duplicate rows. Each completed SKU check is still chargeable, including runs with no changes, because retrieval and matching are performed again. Use one non-overlapping schedule per state name. A matching-rule/profile upgrade can produce CHANGED rows even when the price did not change; inspect the evidence and status. Missing search results are never reported as discontinued, sold out or deleted products.

`SUMMARY` contains candidate counts and the lowest comparable listing price for each successfully checked SKU. Prices are snapshots, not checkout quotes. Shipping remains unknown unless explicitly supplied; unknown shipping is never replaced with zero. `totalPrice` is null when shipping is unknown. No currency conversion, tax normalization, stock verification, repricing or historical backfill is performed.

### Pricing

| Event | Price | Charged when |
| --- | ---: | --- |
| Live product check | $0.03 | One SKU has candidate results and matching has completed, including REVIEW/REJECT outcomes |
| Imported catalog check | $0.01 | One SKU has supplied/dataset candidates and matching has completed |

Up to 40 candidate offers are included per SKU. No per-offer fee, no default dataset-item fee and no custom start fee. Duplicate offers are deduplicated. Source failures and SKUs without candidates are not charged a check event. A completed check may find **zero valid matches**; that is still a completed, chargeable check. Set an Apify maximum charge for each run.

Examples: 10 live SKUs = $0.30; 100 live SKU checks = $3; 1,000 imported SKU checks = $10. Maximum 50 SKUs per run. A daily live check of 20 SKUs for 30 days is $18 at these event prices. Owner testing, external integrations and your Apify plan can have separate platform costs.

### Coverage and limitations

- Google returns a ranked subset of offers, not every seller. Only organic product cards are used; sponsored card extraction is excluded in this release.
- Precise variant codes matter. Broad names and missing expected variant details go to REVIEW. Full manufacturer identifiers can still appear in an inaccurate or bundled seller listing.
- Brand matching is open to explicit brands, but this is not an independently measured universal accuracy claim. Category profiles use selected extraction rules, not complete linguistic or product coverage.
- Google may change markup or block requests. Check `OUTPUT.complete`, `uncheckedSkus`, `warnings` and `connectionAttempts`, not only run status. Incomplete runs end as FAILED while keeping completed results.
- Summary prices exclude REVIEW and REJECT, and currency mismatches. The lowest price covers only comparable returned listings.
- Monitoring remembers observed comparisons, never infers that an absent result has stopped selling. Do not run the same monitor concurrently.

### Output fields

`sku`, `category`, `categorySource`, `merchantEnrichment`, `mpn`, `title`, `seller`, `status`, `comparable`, `evidence`, `reasons`, `warnings`, `detected`, `price`, `currency`, `shippingCost`, `totalPrice`, `ownPrice`, `priceDifference`, `priceDifferencePercent`, `googleProductId`, `offerId`, `sourceSearchUrl`, `observedAt`, `sourceObservedAt`. Monitor mode adds `changeType` and `previousPrice`.

Questions or wrong matches? Open an Apify Store issue with the SKU, listing title, expected variant and run ID. Do not include private credentials or customer data.

### Automatic category recognition

Use `category: "auto"` or omit it. Routing uses the catalog's optional `title`, textual `googleProductCategory` / `productType`, structured variant fields, and candidate titles containing the exact requested model. It selects one of the five supported profiles. Conflicting signals or unsupported categories produce `category: "unknown"` and remain REVIEW. An explicit category overrides routing.

This is our own transparent routing, **not Google's hidden classifier**. Google does classify products, but the Shopping HTML currently parsed does not reliably expose its taxonomy. Numeric taxonomy IDs are not interpreted. Supplying a category does not fill missing variant information or extend support to clothing, groceries or other untested profiles.

### Seller-page enrichment: fewer uncertain comparisons when evidence exists

`enrichMerchantDetails` defaults to `true`. Only REVIEW candidates with a supplied or recovered direct `merchantUrl` are eligible for seller-page fetching. Google cards contribute this URL only when the card has one unambiguous external link; many current cards have none. Imported offers can supply the URL of their exact seller listing. When a direct link is absent, bounded Google detail recovery can supply it (see below). We do not search for a similar product and attach a guessed URL.

The Actor reads public HTML and one unambiguous schema.org Product, linked to the requested page by its product URL or single Offer URL. It verifies identity against the observed listing, then checks manufacturer identifiers, GTIN, brand, condition and variant attributes in the product name; explicit structured color is supported too. Product groups and ambiguous pages are skipped. Missing identity, blocked pages, timeouts and conflicting existing fields leave the comparison uncertain. Contradictory variants may correctly change REVIEW to REJECT. Existing title conflicts and bundle warnings remain effective.

Known attribution parameters (such as `srsltid`, `gclid` and UTM campaign tags) are ignored only when comparing the page URL with its structured product URL. Product and variant query parameters remain significant; a different SKU, size or colour URL is not treated as the same page. This can recover otherwise valid product details without weakening variant checks.

No login, CAPTCHA solving, user cookies, browser rendering or paid merchant proxies are used. URLs resolving to non-public addresses and redirects to another host are refused. No review authors, contact data or raw page HTML are saved. Prices remain the original Shopping/supplied listing prices; enrichment does **not** verify checkout price, shipping, stock or seller-added extras omitted from both sources.

Limits: `maxMerchantPages` defaults to **10 per run** (maximum 20), `maxMerchantPagesPerProduct` to **3** (maximum 5). Each attempt has a 15-second total timeout and a 2 MB response ceiling; no retries after a failed page. Attempts and parsed results are checkpointed across restarts of the same run. Set either limit to 0 or disable enrichment to avoid seller requests. There is **no additional event charge**; ordinary completed-product check pricing still applies.

Each row's `merchantEnrichment` reports status, before/after classification, supplemented fields, and URL/time when verified. OUTPUT includes `merchantPageAttempts` and `enrichmentOutcomes`. `verified` describes the page association and parsed evidence, not a guarantee of a MATCH. An unchanged REVIEW is a valid conservative result.

Example supplied offer (attach only the exact offer's real URL):

```json
{
  "sku": "SSD-2TB",
  "title": "Samsung 990 PRO 2TB M.2 SSD",
  "seller": "Megekko",
  "price": 399,
  "currency": "EUR",
  "condition": "new",
  "merchantUrl": "https://www.megekko.nl/product/5093/293096/SSD-M-2/Samsung-990-PRO-2TB-M-2-SSD"
}
```

The example price is illustrative, not a current quote. Use your actual listing observation. Seller access and structured-data quality vary. A missing URL cannot be repaired by simply inferring a category. Link recovery requires the original Google offer identifiers.

References: [Google product categories](https://support.google.com/merchants/answer/6324436), [schema.org Product](https://schema.org/Product).

#### Earlier validation snapshot — version 1.0.11 (27 October 2026)

A controlled Apify test used three supplied offers with real seller URLs: all three started as REVIEW; seller evidence resolved one to MATCH, rejected one with the wrong capacity, and left one REVIEW because identity could not be confirmed. These are controlled cases, not a market-wide accuracy estimate. A separate regression run retained the prior 106-row result (9 MATCH, 25 REVIEW, 72 REJECT). Those historical Shopping rows had no direct seller URLs, so enrichment could not reduce their REVIEW count. A five-offer live Shopping test also exposed no direct seller links. Automatic category recognition worked in the tested electronics cases; local tests also cover appliance/tool routing, unsupported categories and conflicting signals.

### Recovering missing seller links

`recoverMerchantLinks: true` (default) checks Google's public product detail panel for REVIEW offers lacking a direct URL. This requires `googleProductId` and `offerId`; live searches now also preserve the panel's image/product/group identifiers. Imported offers can supply the same observed IDs.

A recovered link must be inside one unambiguous organic offer card with the **same Google offer ID, seller name, price and currency** as the candidate. A product-level match or similar title alone is not enough. The Actor reads Google's organic `/goto` redirect destination without following ad-click links. The exact offer's fuller title is also compared, so a newly visible colour or bundle can resolve or reject a previously ambiguous listing. Original title conflicts remain effective.

The bounded lookup budget is spent on stronger model/brand candidates first; bundle ambiguity and accessory-like electronics titles receive lower priority. This ordering does not itself change their matching decision or remove them from the results.

Defaults: at most **5 Google detail lookups/run and 2/product**, configurable up to 10/run and 3/product. Each lookup including redirect has a 35-second ceiling and no retry. Counters/cache survive restarts of the same run. A Google blocking response stops further detail lookups for that run. Empty panels, changed prices, ambiguous offers and unresolved redirects do not produce guessed links. Merchant-page limits still apply separately. Existing MATCH/REJECT candidates are not revisited, so this is not a full seller-link export for every result.

No extra event is charged. Completed product-check pricing is unchanged, including imported checks that use this optional recovery. Disable `recoverMerchantLinks` or set the lookup budget to 0 for a workflow without these extra Google requests. No third-party SERP subscription is required.

Output adds `merchantUrl`, `googleOfferTitle`, `linkRecovery` and `statusBeforeRecovery`. OUTPUT adds `googleDetailAttempts` and `linkRecoveryOutcomes`. A `resolved` link confirms the connection to the Google offer; it does not guarantee a correct retailer feed, accessible page, complete specifications or a MATCH. Google can still return sparse detail pages. Variant and merchant-page checks remain conservative.

### When to choose this matcher

Choose this Actor when you already have precise catalog model numbers and want comparable competitor prices tied to your own SKUs, with reasons for rejected and uncertain listings. It combines candidate retrieval, category rules, selective detail checks and change-only output in one workflow. It does not replace a broad scraper for category discovery, all merchants, unlimited result depth, product images or arbitrary retailer coverage. Explainable matching also exists in other products; our focus is this integrated Google Shopping workflow for the five supported profiles and eight markets.

### Spain, Italy, monitors and printers

Choose `country: "es", language: "es"` for Spain or `country: "it", language: "it"` for Italy. Existing NL, BE, DE, FR, AT and IE markets remain available. One market per run; use a separate monitor stateName for each market. EUR prices are compared without foreign-exchange conversion. Geographic search targeting does not prove delivery eligibility or checkout prices. Google's [market documentation](https://support.google.com/merchants/answer/12653197?hl=en) includes Spain and Italy; this Actor's coverage is still limited by observable public results.

Examples of additional catalog rows:

```json
[
  {"sku":"DELL-P2422H","category":"monitors","brand":"Dell","mpn":"P2422H","variantSpecificMpn":true,"screenInches":23.8,"resolution":"1920x1080","refreshHz":60},
  {"sku":"BROTHER-HLL2400DW","category":"printers","brand":"Brother","mpn":"HL-L2400DW","variantSpecificMpn":true,"printTechnology":"laser"}
]
```

`resolution` uses pixel dimensions, for example `1920x1080`, not the ambiguous label “4K”. FHD and QHD titles map to their standard dimensions; generic 4K is deliberately insufficient. `refreshHz` is a positive number. `printTechnology` accepts `laser`, `inkjet` or `thermal`; missing or conflicting evidence remains REVIEW or REJECT. Multiple stated refresh rates/resolutions remain uncertain. Printer toner/cartridge mentions and monitor stands require review or rejection as accessories. No ink yield, duplex, print speed, panel technology or port compatibility checks are claimed. Supply the full manufacturer variant identifier, not a broad family name.

Selected Spanish and Italian colors, used/refurbished conditions, screen-size units, printer terms and accessory phrases are recognized; this is not exhaustive language understanding. Automatic category routing also recognizes monitor/printer terms. Mixed or conflicting categories stay REVIEW; existing explicit categories remain unchanged.

Expansion validation (27 October 2026): two bounded live searches per new country returned 16 candidate offers for Spain and 15 for Italy. These are small connection/parser samples, not market-wide reliability or accuracy measurements. Listings included alternate models, accessories and used stock; geographic targeting does not guarantee every listing is local. An observed underscore-suffixed monitor code triggered an additional exact-model guard before release. Rounded screen labels (24 inches versus a specified 23.8) remain strict conflicts; the Actor does not assume they are equivalent. Nine controlled cases cover positive matches, missing specifications and variant/accessory/condition conflicts; the existing 106-offer regression remains unchanged.

### Additional monitor evidence

For an already verified seller Product JSON-LD node, enrichment also reads explicitly named `additionalProperty` specifications for screen diagonal (inches), display resolution (pixel dimensions) and refresh rate (Hz). Selected labels in the six supported languages are recognized. Power-supply frequency, response time, dimensions of the enclosure, recommendations and free-form descriptions are not used as monitor specifications. Required units, ranges, duplicate conflicts and contradictions with the product title are checked. Known specifications with conflicting or unparseable duplicate values do not become a MATCH. Only existing bounded seller requests are used; no new fee or higher request budget.

An explicit underscore suffix after the requested monitor model (for example P2422H_WOST versus P2422H) now produces REJECT with `model_suffix_conflict`. It is not treated as missing evidence or silently equated with the requested model. Supply the complete variant code if that variant is your intended product. This improves REVIEW triage without pretending that a rejected offer is a usable price comparison.

The initial three-offer monitor investigation recovered two exact seller links with the existing route, but produced no additional MATCH. Rounded 24-inch labels versus a specified 23.8 inches remain strict conflicts. Structured-property enrichment is tested with controlled verified-page fixtures; improved automatic MATCH coverage on the original live sample has not been demonstrated. Blocked pages and pages without sufficient structured data still cannot be enriched.

### Verified manufacturer specifications for monitors

For REVIEW monitor listings, a small reviewed manufacturer-reference set can fill missing fixed specifications before paid link recovery. **Initial reference: Dell P2422H; current coverage is listed below**, using Dell's [official datasheet](https://www.delltechnologies.com/resources/en-us/asset/data-sheets/products/electronics-accessories/dell-24-monitor-p2422h-datasheet.pdf), reviewed 27 October 2026: 23.8 inches, 1920x1080, 60 Hz. This is a versioned reference, not a live manufacturer search or general Dell-family lookup. Models outside the reviewed set keep the existing behavior.

The observed seller title must contain that exact model and brand evidence. Different suffixes, accessories, bundles, ambiguous or conflicting specifications are not filled away. Values come from the reviewed reference, not from the desired catalog attributes. A catalog that expects 144 Hz therefore fails against the 60 Hz reference. This does not verify stock, seller-added extras, regional cables, condition, price or delivery. Source-assumed new-condition warnings remain. Rounded 24-inch listing claims are not overridden by the 23.8-inch reference.

Each affected row includes `manufacturerEnrichment` with source URL, reference model, review date, fields added and before/after status. No extra requests or event charges are introduced. A MATCH can therefore use model-level manufacturer evidence for missing specs; it does not imply that the seller page explicitly listed them. The existing seller-page and exact-offer routes remain available when this reference cannot establish a match.

#### Reviewed monitor reference coverage

All references below were reviewed on 27 October 2026. Refresh rate is the manufacturer's advertised supported display capability, not the current operating frequency or a guarantee for every cable/input. Default energy-label frequency can differ. Models with ambiguous overclock modes are not silently assigned a single rate. These are selected mainstream office/gaming models, not a measured best-seller ranking.

| Brand | Exact model | Diagonal | Resolution | Advertised refresh | Official source |
|---|---|---|---|---|---|
| Dell | P2422H | 23.8 in | 1920x1080 | 60 Hz | [Datasheet](https://www.delltechnologies.com/resources/en-us/asset/data-sheets/products/electronics-accessories/dell-24-monitor-p2422h-datasheet.pdf) |
| Dell | P2425H | 23.8 in | 1920x1080 | 100 Hz | [Specifications](https://www.dell.com/en-in/shop/dell-pro-24-plus-monitor-p2425h/apd/210-bmlz/) |
| BenQ | GW2490 | 23.8 in | 1920x1080 | 100 Hz | [Specifications](https://www.benq.eu/content/dam/b2c/en-eu/support/download/datasheet/monitor/gw2490-datasheet-eng.pdf) |
| BenQ | GW2790 | 27 in | 1920x1080 | 100 Hz | [Specifications](https://www.benq.eu/content/dam/b2c/en-eu/support/download/datasheet/monitor/gw2790-datasheet-eng.pdf) |
| ASUS | VG249Q3A | 23.8 in | 1920x1080 | 180 Hz | [Specifications](https://www.asus.com/uk/displays-desktops/monitors/tuf-gaming/tuf-gaming-vg249q3a/techspec/) |
| LG | 27MR400-B | 27 in | 1920x1080 | 100 Hz | [Specifications](https://www.lg.com/us/monitors/lg-27mr400-b) |

No automatic aliases for GW2490C/T, VG249Q3A-W, model-family prefixes or regional dot-suffixes are added. Exact supplier-title evidence is required. Similar-looking names are not interchangeable. No extra network requests or pricing events are introduced by this reference expansion.

### Automatic official references (BenQ GW monitors)

The Actor includes a bounded BenQ GW home-monitor adapter. `maxManufacturerPages` defaults to 2 (maximum 2); set 0 to disable it. It requests at most that many official pages per run, only for eligible REVIEW offers that lack a reviewed static reference. Exact model identity and one complete specification table are required. Failed, conflicting or ambiguous extraction leaves the offer unchanged. There is no new pricing event or paid proxy; additional runtime can nevertheless incur platform costs.

Requests have a 15-second ceiling and use the existing public-address/redirect guards. The request reservation and both successful and failed results survive restarts within the same run, preventing duplicate retries. Reference records contain source, observation time, parser version and evidence. Cache expiration is seven days for successful results and one day for failures, but this candidate stores them in the run's own state: **no cross-run shared cache is implemented yet**. It is not a general manufacturer search service.

# Actor input Schema

## `products` (type: `array`):

1–50 products: sku, brand, mpn required. category may be auto (default), electronics, appliances power_tools, monitors or printers. Auto uses catalog title, textual googleProductCategory/productType, variant attributes and exact-model candidate titles; ambiguous or unsupported categories stay REVIEW. Optional variant fields: storageGB, ramGB, screenInches, color, region, connectivity, capacityKg, capacityL, packCount, refreshHz, resolution (e.g. 1920x1080), printTechnology (laser/inkjet/thermal). Supply complete variant MPN and variantSpecificMpn:true or GTIN evidence.

## `source` (type: `string`):

Live mode includes the Shopping search; no child Actor charge. Imported rows must contain sku or an exact query of brand + space + mpn.

## `country` (type: `string`):

Country for live search. Imported data must belong to this market.

## `language` (type: `string`):

Language for Google Shopping.

## `maxOffersPerProduct` (type: `integer`):

Up to this many candidate listings are compared per SKU. Search rankings and availability vary.

## `datasetId` (type: `string`):

Dataset source only. Maximum 2,000 rows. Use a snapshot from olliolli/google-shopping-prices with query exactly brand + space + mpn.

## `offers` (type: `array`):

Offers source only. Maximum 2,000 objects: sku (or query), title, price, currency, condition, seller. Optional mpn, gtin, shippingCost, offerId. Optional merchantUrl: direct URL of this exact seller offer, not a search or category page. Used for bounded public product-detail enrichment. Optional googleProductId and offerId enable link recovery; googleGroupId, googleImageDocId and googleProductDocId improve panel selection. IDs must belong to this exact observed offer.

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

Monitor outputs only new or changed comparisons. Each completed product check still costs the same: fresh retrieval and checking take place on each run. No removed/out-of-stock inference.

## `stateName` (type: `string`):

Use a unique name per catalog and country. Do not overlap runs sharing this name.

## `enrichMerchantDetails` (type: `boolean`):

Only REVIEW offers with a direct merchantUrl. Public HTML and product JSON-LD only; no login, browser or paid merchant proxy. No extra event charge. Not all Google cards expose a merchant link.

## `maxMerchantPages` (type: `integer`):

Hard attempt limit, retained during run restart. Each page has a 15-second timeout; blocked pages are not retried.

## `maxMerchantPagesPerProduct` (type: `integer`):

Hard attempt limit, retained during run restart. Each page has a 15-second timeout; blocked pages are not retried.

## `recoverMerchantLinks` (type: `boolean`):

For REVIEW offers with Google product and offer IDs, make bounded Google detail requests. Require the exact offer ID, seller and unchanged price, then resolve an organic Google redirect. No guessed merchant search results and no additional charge event.

## `maxGoogleDetailPages` (type: `integer`):

Hard attempt limit; retained across restarts. 35-second ceiling per detail lookup including redirect. Set 0 to disable requests.

## `maxGoogleDetailPagesPerProduct` (type: `integer`):

Hard attempt limit; retained across restarts. 35-second ceiling per detail lookup including redirect. Set 0 to disable requests.

## `maxManufacturerPages` (type: `integer`):

Set 0 to disable. Bounded BenQ GW home-monitor adapter. At most two official pages per run, 15 seconds each; no proxy or new event fee. Compute still costs money. Results and failures survive restarts within the same run; no cross-run cache yet.

## Actor input object example

```json
{
  "products": [
    {
      "sku": "SONY-BLACK",
      "category": "electronics",
      "brand": "Sony",
      "mpn": "WH-1000XM5",
      "variantSpecificMpn": true,
      "color": "black",
      "currency": "EUR"
    }
  ],
  "source": "google_shopping",
  "country": "nl",
  "language": "nl",
  "maxOffersPerProduct": 20,
  "mode": "snapshot",
  "stateName": "my-tools",
  "enrichMerchantDetails": true,
  "maxMerchantPages": 10,
  "maxMerchantPagesPerProduct": 3,
  "recoverMerchantLinks": true,
  "maxGoogleDetailPages": 5,
  "maxGoogleDetailPagesPerProduct": 2,
  "maxManufacturerPages": 2
}
```

# Actor output Schema

## `comparisons` (type: `string`):

No description

## `diagnostics` (type: `string`):

No description

## `summary` (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 = {
    "products": [
        {
            "sku": "SONY-BLACK",
            "category": "electronics",
            "brand": "Sony",
            "mpn": "WH-1000XM5",
            "variantSpecificMpn": true,
            "color": "black",
            "currency": "EUR"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("olliolli/google-shopping-product-matcher").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 = { "products": [{
            "sku": "SONY-BLACK",
            "category": "electronics",
            "brand": "Sony",
            "mpn": "WH-1000XM5",
            "variantSpecificMpn": True,
            "color": "black",
            "currency": "EUR",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("olliolli/google-shopping-product-matcher").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 '{
  "products": [
    {
      "sku": "SONY-BLACK",
      "category": "electronics",
      "brand": "Sony",
      "mpn": "WH-1000XM5",
      "variantSpecificMpn": true,
      "color": "black",
      "currency": "EUR"
    }
  ]
}' |
apify call olliolli/google-shopping-product-matcher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,olliolli/google-shopping-product-matcher"
        }
    }
}
```

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/7Gdk4dClfuUNv1dmm/builds/aTOseFGBMDaTtdfYQ/openapi.json
