# Tripadvisor Scraper — Reviews, Hotels, Restaurants, Attractions (`tortuga/tripadvisor-scraper`) Actor

Scrape Tripadvisor reviews and hotel, restaurant and attraction data from any Tripadvisor URL or destination: ratings, rankings, addresses, hours, owner responses.

- **URL**: https://apify.com/tortuga/tripadvisor-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 reviews

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

## Tripadvisor Scraper — Reviews, Hotels, Restaurants, Attractions

Scrape **Tripadvisor reviews** and **hotel, restaurant and attraction data** from any Tripadvisor URL (tripadvisor.com, .co.uk, .fr, .de, .es, .it, .com.br ... every country site) or from a destination name like "Lisbon". Get ratings, review counts, rankings ("#3 of 1,200 restaurants in Paris"), rating breakdowns, addresses, coordinates, phone numbers, emails and websites as the business publishes them, price levels, cuisines and amenities — and every review with its original text, date, language, trip type, sub-ratings, photos, reviewer name and location as shown, and the owner's response.

- Two modes: **reviews** (one row per review) and **places** (one row per hotel, restaurant or thing to do).
- All reviews of a place, every year and every language, or only some languages.
- **Only new reviews** on a schedule: a date cutoff ("7 days") or "only new or changed items" — unchanged items are not charged.
- No login, no browser, no residential proxy: fast and cheap to run.

### What data does it extract?

#### Reviews (`mode: reviews`, default)

| Field | Example |
|---|---|
| `reviewId`, `reviewUrl` | `1080444999`, link to the review on Tripadvisor |
| `placeId`, `placeName`, `placeType`, `placeUrl` | `228694`, `Hotel Malte - Astotel`, `hotel` |
| `rating` | `5` (1-5 bubbles) |
| `title`, `text` | full review text |
| `language` | `en`, `fr`, `zhCN` ... |
| `publishedDate` | `2026-10-04` (day of publication) |
| `travelDate` | `2026-10` (month of the stay or visit) |
| `tripType` | `COUPLES`, `FAMILY`, `FRIENDS`, `BUSINESS`, `SOLO` (when the reviewer gave it) |
| `helpfulVotes` | `3` |
| `subratings` | `{"Service": 5, "Value": 5, "Food": 5, "Atmosphere": 5}` (when the reviewer gave them) |
| `photos` | URLs of the reviewer's photos |
| `reviewerName`, `reviewerLocation` | `Ramon D`, `Barcelona, Spain` (as shown on Tripadvisor) |
| `reviewerProfileUrl`, `reviewerContributions` | public profile link; the reviewer's review count is no longer served (empty) |
| `ownerResponse`, `ownerResponseDate`, `ownerResponseAuthor`, `ownerResponseRole` | management response text, date, responding account, `General Manager` |

#### Places (`mode: places`)

| Field | Example |
|---|---|
| `placeId`, `name`, `type`, `url` | `188151`, `Eiffel Tower`, `attraction` (`hotel`, `restaurant`, `activity`) |
| `rating`, `reviewCount` | `4.6`, `144129` |
| `ranking`, `rankingPosition`, `rankingTotal`, `rankingGeo` | `#9 of 4,278 things to do in Paris`, `9`, `4278`, `Paris` |
| `ratingHistogram` | `{"excellent": 101641, "veryGood": 30138, "average": 8858, "poor": 1971, "terrible": 1515}` |
| `categories` | `Sights & Landmarks`, `Observation Decks & Towers` / `Hotel` / `Sit down` |
| `cuisines` | `Italian`, `Pizza` |
| `amenities`, `hotelClass` | `Free Wifi`, `Concierge` ... / `4.0` |
| `priceLevel`, `priceRange` | `$$ - $$$`, `$12 - $27` |
| `address`, `street`, `city`, `state`, `postalCode`, `country`, `neighborhoods` | `2 Boulevard Morland, 75004 Paris France` ... |
| `latitude`, `longitude`, `timezone` | `48.858353`, `2.294464`, `Europe/Paris` |
| `phone`, `website`, `email` | as published by the business on Tripadvisor |
| `description`, `photoUrl`, `photoCount`, `localName`, `localAddress` | |
| `isClosed` | `true` when Tripadvisor marks the place closed |

