# Regional Price Checker - Geo Pricing from US, SG, UK, TW (`tidytools/regional-price-check`) Actor

See the price, currency, country site and language a page shows in the US, Singapore, London and Taiwan, side by side. Extracts prices (text, JSON-LD, meta tags), flags geo blocks and cookie walls, monitors changes. Failed regions free.

- **URL**: https://apify.com/tidytools/regional-price-check.md
- **Developed by:** [Yukai Lin](https://apify.com/tidytools) (community)
- **Categories:** E-commerce, Marketing, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

### What does Regional Price Checker do?

**Input:** pricing, product or store page URLs (and, optionally, which of the four regions to use). **Output:** one row per URL with the **price, currency, country site and language a visitor sees in the US, Singapore, London and Taiwan**, a `differs` flag, and a price table converted to one currency. **Price:** $4.00 per 1,000 regions checked (one URL from all four regions = $0.016), no start fee; blocked, walled, timed-out and empty pages and bad input lines are free.

Give it pricing, product or store pages. It opens each page **from four fixed places at the same time** and shows you, side by side, what a visitor there gets:

- the **price and currency** (from the page text, JSON-LD offers and price meta tags),
- the **country site** it was redirected to (`spotify.com/uk`, `kayak.sg`, `zendesk.tw`) and the HTTP status,
- the **language** of the page,
- **blocks and walls**: "not available in your region", cookie-consent walls, "choose your country" pickers, 404s,
- a **comparison**: does the page differ by region (`differs: true`), what differs (currency, price, redirect, language, availability, consent wall, page text), a price table converted to one currency, and a text-similarity score.

| Vantage point | Network |
|---|---|
| `us` | United States: Phoenix (Oracle data center) |
| `sg` | Singapore (Oracle data center) |
| `eu` | United Kingdom: London (Oracle data center) |
| `tw` | Taiwan: residential internet line |

These are **four fixed locations, not "any country"**. If you need prices from Germany or Brazil, this Actor cannot give them to you.

**Honest by design.** Every request says who it is: user agent `Mozilla/5.0 (compatible; TidyToolsSmartFetch/1.0; +https://apify.com/tidytools/smart-fetch)`. `robots.txt` is respected by default. No proxies pretending to be visitors, no logins, no cookies, no CAPTCHA or bot-check solving. Each region's result really comes from that region: if a region is refused, it is reported as refused (and not charged), never silently replaced by another region.

### Why it matters: 40% of pricing and shop pages differ by region

On **3 October 2026** we fetched 50 news, e-commerce and pricing pages from five networks at the same time. **20 of 50 (40%) showed region-specific content**: a different currency, price list, country store or language. Pricing pages (8 of 16) and shops (7 of 16) varied most; news front pages mostly did not (5 of 18). Fetching the same page twice from one place gave the same currency and country site every time, so these differences come from the region, not from chance.

The same day, this Actor checked 8 of those pages (HTTP mode, all four regions; 31 of 32 region fetches returned the page):

| Page | US | Singapore | London | Taiwan | What differs |
|---|---|---|---|---|---|
| spotify.com/premium | $12.99 | $11.98 (SGD, spotify.com/sg-en) | £12.99 | $168 (TWD, Chinese) | currency, price, country site, language |
| slack.com/pricing | $8.75 | page without prices | £7 | $8.75 | currency, price |
| notion.so/pricing | $10 | $10 | £8.50 | $10 | currency, price |
| grammarly.com/plans | $12 | $12 | £10 | $12 | currency, price |
| shopify.com/pricing | $1 | SGD 1 | £1 | $1 | currency, plan prices |
| zendesk.com/pricing | $19 | US$ 19 (zendesk.com/sg) | £15 (zendesk.co.uk) | $19 in US dollars (zendesk.tw, Chinese) | price, country site, language |
| kayak.com | $38 (kayak.com) | S$ 381 (kayak.sg) | £131 (kayak.co.uk) | NT$2,067 (tw.kayak.com) | country site, currency, language |
| news.yahoo.com | news page | news page | **cookie-consent wall** | news page | consent wall |

Converted with the daily rates of 2 October 2026, Spotify Premium Individual cost **US $12.99, SG $9.36, UK $17.16 and TW $5.25** per month in US dollars. (Kayak's prices are live deals and change all the time; its country site and currency are the stable signal.)

### Use cases

- **Pricing analysts and SaaS competitive intelligence**: see the local price list competitors show in the US, Singapore, the UK and Taiwan, in one table, on a schedule.
- **E-commerce geo-pricing and compliance**: check that each market gets the right currency, country store, stock status and price, and catch pages that send a market to a "choose your country" gate.
- **Ad and localization QA**: confirm that a landing page in London shows pounds and an English (UK) page, and that Taiwan gets the Traditional Chinese site.
- **Monitoring**: turn on **Report changes since the last run** and schedule it daily: you get the price, currency and country-site changes per region.

### How much does it cost?

| Event | Price | When |
|---|---|---|
| Region checked | **$4.00 / 1,000 regions** | one URL fetched from one region and returned with prices, currency, final URL and language |
| Region checked (browser) | **$6.00 / 1,000 regions** | instead of the above, when the Taiwan page was rendered in a real browser (Auto or Browser mode) |

**Examples:** one URL from all four regions = 4 × $0.004 = **$0.016**. 100 pricing pages checked daily from all four regions = $1.60 per day. A region that fails is free, so a URL that only three regions could fetch costs $0.012.

**No start fee**, no proxy costs, no platform usage on top. Larger Apify plans get the usual volume discount (Silver 10%, Gold and above 20%).

#### Control your cost

- **Charged:** each region that returned the page (`chargedEvents` on the row says how many, `priceUsd` the amount).
- **Free:** regions that were blocked, geo-blocked, sent to a cookie-consent wall, timed out, returned 404, or are disallowed by robots.txt (each shows `success: false` and an `error` that ends with "(not charged)"); a page that is an empty JavaScript shell without prices (`needsJavaScript: true`; use Auto or Browser mode); invalid lines, private or local addresses (`localhost`, `192.168.x.x`, `*.local`), addresses with a user name and password, an empty URL list, an unknown region or an unsupported setting value (a free row with `errorType: "invalid_input"` per bad line, or one row for a bad setting; the run still ends normally and nothing is fetched for them); duplicate URLs (checked once). A page that loads but simply shows no price is charged: its currency, country site, language and walls are still compared.
- **Fewer regions, lower cost:** choose only the vantage points you need.
- **Before it starts**, the run logs its worst-case cost (URLs × regions × price) and compares it with your **maximum charge per run**. When the maximum is reached the run stops cleanly: `SUMMARY.status` is `LIMIT_REACHED` and `SUMMARY.notProcessed` lists the URLs that were not checked.

### How to use it

1. Paste your URLs into **URLs**, one per line.
2. Keep all four **Vantage points** or pick some.
3. Optional: **Price near text** (for example a plan name, "Premium Individual") to keep only the prices that follow it, or a **CSS selector** for the price block.
4. Click **Start**. The **Comparison (overview)** tab has one row per URL; **Price table** puts the prices side by side; **All fields** has everything per region.

#### Input example

This is the input the form is prefilled with; a run with it takes about a minute and costs only cents:

```json
{
    "urls": [
        "https://www.spotify.com/premium/",
        "https://www.zendesk.com/pricing/"
    ]
}
```

#### Output example

Real result (3 October 2026), shortened: one URL, four regions, and the Taiwan region in full.

```json
{
    "url": "https://www.spotify.com/premium/",
    "differs": true,
    "differences": ["currency", "price", "redirect", "language", "content"],
    "summary": "Currency differs (US USD, Singapore SGD, London GBP, Taiwan TWD); prices differ (first price: US $12.99, Singapore $11.98, London £12.99, Taiwan $168); different country site (US www.spotify.com/us, Singapore www.spotify.com/sg-en, London www.spotify.com/uk, Taiwan www.spotify.com/tw); language differs (US en-us, Singapore en-sg, London en-gb, Taiwan zh-hant); text differs (lowest similarity 0 between US and Taiwan).",
    "pricesSummary": "US: $12.99 | Singapore: $11.98 | London: £12.99 | Taiwan: $168",
    "currencies": "USD, SGD, GBP, TWD",
    "regionsDelivered": 4,
    "priceTable": [
        {
            "position": 1,
            "us": { "amount": 12.99, "currency": "USD", "display": "$12.99", "period": "month", "inUSD": 12.99 },
            "sg": { "amount": 11.98, "currency": "SGD", "display": "$11.98", "period": "month", "inUSD": 9.36 },
            "eu": { "amount": 12.99, "currency": "GBP", "display": "£12.99", "period": "month", "inUSD": 17.16 },
            "tw": { "amount": 168, "currency": "TWD", "display": "$168", "period": "month", "inUSD": 5.25 }
        }
    ],
    "regions": {
        "tw": {
            "region": "tw",
            "location": "Taiwan (residential line)",
            "success": true,
            "status": "ok",
            "httpStatus": 200,
            "finalUrl": "https://www.spotify.com/tw/premium/",
            "locale": "www.spotify.com/tw",
            "title": "Spotify Premium - Spotify (台灣)",
            "language": "zh-hant",
            "currency": "TWD",
            "currencySource": "text",
            "mainPrice": { "amount": 168, "currency": "TWD", "display": "$168", "period": "month", "source": "text" },
            "renderedWith": "http",
            "elapsedMs": 2140,
            "charged": true
        }
    },
    "fx": { "base": "USD", "date": "Fri, 02 Oct 2026 00:02:31 +0000", "source": "ExchangeRate-API open access (open.er-api.com), daily rates" },
    "chargedEvents": { "region-checked": 4 },
    "priceUsd": 0.016
}
```

**How the currency is read.** "S$", "NT$", "US$", "£", "€", "¥", "円", "₩", ISO codes before or after the number ("SGD 1", "$29 SGD/mo", "12,99 €") are read directly, with 1,234.56 / 1.234,56 / 1 234,56 number formats. A bare "$" is resolved from, in order: the page's structured data, the one dollar currency written elsewhere on the page, a currency named in words ("美元", "Singapore dollars"), and the country in the final URL (`/sg-en/`, `/tw/`, `kayak.sg`). If none of these says which dollar it is, the price is reported as USD with `currencyAssumed: true`, so you can tell a guess from a fact. `mainPrice` is the first structured price, else the first regular non-zero price in the page's currency. Free plans and "$0 for 1 month" trials stay in `prices` but are skipped there and in the price table. Introductory prices ("$1 for the first month, then $9.99/month") and "was" prices are listed with `kind: "intro"` or `kind: "original"` and never become `mainPrice` or a price-table row unless the page shows nothing else; amounts such as "Save $20", "$5 off" or "free shipping over $35" are not prices and are left out. A price that is struck through on the page but not labelled ("$49.99 $29.99") cannot be told apart in the page text: point **Price near text** at the plan.

#### Monitoring changes

Turn on **Report changes since the last run** (and give it a **Monitor name**), then schedule the Actor. Each row gets `monitor.changes`, for example `{ "region": "eu", "field": "mainPrice", "before": "GBP 12.99", "after": "GBP 13.99", "significant": true }`. Status, country site, currency, main price, language and the overall `differs` are significant changes; a reshuffle of the other prices on the page alone is listed with `significant: false` and does not set `monitor.changed` (pages rotate deals and plan variants: in our test slack.com/pricing showed one extra price in one of two runs a few minutes apart). The last result is kept in a named key-value store in your account (`regional-price-check-<monitor name>`).

### Use it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/tidytools~regional-price-check/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://www.spotify.com/premium/"],"regions":["us","eu","tw"]}'
```

**With AI agents (MCP):** connect Apify's MCP server (`https://mcp.apify.com?tools=tidytools/regional-price-check`) to Claude, Cursor or any MCP client and ask, for example, "What does Notion charge in the UK compared with the US?". Minimal input: `{"urls": ["https://www.notion.so/pricing"]}`. Regions that fail are not charged and carry a `status` and `errorType`.

### Advanced settings

- **Page fetching**: HTTP (default) is what our 3 October test used and works for most pricing pages. Only Taiwan has a browser of its own (a Chrome on the same Taiwan line): **Auto** renders the Taiwan page in it when the plain page needs JavaScript or is refused; **Browser** always does. US, Singapore and London are always fetched over HTTP (a browser elsewhere would not be in that region), and their rows say so in `note`. A page that seems to need JavaScript is marked `needsJavaScript: true`.
- **What counts as a difference**: which differences set `differs` (all by default). `differences` always lists everything found.
- **Text differs below (% similarity)**: default 80 (in our test, the same page fetched twice from one place stayed at 88% or more for 95% of sites).
- **Convert prices to**: USD (default), EUR, GBP, SGD, TWD or none. Daily reference rates from open.er-api.com; the rate date is in `fx`.
- **Include page text**, **Respect robots.txt** (default on), **Time limit per region** (30 s), **Parallel URLs** (6).

### Limitations

- Four fixed vantage points only (US Phoenix, Singapore, London, Taiwan). London is the only European one.
- The US, Singapore and London points are data-center networks. Some sites refuse data centers; those regions are reported as `blocked` (not charged). Sites can also tell data centers from home connections and show them different content.
- Prices are read from the page as served; prices that only appear after you choose options, log in or add to cart are not seen. A pricing page with many plans may list several prices: use **Price near text** or a **CSS selector** to point at the one you want.
- Deal and flight prices change by the minute, so they can differ between regions for reasons other than the region. Currency, country site and language are the stable signals.
- Taiwan's residential line has limited capacity: very large runs can be slower there, and a temporarily unavailable region is reported as `unavailable` (not charged).

### FAQ

**Does the Actor collect usage data?** The Actor sends one anonymous usage counter per run (input type, item count range, outcome) to improve the tool; no URLs, content or account data.

**Is this a proxy or a VPN?** No. It fetches from four networks we run, identifies itself, and never tries to look like a person's browser. Pages that refuse us are reported, not worked around.

**Why "eu" for London?** The region names come from our fetch backend; `eu` is London, United Kingdom. Prices there are typically in pounds, not euros.

**Do I pay for a region that was blocked or showed a cookie wall?** No. Only regions that returned the page are charged. The wall is still reported, because a London-only consent wall is itself a regional difference.

**What if I give it a bad URL, no URL, a private address or an unknown region?** The run ends normally with a free row (`errorType: "invalid_input"`) that says what to fix; nothing is charged. Valid URLs in the same list are still checked. Private network addresses and URLs with a password in them are never sent to our fetchers. Region names are case-insensitive and `uk`, `london`, `singapore`, `taiwan` and `usa` are accepted as well as `us`, `sg`, `eu`, `tw`; an unsupported `convertTo`, `mode` or `compareOn` value is reported instead of being replaced by a default.

**Which price formats are read?** Besides the usual `$12.99`, `£`, `€`, `S$`, `NT$` and ISO codes: `12.99$`, `USD$20`, `Rs. 499`, `9,900원`, `¥1,200` and Indian digit grouping (`₹1,49,999`). A bare number without a currency sign or code (`Price 1299`) is not treated as a price.

**A page shows a price in one region and none in another. Why?** Some sites hide prices, show a "contact sales" plan or a country picker to certain regions. That region is reported as it is (`no price`, or `country_picker`) and is still compared; the other regions' prices are unaffected.

**Does it pick the right plan on a page with many prices?** It takes the first regular price on the page (not trial, intro, "was" or discount amounts). For a specific plan, fill in **Price near text** (for example "Premium Individual") or a **CSS selector**.

### Support

Open an issue in the **Issues** tab with the URL and the regions. Issues are checked regularly.

# Actor input Schema

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

Pricing, product or store pages to check, one per line (full URLs or bare domains). Up to 5,000 per run. Invalid lines become a result row with errorType "invalid_input" (not charged) instead of failing the run.

## `regions` (type: `array`):

Where each page is fetched from. Four fixed locations (not "any country"): United States (Phoenix), Singapore, United Kingdom (London) and Taiwan (residential line). Each region that returns the page is charged once; regions that fail are free. Leave empty for all four.

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

HTTP (recommended): the page as each region's server sends it; most pricing pages show their prices this way. Auto: HTTP, plus a real browser from Taiwan when the Taiwan page needs JavaScript or refuses plain HTTP. Browser: render the Taiwan page in a browser. Only Taiwan has a browser of its own; US, Singapore and London are always fetched over HTTP (a browser elsewhere would not come from that region).

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

Adds the converted amount to every row of the price table (daily reference rates from open.er-api.com). Choose "No conversion" to skip.

## `priceAnchors` (type: `array`):

Only keep prices that appear right after one of these words (e.g. a plan name such as "Premium Individual"). Add translations for regions in other languages. When none is found on a page, all prices are kept and the region says anchorFound: false.

## `cssSelector` (type: `string`):

Read text and prices only inside this element (e.g. ".pricing-table" or "#price"). Structured prices (JSON-LD, meta tags) are always read from the whole page.

## `monitor` (type: `boolean`):

Remember each URL's regional result and report what changed since the previous run with the same monitor name (price, currency, country site, language, availability). Use it with a schedule.

## `monitorName` (type: `string`):

Runs with the same name compare with each other (letters, digits and dashes). Default: built from the first URL and the regions.

## `compareOn` (type: `array`):

Which differences make "differs" true. All are always listed in "differences". Leave empty for all.

## `similarityThresholdPercent` (type: `integer`):

Page text counts as different when two regions share less than this share of word sequences. 80 is based on our 3 October 2026 test, where the same page fetched twice from one place stayed at 88% or more for 95% of sites.

## `includeText` (type: `boolean`):

Add each region's visible text (up to 20,000 characters) to the output, e.g. for your own comparison.

## `respectRobots` (type: `boolean`):

Skip pages that the site's robots.txt disallows for our user agent TidyToolsSmartFetch (status robots_disallowed, not charged).

## `timeoutSecs` (type: `integer`):

How long one region may take to fetch a page.

## `waitUntil` (type: `string`):

When a browser page (Taiwan, Auto or Browser mode) counts as loaded.

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

How many URLs are checked at the same time (each URL is fetched from all chosen regions at once).

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

Upload or link .txt/.csv files of URLs (every http(s) URL in a file is read). Full URLs only here.

## Actor input object example

```json
{
  "urls": [
    "https://www.spotify.com/premium/",
    "https://www.zendesk.com/pricing/"
  ],
  "regions": [
    "us",
    "sg",
    "eu",
    "tw"
  ],
  "mode": "http",
  "convertTo": "USD",
  "monitor": false,
  "similarityThresholdPercent": 80,
  "includeText": false,
  "respectRobots": true,
  "timeoutSecs": 30,
  "waitUntil": "load",
  "maxConcurrency": 6
}
```

# Actor output Schema

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

No description

## `prices` (type: `string`):

No description

## `full` (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 = {
    "urls": [
        "https://www.spotify.com/premium/",
        "https://www.zendesk.com/pricing/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidytools/regional-price-check").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 = { "urls": [
        "https://www.spotify.com/premium/",
        "https://www.zendesk.com/pricing/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("tidytools/regional-price-check").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 '{
  "urls": [
    "https://www.spotify.com/premium/",
    "https://www.zendesk.com/pricing/"
  ]
}' |
apify call tidytools/regional-price-check --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tidytools/regional-price-check"
        }
    }
}
```

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/NQ3LNyHkvKKUAjQCt/builds/uJYIgAvIzT1tmQEza/openapi.json
