Viator API Scraper avatar

Viator API Scraper

Pricing

from $2.64 / 1,000 activity rows

Go to Apify Store
Viator API Scraper

Viator API Scraper

Viator API Scraper: scrape and unify tour and activity prices from Viator and GetYourGuide into one normalized schema — prices, duration, ratings, review counts, booking URLs per activity — export to JSON or CSV. A Viator / GetYourGuide API alternative for tour operators and OTA analysts.

Pricing

from $2.64 / 1,000 activity rows

Rating

0.0

(0)

Developer

DevilScrapes

DevilScrapes

Maintained by Community

Actor stats

0

Bookmarked

8

Total users

2

Monthly active users

17 hours ago

Last modified

Features

Limited permissions

Share

Viator and GetYourGuide Scraper

Viator & GetYourGuide Scraper

We do the dirty work so your dataset stays clean. 😈

$3.00 / 1,000 activity rows — pay per result, no start fee.

Viator and GetYourGuide list overlapping inventory with different SKUs and prices. Running two single-source scrapers and writing your own normalization layer costs 1–2 dev-weeks and still leaves you with mismatched schemas. This Actor hits both platforms in one run, absorbs the blocks and retries, and emits one flat row per activity — platform, price, rating, duration, booking URL — straight into your Apify dataset.

One run. One schema. Ready for your spreadsheet, BI tool, or warehouse.

🎯 What this scrapes

Two major tours-and-activities platforms, unified into one validated schema:

  1. Viator — viator.com/searchResults/all?text=<query> (24 cards per page)
  2. GetYourGuide — getyourguide.com/s/?q=<query> (24 cards per page)
  3. Klook (future upgrade — currently returns 0 rows) — Klook's search is gated by a JS challenge that requires full browser execution. Documented as a future upgrade; this version returns no Klook rows and logs a warning.

Output rows carry every field needed for cross-platform comparison:

FieldTypeDescription
platformstringPlatform literal (viator, getyourguide, klook)
activity_idstringPlatform-canonical activity ID
activity_titlestringCard title text
location_querystringEcho of the user input — useful when batching cities
location_citystring | nullBest-effort city parsed from URL or query
location_countrystring | nullBest-effort country
price_usdnumber | nullUSD price when the platform itself displays USD
currency_originalstring | nullISO 4217 code parsed from the price symbol
price_originalnumber | nullNumeric price in the displayed currency
duration_hoursnumber | nullActivity duration in hours; midpoint for ranges
ratingnumber | nullStar rating, 0–5 scale
review_countinteger | nullNumber of reviews
operator_namestring | nullTour operator/supplier when surfaced
categorystring | nullCard tag (tour, experience, ...)
booking_urlstringAbsolute URL to the activity page
image_urlstring | nullAbsolute URL to the primary thumbnail
scraped_atstringISO 8601 UTC timestamp

🔥 Features

  • Two platforms, one schema — drop the dataset straight into a spreadsheet or BI tool; no per-platform normalization required.
  • We retry with increasing delays — temporary failures trigger up to 5 attempts and Retry-After headers are honoured. Temporary connection failures are retried a few times on the same route.
  • Apify Proxy on by default — requests use a US residential exit; if it is unavailable on your account the run stops with a clear error rather than switching route. Switch useProxy off for direct routing.
  • Per-platform isolation — one platform's failure does not abort the run; surviving platforms still produce data.
  • Currency-aware — symbol-to-ISO mapping (€/$/£/¥ → EUR/USD/GBP/JPY); price_usd is populated only when the platform itself displays USD.
  • Duration parser handles ranges — "5 to 9 hours" → 7.0 (midpoint); "30 minutes" → 0.5; "1 day" → 24.0.
  • Input and output validation — input and every output row are validated; invalid input fails fast with a clear error before any network call.
  • Clean dataset rows — ISO-8601 timestamps, stable platform IDs, no half-parsed strings.
  • Configurable cap — maxPerPlatform lets you cap each platform at 1–100 rows per run.

💡 Use cases

  • Tour operator competitive intelligence — find every activity your competitors list in your destination, compare prices, ratings, and durations side-by-side.
  • OTA cross-platform analyst dashboards — feed a BI tool with snapshots of how Viator and GetYourGuide each rank the same destination.
  • Dynamic pricing strategy — track how the same activity type is priced on each platform over time and adjust your own listings accordingly.
  • Destination intelligence reports — schedule weekly runs for "Paris" or "Tokyo" into a named dataset and chart price drift.
  • Travel-blogger affiliate research — surface high-rating, high-review-count activities for destination guides without manual browsing.
  • Inbound-tour-builder market research — discover which experiences dominate the first-page results when entering a new destination.
  • Travel-tech investor diligence — benchmark the top-of-funnel pricing across the experience-booking layer of the travel stack.

⚙️ How to use it

  1. Open the Actor input form.
  2. Type a Destination (Paris, New York, Tokyo, Bali, …).
  3. (Optional) Pick Platforms — leave empty to scrape all three, or list a subset like ["viator"] or ["getyourguide"]. Klook returns 0 rows in this version (documented limitation).
  4. (Optional) Set Max rows per platform — default 20, max 100.
  5. Leave Use Apify Proxy on (default) to route requests through a US residential exit.
  6. Click Start. Results stream into the default dataset.