`ratingHistogram`, `photoCount`, `localName` and `localAddress` are added for place URLs, and for places from lists or destinations with **Add rating breakdown to list places** on.

Since Tripadvisor changed its app data on 2026-10-22, `openingHours`, `dietaryRestrictions` and `recommendedVisitLength` are no longer served and stay empty (the fields are kept so existing integrations do not break).

### How to scrape Tripadvisor reviews

1. Paste one or more place URLs into **Tripadvisor URLs** — hotels, restaurants, attractions or tours, from any Tripadvisor country site.
2. Set **Max reviews per place** (and **Max items** for the whole run).
3. Optional: **Review languages** (`en`, `fr`, `de` ...) or **Only reviews newer than** (`30 days`, `2026-09-01`).

```json
{
  "mode": "reviews",
  "startUrls": [
    { "url": "https://www.tripadvisor.com/Hotel_Review-g187147-d228694-Reviews-Hotel_Malte_Astotel-Paris_Ile_de_France.html" },
    { "url": "https://www.tripadvisor.co.uk/Restaurant_Review-g187147-d34162331-Reviews-Pizzeria_Arrivederci_4eme-Paris_Ile_de_France.html" }
  ],
  "maxReviewsPerPlace": 500,
  "maxItems": 1000
}
```

You can also give a list or destination (a `Restaurants-g187147-...` URL, a `Tourism-g...` page, or **Destinations**: `["Lisbon"]`): the actor takes its top **Max places per list** places in Tripadvisor ranking order and scrapes their reviews.

Output (one review):

```json
{
  "reviewId": "1080444999",
  "placeId": "228694",
  "placeName": "Hotel Malte - Astotel",
  "placeType": "hotel",
  "placeUrl": "https://www.tripadvisor.com/Hotel_Review-g187147-d228694-Reviews-Hotel_Malte_Astotel-Paris_Ile_de_France.html",
  "rating": 5,
  "title": "A Wonderful Stay with Exceptional Service and a Special Birthday Surprise",
  "text": "We had a wonderful stay at Hotel Malte Astotel in Paris. From the moment we arrived, ...",
  "language": "en",
  "publishedDate": "2026-10-04",
  "travelDate": "2026-10",
  "tripType": "COUPLES",
  "helpfulVotes": 0,
  "subratings": null,
  "photos": [],
  "reviewerName": "Ramon D",
  "reviewerLocation": null,
  "reviewerProfileUrl": "https://www.tripadvisor.com/MemberProfile-a_uid.DCB85738DBE471E2CD82CDD9A428CEDB",
  "reviewerContributions": null,
  "ownerResponse": "Dear Ramon D,\n\nThank you for choosing Hotel Malte - Astotel for such a special celebration ...",
  "ownerResponseDate": "2026-10-05",
  "ownerResponseAuthor": "Paris_Astotel",
  "ownerResponseRole": "General Manager",
  "reviewUrl": "https://www.tripadvisor.com/ShowUserReviews-g187147-d228694-r1080444999-Hotel_Malte_Astotel-Paris_Ile_de_France.html#review1080444999",
  "scrapedAt": "2026-10-10T04:31:13+00:00"
}
```

### How to scrape hotels, restaurants and things to do in a city

Choose **Places**, then give list URLs (`https://www.tripadvisor.com/Restaurants-g189158-Lisbon_Lisbon_District_Central_Portugal.html`, `Hotels-g...`, `Attractions-g...`) or destination names with the **Place types** you want. Places come in Tripadvisor's ranking order ("Traveler favorites"), 50 per request, from the area around the destination; places of neighbouring destinations are left out.

```json
{
  "mode": "places",
  "searchQueries": ["Lisbon"],
  "placeTypes": ["restaurants", "hotels"],
  "maxPlacesPerSearch": 200,
  "maxItems": 400,
  "includeDetails": false
}
```

Output (one place, shortened):

