Viator Scraper – Tours, Activities, Prices & Availability avatar

Viator Scraper – Tours, Activities, Prices & Availability

Pricing

from $1.50 / 1,000 results

Go to Apify Store
Viator Scraper – Tours, Activities, Prices & Availability

Viator Scraper – Tours, Activities, Prices & Availability

Collect Viator.com tour and activity results from destinations, categories, search pages, or pasted URLs. Returns product codes, prices, ratings, reviews, images, availability, source context, and optional detail fields.

Pricing

from $1.50 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

13

Total users

3

Monthly active users

5 hours ago

Last modified

Share

Viator Scraper: Tours, Activities, Prices and Ratings

Viator Scraper turns Viator into structured travel data. Get tour and activity listings for seven major destinations and six tour categories, including prices, ratings, review counts, availability, images and source breadcrumbs, plus optional full product page detail with descriptions, complete image lists, recent reviews and itinerary stops. Pick a destination and category, or paste Viator listing URLs, then export to JSON, CSV or Excel, or pull results straight into your app through the API.

Why This Scraper?

  • Two ways to find data. Pick a destination and category preset (7 destinations, 6 categories), or type any destination name, or paste Viator destination, category or product URLs directly. No need to build URLs by hand.
  • Filters and sort work everywhere. Keyword, price range, currency, minimum rating, minimum reviews and availability all narrow and reorder results in both search mode and URL mode, including a pasted URL's results.
  • Optional detail enrichment. Turn on Fetch details to open each product's own page for its full description, complete image list, up to Max reviews per product reviews (newest first across all sources, with language, title, helpful votes, photos and owner responses where present) and itinerary stops. Rows are still saved when a product page can't be opened.
  • Nothing lost on a failed run. Every matching row is written to the dataset as soon as it's found, so a run that stops partway through still keeps what it already collected.
  • Deduplicated pagination. Listing pages are walked until Max items is reached or a page repeats an earlier page's results, and the same product is never saved twice.
  • Cost control built in. Max items and Max pages cap a run before it starts, and detail enrichment is billed only for the product pages that are successfully enriched.

Use Cases

  • Travel research and itinerary planning: compare tours and activities in a destination by price, rating and availability before booking.
  • Price and catalog monitoring: track how listed prices, availability and review counts for a set of products change over time.
  • Market research for tour operators: see how bus tours, walking tours, day trips and attractions in a destination are priced and reviewed.
  • Content and affiliate sites: pull activity names, images, descriptions and ratings to build destination guides or comparison pages.
  • Outreach and lead lists: collect tour and operator names with source context for a destination or category to prioritize outreach.

