# GetYourGuide Price & Review Monitor – Competitor Tracker (`voranil/getyourguide-price-monitor`) Actor

Get alerts when GetYourGuide tours change price, sell out, gain reviews or ratings, and when new competitors launch in your city. Only changes, no duplicate rows. Built for tour operators: schedule daily and send to Slack, email or Sheets.

- **URL**: https://apify.com/voranil/getyourguide-price-monitor.md
- **Developed by:** [Altuğ CEYLAN](https://apify.com/voranil) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 tour checkeds

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

## GetYourGuide Price & Review Monitor – Competitor Tracker

**Know what your competitors on GetYourGuide changed, before your customers do.** This Actor watches GetYourGuide tours and tells you **only what changed** since the last run: price moves and discounts, dates selling out, rating drops, new reviews, and brand-new competitor tours in your city. Schedule it daily and send the alerts to Slack, email or Google Sheets with Apify integrations.

> Alerts, not data dumps. A quiet day costs almost nothing and returns a one-line summary.

### Who it's for

- **Tour and activity operators** watching their own listings and their direct competitors
- **Revenue managers** who want to react when a rival discounts or sells out a date
- **Travel market researchers** tracking prices, ratings and new supply in a destination

### What you get

| Alert                    | When it fires                                                                                                                                                                |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 💶 `PRICE_CHANGE`        | The "from" price moved (old/new price, change in %, and old/new discount, so you see sales start and end)                                                                    |
| 📅 `AVAILABILITY_CHANGE` | A date in your window became available, sold out or unavailable (optional add-on)                                                                                            |
| ⭐ `RATING_CHANGE`       | The average rating moved by 0.05 or more, or the review count grew by 10 or more (adjustable)                                                                                |
| 📈 `RANK_CHANGE`         | A tour moved up or down in its city's GetYourGuide ranking (3+ places by default, confirmed over two runs)                                                                   |
| 💬 `NEW_REVIEW`          | A new review: rating, text, date, language, traveller type, sub-ratings (guide, transport, value…), photo count and the operator's reply. Reviewer names are never collected |
| 🆕 `NEW_COMPETITOR`      | A newly launched tour appeared in a city you watch (GetYourGuide's "New activity" badge or ≤ 10 reviews)                                                                     |
| 🚫 `TOUR_UNAVAILABLE`    | A tour was removed (reported once)                                                                                                                                           |
| 📋 `RUN_SUMMARY`         | Always, free: what was checked and how many changes there were                                                                                                               |

The first run records a baseline (`FIRST_SEEN` for each tour, free). From the second run on you only get changes.

Every tour also comes with, at no extra cost:

- **price in the currency you choose**, original price and discount, and whether it's **per person or per group**
- **city ranking position**, **"booked N times yesterday"** and scarcity like **"10 spots left today"** (when GetYourGuide shows them)
- duration, free cancellation, skip the line, booking cutoff, category, "New activity" badge and image
- optionally the **operator** (the company running the tour), on every alert

### Monitor vs. scraper

|                             | This monitor                         | A typical GetYourGuide scraper |
| --------------------------- | ------------------------------------ | ------------------------------ |
| Output                      | Only what changed, as alerts         | Every tour, every time         |
| Comparing runs              | Done for you, with baselines         | Your job                       |
| Sold-out dates              | ✅ per date (add-on)                 | ❌                             |
| New reviews                 | Only the new ones, with text         | All reviews again              |
| New competitors             | Only genuinely new tours             | ❌                             |
| Ranking moves               | ✅ alert when a tour climbs or drops | Raw position at best           |
| Operator replies to reviews | ✅                                   | Rarely                         |
| Quiet day                   | One free summary row                 | Full dataset, full price       |

### How much does it cost?

You pay per event; the baseline (`FIRST_SEEN`), errors and the run summary are free. A run that can't check anything costs nothing.

| Event                                                                                   | Price   |
| --------------------------------------------------------------------------------------- | ------- |
| `tour-checked` – one tour checked                                                       | $0.002  |
| `change-detected` – a price, rating, ranking, availability, competitor or removal alert | $0.005  |
| `review-extracted` – a new review                                                       | $0.002  |
| `availability-checked` – add-on, per tour, when availability tracking is on             | $0.003  |
| `listing-page-checked` – one page (24 tours) of a city scanned for new competitors      | $0.0025 |

**Examples (daily schedule, 30 runs a month):**

- 20 tours: about **$1.20/month** plus alerts
- 20 tours + new-competitor scan of their city (3 pages): about **$1.45/month** plus alerts
- 20 tours with sold-out-date tracking: about **$3/month** plus alerts

Operator names (optional) cost nothing extra in fees: they need one extra page per tour, once, and are then remembered.

### Quick start

1. Paste your tour URLs (and your competitors') into **Tour URLs**.
2. Optional: add your city page, e.g. `https://www.getyourguide.com/antalya-l172/`, to **Listings to watch** to catch new competitors.
3. Choose your **currency**.
4. Run once to record the baseline, then add a daily **schedule** and an integration (see below).

```json
{
    "tourUrls": [
        "https://www.getyourguide.com/antalya-l172/antalya-suluada-island-boat-trip-with-lunch-hotel-pickup-t468561/",
        "https://www.getyourguide.com/antalya-l172/antalya-old-city-tour-wboat-trip-cable-car-waterfalls-t1156943/"
    ],
    "searchQueries": ["https://www.getyourguide.com/antalya-l172/"],
    "currency": "EUR",
    "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["UNBLOCKER"] }
}
```

### Get alerts in Slack, Google Sheets or email

1. Click **Save as a new task** with your input, so the schedule and integrations belong to one saved setup.
2. In the task, open **Schedules** and run it daily (or every few hours).
3. Open the task's **Integrations** tab and pick where alerts should go:
   - **Slack:** post a message to a channel when a run finishes.
   - **Email / Gmail:** get the run's results by email.
   - **Google Sheets / Google Drive:** append each alert as a row to build a price and review history.
   - **Make, Zapier, n8n or a webhook:** for anything else, e.g. a WhatsApp message on every `PRICE_CHANGE`.
4. To skip quiet days, filter on the `RUN_SUMMARY` item: its `changes` field is `0` when nothing changed.

### Input

| Field                  | Default            | Description                                                                                                                                                                                      |
| ---------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `tourUrls`             |                    | GetYourGuide tour URLs (`…-t<number>/`)                                                                                                                                                          |
| `searchQueries`        |                    | City or category pages to scan for new competitors, e.g. `https://www.getyourguide.com/antalya-l172/`. Free-text searches also work but GetYourGuide's keyword search can return unrelated tours |
| `trackPrice`           | `true`             | Report price changes                                                                                                                                                                             |
| `trackAvailability`    | `false`            | Report sold-out and newly available dates (add-on, reads each tour's page)                                                                                                                       |
| `availabilityDays`     | `14`               | Days ahead to watch, starting tomorrow (same-day booking closes during the day, so today is skipped)                                                                                             |
| `trackReviews`         | `true`             | Report new reviews                                                                                                                                                                               |
| `maxReviewsPerTour`    | `50`               | Max newest reviews checked per tour per run                                                                                                                                                      |
| `minPriceChangePct`    | `0`                | Only report price moves of at least this many percent. Smaller moves add up until they cross it                                                                                                  |
| `minReviewCountChange` | `10`               | Review-count growth that triggers a rating alert on its own (a 0.05 rating move always does)                                                                                                     |
| `minRankChange`        | `3`                | Places a tour must move in its city ranking (on two runs in a row) before a `RANK_CHANGE` alert                                                                                                  |
| `includeOperatorName`  | `false`            | Add the operator (company running the tour) to every alert. One extra page per tour, once                                                                                                        |
| `currency`             | `EUR`              | Currency for prices (exact in fast mode; tour pages use the visitor's location)                                                                                                                  |
| `language`             | `en`               | Preferred page language                                                                                                                                                                          |
| `includeSnapshot`      | `false`            | Also output the full current state of each tour on every run                                                                                                                                     |
| `useLocationFeed`      | `true`             | Fast mode: read up to 24 tours per request from the city feed. Missing tours are checked on their own page                                                                                       |
| `feedMaxPages`         | `3`                | Feed pages (24 tours each) per city, for your tours and for competitor scans                                                                                                                     |
| `maxConcurrency`       | `4`                | Parallel requests; keep it low                                                                                                                                                                   |
| `proxyConfiguration`   | UNBLOCKER on Apify | GetYourGuide blocks most automated traffic; the `UNBLOCKER` group is used automatically when left empty                                                                                          |

### Output

One dataset item per alert. Every item has `type`, `source`, `tourId`, `tourUrl`, `tourTitle` and `detectedAt`.

```json
{
    "type": "PRICE_CHANGE",
    "source": "getyourguide",
    "tourId": "1156943",
    "tourUrl": "https://www.getyourguide.com/antalya-l172/antalya-old-city-tour-wboat-trip-cable-car-waterfalls-t1156943/",
    "tourTitle": "Antalya: Old City & Waterfall Tour, Cable Car & Boat Options",
    "operatorName": null,
    "detectedAt": "2026-10-30T07:00:12.408Z",
    "oldPrice": 12.35,
    "newPrice": 13.5,
    "currency": "EUR",
    "changePct": 9.31,
    "oldDiscountPct": 5,
    "newDiscountPct": null
}
```

```json
{
    "type": "NEW_REVIEW",
    "source": "getyourguide",
    "tourId": "1243237",
    "tourTitle": "Antalya/Alanya Rafting, Zipline, Jeep, Quad, Buggy Safari",
    "detectedAt": "2026-10-29T11:22:19.015Z",
    "reviewId": "129227740",
    "rating": 4,
    "title": "",
    "text": "We were a group of six… The whole group enjoyed the rafting…",
    "reviewDate": "2026-10-29T11:00:43+01:00",
    "language": "en",
    "travelerType": "family_young",
    "subRatings": { "guide": 5, "transport": 4, "value": 5 },
    "photoCount": 0,
    "operatorReply": null,
    "operatorReplyDate": null
}
```

```json
{
    "type": "NEW_COMPETITOR",
    "source": "getyourguide",
    "query": "https://www.getyourguide.com/antalya-l172/",
    "tourId": "1520562",
    "tourTitle": "Antalya: Design Your Own Signature Perfume – Hands-On Workshop",
    "price": 29.92,
    "basePrice": 37.4,
    "discountPct": 20,
    "priceIsPer": "person",
    "currency": "EUR",
    "rating": null,
    "reviewCount": 0,
    "rank": 5,
    "isNew": true,
    "availabilityNote": "10 spots left today",
    "spotsLeft": 10,
    "duration": "1.5 hours",
    "freeCancellation": true,
    "category": null,
    "activityType": "other",
    "bookedYesterday": null
}
```

Other alerts add: `AVAILABILITY_CHANGE` → `date`, `oldStatus`, `newStatus`; `RATING_CHANGE` → `oldRating`, `newRating`, `oldReviewCount`, `newReviewCount`; `RANK_CHANGE` → `oldRank`, `newRank`; `TOUR_UNAVAILABLE` / `ERROR` → `message` (and `stage`). `FIRST_SEEN` and `SNAPSHOT` carry the full state: price, currency, rating, review count, availability and all the tour details above (`basePrice`, `discountPct`, `priceIsPer`, `rank`, `bookedYesterday`, `isNew`, `availabilityNote`, `spotsLeft`, `nextAvailableDate`, `duration`, `freeCancellation`, `skipTheLine`, `bookingCutoff`, `category`, `activityType`, `imageUrl`, `operatorName`). Fields GetYourGuide doesn't show for a tour are `null`.

**Example Slack message** (built with an Apify integration from the dataset):

> 💶 *Antalya: Old City & Waterfall Tour* – price €12.35 → €13.50 (+9.3%)
> 💬 *Antalya/Alanya Rafting…* – new 4★ review: "We were a group of six…"
> 🆕 New competitor in Antalya: *Design Your Own Signature Perfume* – €29.92 (20% off)

A run summary is also stored in the default key-value store under `OUTPUT`.

### FAQ

**Why didn't my first run report any changes?**
The first run records the baseline. Changes, new reviews and new competitors are reported from the second run on.

**Why do I get ERROR items with HTTP 403?**
GetYourGuide blocks most automated traffic. Use the `UNBLOCKER` proxy group (it's the default on Apify when the proxy field is empty). Failed tours are never charged.

**Why don't I get NEW_COMPETITOR for every tour I haven't seen?**
City pages show a changing selection of tours. Only tours that are actually new (GetYourGuide's "New activity" badge or 10 reviews or fewer, and newer than anything seen before) are reported.

**Prices are in a different currency than I asked for.**
In fast mode prices come in your chosen currency. Tours checked on their own page (availability tracking, or tours missing from the feed) use the currency GetYourGuide picks for the visitor's location. Prices are only ever compared within the same currency, so this never creates a fake price change.

**The alert says €7.60 but GetYourGuide shows €8.**
GetYourGuide rounds prices on its pages; the Actor reports the exact price from GetYourGuide's data. The crossed-out price is rounded too, so a small discount can look like none.

**A tour's review count went up by 5 but I got 2 `NEW_REVIEW` items.**
The review count GetYourGuide shows can lag behind its review list, so some of those reviews were already known from an earlier run. Every review is reported exactly once.

**Why did a ranking change arrive a run later?**
GetYourGuide's city ranking shuffles during the day, so a tour can jump 15 places and back within hours. A `RANK_CHANGE` is only reported once two runs in a row show the move in the same direction, which filters out that noise.

**Is personal data collected?**
No. Reviewer names, countries and photos are dropped before anything is stored.

**Viator, Klook, Tripadvisor?**
Viator is planned next.

***

This Actor is an independent tool and is not affiliated with, endorsed by or sponsored by GetYourGuide. It only reads publicly available pages.

# Actor input Schema

## `tourUrls` (type: `array`):

GetYourGuide tour pages to watch, e.g. https://www.getyourguide.com/antalya-l172/antalya-suluada-island-boat-trip-with-lunch-hotel-pickup-t468561/. Required unless you give search queries.

## `searchQueries` (type: `array`):

GetYourGuide listing pages (recommended), e.g. https://www.getyourguide.com/antalya-l172/, or free-text searches such as "antalya boat tour". New tours appearing here are reported as NEW_COMPETITOR. Free-text search results on GetYourGuide can be unrelated to the query, so prefer listing URLs.

## `trackPrice` (type: `boolean`):

Report changes of the "From" price per person.

## `trackAvailability` (type: `boolean`):

Report dates that become available, sold out or unavailable. Needs each tour's own page, so it is billed as an extra availability-checked event per tour.

## `availabilityDays` (type: `integer`):

How many days ahead to watch availability for, starting tomorrow. Today is skipped because same-day booking closes during the day, which would look like a change on every run.

## `trackReviews` (type: `boolean`):

Report new reviews (rating, text, date, language). Reviewer names are never collected.

## `maxReviewsPerTour` (type: `integer`):

Upper limit of newest reviews checked per tour in one run. Paging stops earlier once already-seen reviews are reached.

## `minPriceChangePct` (type: `integer`):

Only report price changes of at least this many percent. 0 reports every change of 0.01 or more. Smaller moves are not lost: they add up until they cross the threshold.

## `minReviewCountChange` (type: `integer`):

Report a RATING_CHANGE when the review count grows by at least this many (a rating move of 0.05 or more is always reported). Each new review is already its own NEW_REVIEW item, so the default only flags bigger bursts. Set 1 to get a rating alert on every new review.

## `minRankChange` (type: `integer`):

Report a RANK_CHANGE when a tour moves at least this many places in its city ranking (fast mode), on two runs in a row in the same direction. GetYourGuide's ranking shuffles during the day, so a one-off jump is ignored. Small moves add up until they cross the threshold.

## `currency` (type: `string`):

3-letter currency code you expect prices in. GetYourGuide chooses the currency by visitor location, so the actual currency is reported on every price, and prices are only compared within the same currency. A warning is logged when it differs.

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

Language code sent to GetYourGuide as the preferred page language. Reviews in all languages are reported, each with its language.

## `includeSnapshot` (type: `boolean`):

Also output one SNAPSHOT item per tour with its full current state, even when nothing changed.

## `includeOperatorName` (type: `boolean`):

Look up the company that runs each tour and add it to every alert. Needs one extra tour-page request per tour, once (it is remembered afterwards); tours read from their own page get it for free.

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

Maximum parallel requests. Keep this low to avoid being blocked.

## `useLocationFeed` (type: `boolean`):

Reads up to 24 tours per request from GetYourGuide's city feed (price in your currency, discount, rating, review count, "booked yesterday"), which makes runs much cheaper. Tours not found in the feed are checked on their own page automatically. When availability tracking is on, tours are read from their own pages, because per-date availability exists only there.

## `feedMaxPages` (type: `integer`):

How many feed pages (24 tours each) to read per city: for your tours before checking any missing ones on their own page, and for each listing in "Listings to watch" when scanning for new competitors. Each listing page scanned is billed as one listing-page-checked event.

## `proxyConfiguration` (type: `object`):

Proxies used for requests. GetYourGuide blocks most automated requests; the UNBLOCKER group (Special tab) is the only option that worked reliably in testing. If you leave this empty, runs on Apify use UNBLOCKER automatically.

## Actor input object example

```json
{
  "tourUrls": [
    "https://www.getyourguide.com/antalya-l172/antalya-suluada-island-boat-trip-with-lunch-hotel-pickup-t468561/",
    "https://www.getyourguide.com/antalya-l172/antalya-old-city-tour-wboat-trip-cable-car-waterfalls-t1156943/"
  ],
  "searchQueries": [
    "https://www.getyourguide.com/antalya-l172/"
  ],
  "trackPrice": true,
  "trackAvailability": false,
  "availabilityDays": 14,
  "trackReviews": true,
  "maxReviewsPerTour": 50,
  "minPriceChangePct": 0,
  "minReviewCountChange": 10,
  "minRankChange": 3,
  "currency": "EUR",
  "language": "en",
  "includeSnapshot": false,
  "includeOperatorName": false,
  "maxConcurrency": 4,
  "useLocationFeed": true,
  "feedMaxPages": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ]
  }
}
```

# Actor output Schema

## `changes` (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 = {
    "tourUrls": [
        "https://www.getyourguide.com/antalya-l172/antalya-suluada-island-boat-trip-with-lunch-hotel-pickup-t468561/",
        "https://www.getyourguide.com/antalya-l172/antalya-old-city-tour-wboat-trip-cable-car-waterfalls-t1156943/"
    ],
    "searchQueries": [
        "https://www.getyourguide.com/antalya-l172/"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "UNBLOCKER"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("voranil/getyourguide-price-monitor").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 = {
    "tourUrls": [
        "https://www.getyourguide.com/antalya-l172/antalya-suluada-island-boat-trip-with-lunch-hotel-pickup-t468561/",
        "https://www.getyourguide.com/antalya-l172/antalya-old-city-tour-wboat-trip-cable-car-waterfalls-t1156943/",
    ],
    "searchQueries": ["https://www.getyourguide.com/antalya-l172/"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["UNBLOCKER"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("voranil/getyourguide-price-monitor").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 '{
  "tourUrls": [
    "https://www.getyourguide.com/antalya-l172/antalya-suluada-island-boat-trip-with-lunch-hotel-pickup-t468561/",
    "https://www.getyourguide.com/antalya-l172/antalya-old-city-tour-wboat-trip-cable-car-waterfalls-t1156943/"
  ],
  "searchQueries": [
    "https://www.getyourguide.com/antalya-l172/"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ]
  }
}' |
apify call voranil/getyourguide-price-monitor --silent --output-dataset

```

## MCP server setup

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

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/7gyv8hAVtLFFpidad/builds/j7VGJO9eQJXltHw14/openapi.json