```json
{
  "placeId": "27586618",
  "type": "restaurant",
  "name": "Ponto Com Sabores",
  "url": "https://www.tripadvisor.com/Restaurant_Review-g189158-d27586618-Reviews-Ponto_Com_Sabores-Lisbon_Lisbon_District_Central_Portugal.html",
  "rating": 4.9,
  "reviewCount": 655,
  "ranking": "#1 of 7,466 places to eat in Lisbon",
  "rankingPosition": 1,
  "rankingTotal": 7466,
  "priceLevel": "$$ - $$$",
  "priceRange": "$15 - $25",
  "cuisines": ["Italian", "Brazilian", "Mediterranean", "European", "Portuguese"],
  "address": "Rua Passos Manuel, 91A, Lisbon 1150-053 Portugal",
  "latitude": 38.730106,
  "longitude": -9.137014,
  "phone": "+351 21 247 4554",
  "website": "https://pontocomsabores.pt/",
  "ratingHistogram": {"excellent": 631, "veryGood": 19, "average": 4, "poor": 0, "terrible": 2}
}
```

### Monitor changes on a schedule

Turn on **Only new or changed items**, save the input as a task and add a Schedule in Apify (for example daily). In reviews mode each run checks the newest **Max reviews per place** reviews of every place (all languages merged by date) and saves only reviews it has not saved before; **Only reviews newer than** (`1 day`, `7 days` or a date) narrows it further. In places mode a place is saved again only when its rating, ranking position or closed status changed (review counts are not compared, they tick every day). Unchanged items are not output and not charged. New items carry `changeType: "new"`, changed ones `changeType: "changed"` plus `previousValues` with the old values of the fields that changed. Use **Monitoring key** to keep several schedules on the same input apart.

### How many reviews can I get per place?

