# Product Price Tracker & Comparison by Country (`zaiq/product-prices-by-country`) Actor

Track a product's price, currency and stock in every country you pick and compare them side by side in one currency. Fetched through real home (residential) internet connections in each country, with proof of location. Works on Shopify, WooCommerce and most stores. Pay only for prices found.

- **URL**: https://apify.com/zaiq/product-prices-by-country.md
- **Developed by:** [Zaiq](https://apify.com/zaiq) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $24.00 / 1,000 product prices

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

## Product Price Tracker & Comparison by Country

Track what a product costs in each country you pick and compare the prices side by side: the price, currency and stock
a shop shows to a visitor there, converted to one currency. Built for competitor price monitoring and regional pricing
checks. Each product page is fetched through a real home internet connection in that country (residential,
geo-targeted), and every result proves where the request actually came from.

### What it does

For each product page and each country, it returns:

- The price, currency and stock status the shop shows in that country, read from the page's own product data (JSON-LD,
  microdata, product meta tags, or Shopify's product record).
- The same price converted to the currency you choose, at the day's reference rate (European Central Bank, with
  open.er-api.com for currencies the ECB does not quote).
- The address the page finally landed on and every redirect on the way, so you can see which country store a
  visitor is sent to.
- **Proof of location**: before the page is fetched, the same connection is checked with two IP-location services,
  and it counts only if both place it in the country. The row shows the country, city and network, which services
  confirmed it, and when.
- Optionally, a screenshot of the page from each country, as evidence.

When the run finishes, the key-value store record `SUMMARY` lists each product's prices side by side, with the cheapest
and dearest country and the spread between them.

### Who uses it

- **Brands and marketplaces** checking that each market sees the intended price and currency.
- **Pricing and competitor research**: how a rival prices the same product in the US, UK, EU and elsewhere.
- **Price-parity and grey-market checks**: where a product is cheapest once converted, and where it is out of stock.
- **Evidence**: a screenshot and a location receipt for each country.

### Example

A tech accessory brand's USB-C adapter, one product URL checked from five countries in one run on Apify (4 October 2026):

| Country asked | Came from (two services agree) | Store reached | Price shown | In USD | Stock |
|---|---|---|---|---|---|
| AU | Melbourne, Superloop | Australia | A$19 | $13.18 | In stock |
| CA | Courtenay, Shaw | Canada | C$19 | $13.34 | Out of stock |
| US | Dallas, T-Mobile | US | $15 | $15.00 | Out of stock |
| DE | Frankfurt, Deutsche Telekom | EU | €15 | $16.84 | In stock |
| GB | Caerphilly, BT | UK | £15 | $19.80 | In stock |

The same adapter costs 50% more in the UK than in Australia, and it is out of stock in the US and Canada while in stock
elsewhere: two things a single-country price check would miss.

### Input

```json
{
  "products": [{ "url": "https://shop.example.com/products/some-product" }],
  "countries": ["us", "gb", "de", "au"],
  "convertTo": "USD",
  "render": "auto",
  "screenshot": false
}
```

- `countries`: any two-letter country code.
- `convertTo`: the currency every price is converted to for comparison.
- `render`: `auto` uses a real browser only for pages whose price appears after JavaScript runs; `never` keeps to plain
  fetches (cheapest); `always` loads every page in a browser.
- `screenshot`: a screenshot of each page from each country (always uses the browser).
- `maxTriesPerPage`: if a connection is not confirmed in the country, fails, or meets a bot wall, a new one is tried, up
  to this many times. Failed tries are free.

### Output

One row per product and country. This is the UK row from the example above, with the shop's address replaced and a
few fields left out (product name, SKU, other prices on the page); the rest is as returned.

```json
{
  "url": "https://www.example-store.com/products/usb-c-adapter",
  "country": "GB",
  "priceFound": true,
  "price": 15.0,
  "currency": "GBP",
  "convertedPrice": 19.8,
  "convertedCurrency": "USD",
  "availability": "InStock",
  "priceSource": "json-ld",
  "variant": null,
  "priceNote": null,
  "status": 200,
  "finalUrl": "https://www.example-store.com/uk/products/usb-c-adapter",
  "exit": {
    "country": "GB",
    "city": "Caerphilly",
    "network": "AS2856 British Telecommunications Limited",
    "verified": true,
    "checkedWith": ["ipinfo.io", "ifconfig.co"]
  },
  "rendered": false,
  "blocked": false,
  "countryUnavailable": false,
  "error": null,
  "charged": true
}
```

### Use it from code, automations and AI agents

- **API**: run it and get the results in one call: `POST https://api.apify.com/v2/acts/zaiq~product-prices-by-country/run-sync-get-dataset-items?token=YOUR_TOKEN` with the input as JSON. The API tab on this page has ready-made Python, JavaScript and cURL examples.
- **Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("zaiq/product-prices-by-country").call(run_input={'products': [{'url': 'https://www.ridgewallet.com/products/wallet-power-bank-keycase-kintsugi-navy-dark-harbor-kintsugi-navy'}], 'countries': ['us', 'gb']})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