Data You Get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
name"Boston Hop-On Hop-Off Trolley Tour"
productCode"5892HOHO"
urlViator link to the activity
imageMain image URL
locationName"Boston" (destination name parsed from page context, when available)
addressLocality"Boston" (locality parsed from page context, when available)
addressCountryName"United States" (parsed from the page's breadcrumb, when available)
offerPrice / offerCurrency42.5 / "USD"
availability"InStock"
priceValidUntil"2027-01-01" (when present)
ratingValue / exactRating4.6 / 4.6 (both read from the same source rating)
bestRating / worstRating5 / 1
reviewCount1280
descriptionfull activity description (when Fetch details is on)
imagesall product image URLs (when Fetch details is on)
reviewsup to Max reviews per product reviews, each with author, rating, date, text, language, title, helpful votes and source, plus photos, traveller type and the owner's reply when the review has them (when Fetch details is on). If the full review list cannot be read for a product, the reviews shown on its page (up to 30, without language) are kept and the row is still saved
itineraryStopCount / itineraryStopsstop count and stop names (when Fetch details is on)
positionposition on the source listing page
sourceUrl / sourcePagelisting page URL and page number the row came from
sourceName / sourceDescriptionlisting page title and description text
breadcrumbslisting page breadcrumb labels
detailStatus"not_requested", "enriched", "no_structured_detail", or "unavailable"
detailErrordetail fetch error summary (only when Fetch details fails for that row)
scrapedAtISO timestamp

Every row is a tour or activity listing; there is no separate record type. description, images, reviews, itineraryStopCount and itineraryStops are only populated when Fetch details is switched on, and only for the rows whose product page loaded successfully.

How to Use

  1. Pick a mode: search (destination and category preset) or url (paste Viator listing links).
  2. Fill in the fields for that mode: destination and category for search mode, or one or more listing URLs for URL mode.
  3. Optionally set keyword, price, currency, rating, review and availability filters, choose a sort order, and turn on Fetch details for full product pages.
  4. Set Max items and Max pages to control run size and cost, then click Start.

Search Boston bus tours, filtered and sorted:

{
"mode": "search",
"destination": "boston",
"category": "bus_tours",
"keyword": "hop",
"minRating": 4,
"minReviews": 50,
"sortBy": "price_asc",
"maxItems": 20,
"maxPages": 0
}

Search with detail enrichment:

{
"mode": "search",
"destination": "paris",
"category": "walking_tours",
"fetchDetails": true,
"maxItems": 10,
"maxPages": 1
}

Paste a listing URL, filters still apply:

{
"mode": "url",
"urls": ["https://www.viator.com/Boston-tours/Bus-and-Minivan-Tours/d678-g12-c98"],
"currency": "USD",
"minRating": 4,
"sortBy": "rating_desc",
"maxItems": 20
}

URL mode with a price range:

{
"mode": "url",
"urls": ["https://www.viator.com/London-tours/Tours-and-Sightseeing/d737-g12"],
"minPrice": 30,
"maxPrice": 150,
"maxItems": 30,
"maxPages": 0
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/viator-com-scraper").call(
run_input={"mode": "search", "destination": "boston", "category": "bus_tours", "maxItems": 20}
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
print(row["name"], row["offerPrice"], row["offerCurrency"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/viator-com-scraper').call({
mode: 'search',
destination: 'boston',
category: 'bus_tours',
maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Send results into your apps (MCP connectors)

Optionally pipe a capped subset of saved rows into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each row, not the full JSON. Each row becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where rows should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (destination/category preset) or url (pasted listing URLs).
destinationstringbostonDestination preset: Boston, New York City, Las Vegas, London, Paris, Rome, or Sydney. Search mode only; ignored in URL mode.
destinationQuerystringnoneSearch mode only. Type a destination name (for example Lisbon); it is looked up on Viator and used only when it resolves to a destination page with a matching name. No match stops the run with a clear message. Category still applies; ignored in URL mode.
categorystringtours_sightseeingCategory preset: Tours and sightseeing, Bus tours, Day trips, Walking tours, Food and drink, or Attractions and tickets. Search mode only; ignored in URL mode.
urlsarrayone example of each URL shape (category, destination, product)Viator category, destination page or single product URLs for URL mode. A search-results link works only when Viator redirects it to a destination page; free-text activity searches are not supported. Left untouched, URL mode scrapes one example of each shape.
keywordstringnoneText that must appear in the activity name, URL, destination or category text. Applies in both modes, including a pasted URL.
minPricenumbernoneMinimum listed price. Both modes.
maxPricenumbernoneMaximum listed price. Both modes.
currencystringAnyKeep only rows in a selected currency. Both modes.
minRatingnumbernoneMinimum aggregate rating. Both modes.
minReviewsintegernoneMinimum review count. Both modes.
availabilitystringAnyAvailability filter. Both modes.
sortBystringsourceSource, price, rating, or review-count order. Both modes. A price, rating or review-count sort is applied across all crawled pages: the run keeps crawling until it holds Max items matching rows (or Max pages or the end of the results), then sorts them together. Source order saves each page as it is read.
maxReviewsPerProductinteger20Most reviews kept per product when Fetch details is on (0 to 100). Reviews add no separate charge.
fetchDetailsbooleanfalseOpen each product page for description, all images, reviews and itinerary. Results are still saved if a product page is unavailable.
maxItemsinteger20Maximum matching rows to save (at least 1). Fewer rows can be returned when the source and filters match fewer live records.
maxPagesinteger0No page limit when set to 0. The run stops at Max items.
proxyobjectResidential (Apify Proxy)Connection settings.
resumeFromRunIdstringnoneRun or dataset id of an earlier run; products it already collected are skipped.
incrementalModebooleanfalseReturn only NEW, UPDATED and REAPPEARED products compared with the last run of the same setup.
stateKeystringautoName a monitoring campaign, or share state between setups.
emitUnchangedbooleanfalseAlso return UNCHANGED products (billed as result rows).
emitExpiredbooleanfalseAlso return EXPIRED products, only after a fully scanned run (billed as result rows).
ignoreFieldsForChangesarraynoneOutput fields that never make a product UPDATED.
mcpConnectorsarraynoneOptional: send a summary of each saved row to apps you authorized under Integrations.
notionParentPageUrlstringnoneNotion connector only: page under which rows are created.
maxNotifyListingsinteger50Cap on rows written to each connector per run (1-1000). Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live record.

{
"name": "Boston Hop-On Hop-Off Trolley Tour",
"productCode": "5892HOHO",
"url": "https://www.viator.com/tours/Boston/Old-Town-Trolley-Tour/d678-5892HOHO",
"image": "https://media.viator.com/sample-image-1.jpg",
"locationName": "Boston",
"addressLocality": "Boston",
"addressCountryName": "United States",
"offerPrice": 42.5,
"offerCurrency": "USD",
"availability": "InStock",
"priceValidUntil": "2027-01-01",
"ratingValue": 4.6,
"exactRating": 4.6,
"bestRating": 5,
"worstRating": 1,
"reviewCount": 1280,
"description": "Hop on and off a narrated trolley at stops around Boston's historic sites.",
"images": [
"https://media.viator.com/sample-image-1.jpg",
"https://media.viator.com/sample-image-2.jpg"
],
"reviews": [
{ "author": "Sample Traveler", "rating": 5, "date": "2025-06-01", "text": "Great way to see the city.", "language": "en", "source": "VIATOR" }
],
"itineraryStopCount": 3,
"itineraryStops": ["Faneuil Hall", "Boston Common", "North End"],
"position": 3,
"sourceUrl": "https://www.viator.com/Boston-tours/Bus-and-Minivan-Tours/d678-g12-c98",
"sourcePage": 1,
"sourceName": "Boston Bus and Minivan Tours",
"sourceDescription": "Bus and minivan tours in Boston.",
"breadcrumbs": ["Home", "Things to do in United States", "Boston", "Bus and Minivan Tours"],
"detailStatus": "enriched",
"scrapedAt": "2026-09-28T12:00:00.000000+00:00"
}

Plan Requirement

Viator protects its pages with an interactive bot challenge, so this actor reads them through Apify residential proxies, which are selected by default. Residential proxies are not included in Apify free plans, so a free plan cannot rely on the default connection.

  • If the selected connection is unavailable to the run, the log says: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable." Rows can still be returned, but fewer pages may load.
  • If the backup also cannot load the pages, the run fails with: "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested Viator pages." Upgrade your plan or supply your own proxy URLs under Connection.
  • If the proxy is refused for the whole account, the run fails with: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required."
  • If no results page can be loaded for another reason, the run fails with: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search."

A failed run is never reported as an empty success. Rows saved before a failure stay in the dataset.

Billing

The actor bills a small start charge per run and one result event per saved row. When Fetch details is on, it also bills one detail-enrichment event for each product page that is successfully enriched; rows whose product page is unavailable are not charged that event. Reviews are part of detail enrichment and add no separate charge. The Pricing tab shows current rates.

Views

The dataset has four views: Viator activities (one row per listing), Activity details (the enriched product fields) and Reviews (one row per review), which unwinds the reviews array of enriched products. A fourth view, Changes (incremental mode), lists the change columns when incremental mode is on.

FAQ

How much does it cost?

You pay a small start charge per run and a fee per saved result, plus a detail-enrichment charge for each row that is successfully enriched when Fetch details is on. The Pricing tab shows current rates. Use Max items and Max pages to cap the cost of a run.

This actor collects only publicly available tour and activity listings. You are responsible for how you use it: follow Viator's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Reviews, photos and descriptions may be subject to third-party rights.

Do the filters and sort also apply when I paste a URL?

Yes. Keyword, price range, currency, minimum rating, minimum reviews, availability and sort order all apply to search mode and to a pasted URL's results alike. Only Destination, Destination (type a name) and Category are search-mode settings; they pick the listing page that search mode walks and are ignored in URL mode, where the pasted URL is the source instead.

Can I schedule recurring runs, or get only new results?

Yes. Turn on Incremental changes for scheduled runs and schedule the actor: the first run returns every matching product as NEW, later runs return only NEW, UPDATED and REAPPEARED products with changeType, changedFields, firstSeenAt and lastSeenAt. Unchanged products are not saved or billed unless you turn on Emit unchanged products; Emit expired products adds products that disappeared, but only when the run scanned every source to a confirmed end of results (not after a Max items or Max pages cut, and not after Resume). When Fetch details is on, the detail event is billed only for rows that are actually saved. Prices come back in the local currency of the connection a run used, so two runs can differ on offerPrice and offerCurrency without any product change; add those fields to Ignore fields when detecting changes if you only want other changes. The listing rank (position) and the review list never count as a change, so new review text alone does not make a product UPDATED. With Fetch details on, a product page that could not be read in a run is not treated as a change either: the last good detail is kept for comparison and the row is reported only when something else changed. Use Resume from a previous run to continue one specific earlier run instead.

Why did my run return 0 rows instead of an error?

URL mode needs at least one URL: if Mode is url and no URL is provided, the run completes with an empty dataset. A destination and category combination, or a keyword and filter set, with no matching live listings can also legitimately return 0 rows.

Why did my run fail instead of returning an empty dataset?

If a listing page can't be loaded at all, even after retries and one proxy session rotation, the run stops with an error rather than reporting an empty result as if nothing was there. Rows already saved before the failure stay in the dataset. See the Plan Requirement section for the exact messages; try again, or use residential proxy or your own proxy URLs under Connection.

What happens if my typed destination is not found?

The name is looked up on Viator. If it does not resolve to a destination page with a matching name, the run stops with the message "No Viator destination matches ..." and saves nothing, instead of scraping a different place. Check the spelling or pick a destination from the list.

Yes. A product page URL (a Viator tour link ending in the product code, such as d678-358782P2) returns one row for exactly that product, matched on its product code. Like every other row, it carries the listing-level fields only (detailStatus is not_requested) unless Fetch details is on, in which case it also carries the description, images, reviews and itinerary, and the detail event is billed once for that row after it is saved. A page that does not carry that product is skipped with a warning and never replaced by a different tour.

What happens if I leave the URL list untouched?

URL mode with the field untouched now scrapes one example of each supported shape: a category listing, a destination page and a single product page. Replace the list with your own URLs for real runs.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push a summary of saved rows into Notion, Linear or Airtable.

🔗 Want more travel data?

Pair this actor with these related scrapers from the same team:

🧩 KKday Scraper
Scrape KKday travel activities by keyword, city or URL. Every row carries prices...
🏨 Klook Scraper
Scrape Klook activities, tours, attractions and travel experiences from search pages or...
✈️ Naver Map Scraper
Scrape Naver Map places by keyword or URL: names, categories, ratings, phones, addresses...
🛒 The Warehouse NZ Scraper
Scrape The Warehouse New Zealand search results, category pages, and direct product URLs...
✈️ FurnishedFinder
Scrape furnishedfinder.com listings by city or URL. Extract structured data including...
🏨 Vrbo Scraper
Extract vacation rental data from Vrbo.com by location, region, coordinates, property...

👉 Browse all abotapi scrapers

💬 Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.