All of them. Tripadvisor serves every review of a place through this actor, 20 per request, newest first across all languages. Reviews come in their original language and text (Tripadvisor's own list shows machine translations; the actor reads each translated review as written). **Review languages** filters by the review's original language; the actor reads the list until it has found enough reviews in those languages, so a rare language in a very large place takes longer.

### Does it work without login or a Tripadvisor account?

Yes. It reads only public data, needs no account or cookies, and runs on Apify's standard datacenter proxy.

### How much does it cost?

$2.00 per 1,000 reviews and $2.50 per 1,000 places, no start fee. Platform usage is small: about $0.0035 per 1,000 reviews and $0.0055 per 1,000 places in our test runs (2026-10-23; mostly Apify's dataset storage fee). 2,000 reviews of two places took 1 minute.

### Proxy note

The default Apify datacenter proxy is enough. Residential or Unblocker proxies are not needed and would only add cost.

### What is not included?

Travellers' Choice awards, opening hours, dietary options, recommended visit length and the reviewer's review count are shown on the website but are not part of the data Tripadvisor serves to this actor (since 2026-10-22), so they are not in the output. Hotel prices for specific dates are not scraped.

### Is it legal to scrape Tripadvisor?

The actor collects publicly visible data: place information as businesses publish it on Tripadvisor and reviews with the reviewer's display name and location as Tripadvisor shows them. It does not log in or access anything private. Reviews contain personal data (names, locations); make sure your use complies with GDPR and similar laws and with Tripadvisor's terms, and do not use the data to contact or profile individuals.

# Actor input Schema

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

reviews: one item per review (rating, title, text, dates, reviewer name and location as shown, owner response, photos). places: one item per hotel, restaurant or attraction (rating, ranking, address, coordinates, phone, website, cuisines, amenities, price level).

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

Any Tripadvisor country domain. Place pages (Hotel_Review-..., Restaurant_Review-..., Attraction_Review-..., AttractionProductReview-...), list pages (Hotels-g187147-..., Restaurants-g187147-..., Attractions-g187147-...) or destination pages (Tourism-g187147-...). In reviews mode a list or destination stands for its top places (see Max places per list).

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

City, region or country names, e.g. "Lisbon" or "Tuscany". Looked up with Tripadvisor's destination search; its places of the chosen types are scraped in Tripadvisor ranking order.

## `placeTypes` (type: `array`):

Which lists to read for destinations and Tourism-g... pages. Empty = hotels, restaurants and attractions. List URLs (Hotels-g..., Restaurants-g...) always use their own type.

## `maxItems` (type: `integer`):

Stop after this many items in total (reviews in reviews mode, places in places mode). You pay per item, so this caps the cost.

## `maxReviewsPerPlace` (type: `integer`):

Reviews mode: cap per place. Tripadvisor serves every review of a place (all years, all languages).

## `maxPlacesPerSearch` (type: `integer`):

How many places (Tripadvisor ranking order) are taken from each list URL and from each destination x place type. Empty = 20 in reviews mode; in places mode no per-list cap (Max items still applies).

## `reviewLanguages` (type: `array`):

Only reviews written in these languages (Tripadvisor codes: en, fr, de, es, it, pt, nl, ru, ja, ko, zhCN, zhTW, sv, da, no, pl, tr, el, iw, ar, ...). Empty = all languages, newest first. Filters by the review's original language.

## `reviewsNewerThan` (type: `string`):

Only reviews newer than: a date (YYYY-MM-DD) or a period such as '7 days' or '24 hours'. Reviews are read newest first across all languages and paging stops once a whole page is older (review dates are days).

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this search returned and output only new items or items whose price/status changed. Use with a Schedule; unchanged items are not charged. Reviews: each run checks the newest 'Max reviews per place' reviews of every place and saves only reviews not seen before. Places: compared on rating, ranking position and closed status; with this on, Max items is the number of places watched.

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input.

## `includeDetails` (type: `boolean`):

Places mode: places from lists and destinations already have rating, ranking, address, contact and cuisines/amenities. This adds the rating breakdown (excellent ... terrible counts), photo count and local-language name and address. Place URLs always get them.

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

Apify datacenter proxy (default) works: the scraper reads Tripadvisor's app API, which does not need residential or Unblocker proxies.

## Actor input object example

```json
{
  "mode": "reviews",
  "startUrls": [
    {
      "url": "https://www.tripadvisor.com/Hotel_Review-g187147-d228694-Reviews-Hotel_Malte_Astotel-Paris_Ile_de_France.html"
    }
  ],
  "searchQueries": [],
  "placeTypes": [
    "hotels",
    "restaurants",
    "attractions"
  ],
  "maxItems": 100,
  "maxReviewsPerPlace": 100,
  "maxPlacesPerSearch": 20,
  "reviewLanguages": [],
  "onlyNewOrChanged": false,
  "includeDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (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 = {
    "startUrls": [
        {
            "url": "https://www.tripadvisor.com/Hotel_Review-g187147-d228694-Reviews-Hotel_Malte_Astotel-Paris_Ile_de_France.html"
        }
    ],
    "searchQueries": [],
    "placeTypes": [
        "hotels",
        "restaurants",
        "attractions"
    ],
    "maxPlacesPerSearch": 20,
    "reviewLanguages": [],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/tripadvisor-scraper").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 = {
    "startUrls": [{ "url": "https://www.tripadvisor.com/Hotel_Review-g187147-d228694-Reviews-Hotel_Malte_Astotel-Paris_Ile_de_France.html" }],
    "searchQueries": [],
    "placeTypes": [
        "hotels",
        "restaurants",
        "attractions",
    ],
    "maxPlacesPerSearch": 20,
    "reviewLanguages": [],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/tripadvisor-scraper").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 '{
  "startUrls": [
    {
      "url": "https://www.tripadvisor.com/Hotel_Review-g187147-d228694-Reviews-Hotel_Malte_Astotel-Paris_Ile_de_France.html"
    }
  ],
  "searchQueries": [],
  "placeTypes": [
    "hotels",
    "restaurants",
    "attractions"
  ],
  "maxPlacesPerSearch": 20,
  "reviewLanguages": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/tripadvisor-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tortuga/tripadvisor-scraper"
        }
    }
}
```

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/KWu2f0H1n2fu2rRYJ/builds/KDfdnS4knmkLUlpEd/openapi.json