- **No code**: connect it to Google Sheets, Zapier, Make or n8n from the Integrations tab, schedule runs in Apify Console, and get a webhook when a run finishes.
- **AI agents (MCP)**: add it as a tool to Claude, Cursor or any MCP client through Apify's MCP server: `https://mcp.apify.com?tools=zaiq/product-prices-by-country`.

### Pricing

You pay only for prices found in the requested country. Apify's platform usage is included.

| Event | Price |
|---|---|
| Price found (plain fetch) | $0.03 ($30 per 1,000) |
| Price found with a browser (the page needed JavaScript, or you asked for a screenshot) | $0.10 ($100 per 1,000) |

Plus Apify's standard run start fee of $0.00005.

Free: pages with no price in their product data, pages blocked by the site, errors, countries where no connection
could be confirmed, and every retry. A row is charged only when its `charged` field is `true`. Your spending limit for
the run is respected: the run stops cleanly when it is reached.

In a test on 2 October 2026, 45 of 50 checks (10 shops, 5 countries) found a price with plain fetches. The other 5
were one shop whose pages carry no product data.

### Checked against the store's own record

Shops' product data is sometimes wrong, and a price tracker that copies it passes the error on. On Shopify stores each
price is checked against the store's own product record before it is reported:

- **Wrong currency label.** Some themes label every country's price with the shop's home currency, so a Canadian
  C$110 is published as £110 (found on a large apparel store in 4 of 5 countries, 4 October 2026). The price is
  reported in the currency the store actually served, and `priceNote` says what was corrected.
- **Amounts in cents.** Some pages publish 36068 for €360.68. The amount is corrected and `priceNote` says so.
- **The same variant in every country.** A product with sizes or colours is reported for the variant the page opens
  on (the add-to-cart form, or `?variant=` in your URL), named in `variant`, so countries are compared like for like.
  The other variants' prices are in `otherPrices`.

### Limits

- Prices come from the page's own product data. Most shops publish it (Shopify, WooCommerce, BigCommerce, Magento and
  many large retailers), but some show prices only as text; those rows come back with `priceFound: false` and are free.
- A shop decides what each visitor sees using its own location lookup. Confirming the connection with two services
  makes a mismatch unlikely, not impossible.
- Some sites block automated visits even from home connections, or show a waiting page; those rows come back marked
  `blocked` and are free.
- Use it on pages you are allowed to access, and follow each site's terms.

### FAQ

**Why do some countries show the same currency?** Many shops sell to some countries in their home currency or send
them to an international store. That is what a visitor there sees, so that is what is reported.

**How fresh are the exchange rates?** They are fetched at the start of each run; `SUMMARY` names the date and source.

# Actor input Schema

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

Product page URLs. Each one is checked from every country below.

## `countries` (type: `array`):

Pick countries, or type any two-letter country code.

## `convertTo` (type: `string`):

Every price is also converted to this currency (ISO code, for example USD, EUR, GBP, ZAR) with the day's reference rate, so countries can be compared.

## `render` (type: `string`):

Most shops put the price in the page itself. Some only show it after JavaScript runs; for those a real browser is used, at the browser price.

## `screenshot` (type: `boolean`):

Save a screenshot of each product page from each country (always uses the browser). The row links to it.

## `maxTriesPerPage` (type: `integer`):

If an address lands outside the country, fails or meets a bot wall, a new address is tried, up to this many. Failed tries are free.

## `maxConcurrency` (type: `integer`):

How many pages are checked at the same time.

## `acceptLanguage` (type: `string`):

Leave empty to send each country's usual browser language. Set it to force one language everywhere.

## Actor input object example

```json
{
  "products": [
    {
      "url": "https://www.ridgewallet.com/products/wallet-power-bank-keycase-kintsugi-navy-dark-harbor-kintsugi-navy"
    }
  ],
  "countries": [
    "us",
    "gb",
    "de"
  ],
  "convertTo": "USD",
  "render": "auto",
  "screenshot": false,
  "maxTriesPerPage": 4,
  "maxConcurrency": 10
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset with one row per product and country.

## `summary` (type: `string`):

Each product's prices side by side, converted to one currency, with the cheapest and dearest country and the spread.

# 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": [
        {
            "url": "https://www.ridgewallet.com/products/wallet-power-bank-keycase-kintsugi-navy-dark-harbor-kintsugi-navy"
        }
    ],
    "countries": [
        "us",
        "gb",
        "de"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("zaiq/product-prices-by-country").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": [{ "url": "https://www.ridgewallet.com/products/wallet-power-bank-keycase-kintsugi-navy-dark-harbor-kintsugi-navy" }],
    "countries": [
        "us",
        "gb",
        "de",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("zaiq/product-prices-by-country").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": [
    {
      "url": "https://www.ridgewallet.com/products/wallet-power-bank-keycase-kintsugi-navy-dark-harbor-kintsugi-navy"
    }
  ],
  "countries": [
    "us",
    "gb",
    "de"
  ]
}' |
apify call zaiq/product-prices-by-country --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zaiq/product-prices-by-country"
        }
    }
}
```

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/oweKslFvlBwaVbar7/builds/veFAygCqvNXSbi575/openapi.json