Quick examples

Both supported platforms, default cap:

{
"locationQuery": "Paris"
}

GetYourGuide only, 5 rows (fastest path to confirm output shape):

{
"locationQuery": "Paris",
"platforms": ["getyourguide"],
"maxPerPlatform": 5,
"useProxy": false
}

Viator only, 50 rows:

{
"locationQuery": "Tokyo",
"platforms": ["viator"],
"maxPerPlatform": 50,
"useProxy": false
}

📥 Input

JSON keyTypeDefaultDescription
locationQuerystring(required)Destination text query (e.g. "Paris")
platformsarray of literal[] (= all 3)Subset of viator / getyourguide / klook
maxPerPlatforminteger20Cap on rows per platform (1–100)
useProxybooleantrueRoute via Apify Proxy using a US residential exit; the run stops with an error if that proxy is unavailable

locationQuery is the only required field. Whitespace is stripped; blank values are rejected up-front by input validation before any network call is made.

📤 Output

One row per activity. See the What this scrapes table above for the full schema.

{
"platform": "getyourguide",
"activity_id": "508441",
"activity_title": "Paris: Le Marais Guided Food Tour with Tastings",
"location_query": "Paris",
"location_city": "Paris",
"location_country": null,
"price_usd": null,
"currency_original": "EUR",
"price_original": 69.0,
"duration_hours": 3.0,
"rating": 4.9,
"review_count": 506,
"operator_name": null,
"category": "experience",
"booking_url": "https://www.getyourguide.com/paris-l16/no-diet-club-unique-local-food-tour-in-paris-le-marais-t508441/",
"image_url": "https://cdn.getyourguide.com/image/.../tour_img/7b9edf635985a601.jpeg",
"scraped_at": "2026-05-16T22:00:00.000Z"
}

💰 Pricing

No Actor start fee. You pay for the output events below.

EventUSD per eventBilling unit
result-row$0.003Charged per activity row emitted (one row per platform x activity).

1,000 output events cost $3.00 at the standard rate, with no start charge.

Existing subscriber discounts remain available in the Apify Pricing tab.

🚧 Limitations

  • Klook returns 0 rows in this version — Klook's search is gated by a JS challenge that cannot be cleared without a full browser. We document this up front and ship without it rather than over-promise.
  • First page only — no pagination across multiple result pages. Each platform returns ~20–24 cards on the first page; the default cap is 20.
  • No detail-page scraping — we scrape the search-results surface only. Itineraries, photo galleries, availability calendars, and meeting points are out of scope.
  • Currency follows the platform's display — price_usd is populated only when the platform itself displays USD. We do not run our own FX conversion.
  • Search relevance is the platform's — "Paris" can include cards for Versailles or nearby destinations, depending on each platform's relevance engine.
  • Residential proxy only — with useProxy on, requests use a US residential exit, which keeps prices and currency comparable across runs. If the residential proxy is unavailable on your account the run fails with an error instead of using another route.
  • A run fails when no platform returns rows — if every platform is blocked or returns nothing readable, the run is marked failed rather than reporting an empty success.

❓ FAQ

Q: Does Viator or GetYourGuide offer an official API I can use instead? A: Viator and GetYourGuide do publish partner APIs, but they require approved partner status, commercial agreements, and ongoing approval processes that most independent developers and analysts cannot access. This Actor scrapes the public search-results pages — no partner relationship needed. The output schema is compatible with what a partner API would return for the same fields.

Q: Why is Klook in the schema but returns 0 rows? A: Klook gates its search behind a JS challenge that cannot be cleared without a full browser. We kept the platform literal in the schema so a future upgrade can land without breaking the dataset shape — but for now, every Klook call returns no rows with a warning. Use platforms: ["viator", "getyourguide"] to skip the wasted call entirely.

Q: How is duration_hours parsed? A: Viator and GetYourGuide write durations in several formats: "3 hours", "1 hour", "30 minutes", "5 to 9 hours", "1 day", "2.5 hours". We parse all of them. For ranges, we use the midpoint ("5 to 9 hours" → 7.0). Anything unparseable stays null rather than crashing the row.

Q: Can I track an activity's price across multiple runs? A: Yes — each run is independent. To track an activity over time, schedule periodic runs and write to a named dataset or export to your warehouse. The Apify default dataset retention is limited; a named dataset persists until you delete it.

Q: Can I batch multiple cities in one run? A: Not currently — one locationQuery per run. To batch, schedule one Actor task per city. Each result row carries location_query so downstream pivots stay correct.

Q: Why default useProxy: true? A: Both platforms run behind edge protection and can refuse datacenter traffic. The default-on posture uses a US residential exit for materially higher first-page success rates. If you are running from a clean residential network, you can set it to false.

Q: Why no detail-page scraping? A: Each detail page is a heavier scrape (cancellation policy, photos, availability) and is behind additional edge protection. This version ships the breadth-first surface-level price intel most buyers need.

💬 Your feedback

Found a parser glitch, a missing platform, or a field that's broken? Open an issue on the Actor's Apify Store page. We read every report.