kestrel actors › Guest & customer reviews
TripAdvisor Reviews Scraper — Hotel Guest Reviews & Ratings
A tripadvisor reviews scraper — a hotel reviews scraper for tripadvisor hotel reviews — that returns every review a hotel has as structured rows: tripadvisor ratings as 1–5 bubbles, the title and the full text, the six sub-ratings (value, rooms, location, cleanliness, service, sleep quality), the language it was written in and whether you are reading a machine translation, the stay date and trip type, the reviewer's profile, photos, helpful votes and the hotel's management response. It is a tripadvisor scraper for guest reviews built for review monitoring: give it hotels, get tripadvisor review data — hotel review data you can sort, filter and export.
Run TripAdvisor Reviews Scraper on Apify →
TripAdvisor reviews scraper pricing: what one row costs
| Event | What it is | Price | Charged for |
|---|---|---|---|
review | Review row | $0.005 | One TripAdvisor guest review: 1-5 bubbles, title, full text, six sub-ratings, language and original language, stay date, trip type, reviewer profile, photos and the management response. Hotels with no reviews, unknown ids and filtered reviews are free. |
$0.005 per review row. Hotel rows, status rows, filtered reviews, unknown ids, duplicate targets and reviews the spending limit refused are free. Every review a hotel has on the English site — say 1,456 — is $7.28; a daily complaints feed that finds two complaints a week costs cents a month. Set maxReviewsPerHotel and sinceDate to keep runs the size you want, and the run's maxTotalChargeUsd as a hard ceiling. Residential proxy traffic (about a megabyte per ten reviews) is included in the price.
TripAdvisor reviews scraper input reference
Every field of TripAdvisor Reviews, straight from the actor's input schema.
| Field | Type | Default | What it does |
|---|---|---|---|
startUrls | array | [] | Hotel pages on any TripAdvisor domain, e.g. https://www.tripadvisor.com/Hotel_Review-g189158-d4509998-Reviews-Memmo_Alfama_Hotel-Lisbon.html — the geo id and slug do not have to be right, the numeric d<id> is what counts. Any query string is fine. |
locationIds | array | [] | The numeric ids after d in TripAdvisor URLs, e.g. 4509998 or d4509998 — what an earlier run's location_id gives you. The fastest path: no lookup at all. |
hotelNames | array | [] | Hotel names, ideally with the city ("Memmo Alfama Lisbon"). Resolved through TripAdvisor's own typeahead; a hit must share at least half of the words you typed, so a nonsense name comes back as an error row instead of a random hotel. The resolved name is in the hotel and status rows so you can check the match. |
languages | array | ["en"] | Which TripAdvisor sites to read — each site serves the reviews in its own language, machine-translated ones included: en (tripadvisor.com), en-gb, de, fr, es, it, pt (tripadvisor.com.br), nl, ja, zh, ru, sv, da, no, fi, pl, tr, el, ko, th, vi, id, cs, hu, he, en-au, en-ca, en-in, en-ie, en-sg. One hotel × one language = one job; the same review can appear once per language (as a translation), so pick the languages you need. |
maxReviewsPerHotel | integer | 100 | 0 = every review the site lists for the hotel in that language (10 per page; popular hotels run into the thousands, and each page is about a megabyte of residential proxy traffic). N = the newest N. The main cost control. Range 0-20000. |
maxRating | number | 0 | 0 = keep every review. 1-5 = keep only reviews with that many bubbles or fewer — 2 gives a complaints feed. Filtered reviews are never charged (the pages are still read, so combine with a sensible max). Range 0-5. |
tripTypes | array | [] | Keep only reviews from these trip types: family, couples, solo, business, friends. Empty = all. Filtered reviews are never charged. |
sinceDate | string | "" | YYYY-MM-DD, or relative so schedules never go stale: "30 days", "2 weeks", "6 months". Pages come newest first, so the run stops reading once a whole page predates the date — a daily schedule reads one or two pages per hotel. Empty = no date limit. |
requireText | boolean | false | Drop rating-only reviews before billing. TripAdvisor reviews almost always carry text, so this rarely removes much. |
includeTranslated | boolean | true | Each site shows reviews written in other languages as machine translations (rows carry translated = true and the original_language). Untick to keep only reviews written in the site's language — with several languages selected that also stops the same review arriving once per language. |
includeHotelRow | boolean | true | Also emit one row per hotel and language with its ids, name, bubble rating and review count, the count of reviews per rating and per language, six sub-ratings, its ranking in the city, address, coordinates, phone, website and amenities. Never charged. |
sessions | integer | 2 | How many residential proxy sessions (egress IPs) run in parallel. More is faster; each is paced separately. Range 1-16. |
perIp | number | 1 | Pace for each session. TripAdvisor serves 1 page/s per IP steadily; raising it causes rotations, not speed. Range 0.1-3. |
proxyConfiguration | object | {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]} | Apify Proxy with the RESIDENTIAL group is required: TripAdvisor's bot gate refuses every datacenter range outright, and only residential IPs are served. Keep the default. |
Example input
{
"locationIds": ["4509998", "228423"],
"hotelNames": ["The Lumiares Lisbon", "Bairro Alto Hotel Lisbon", "Memmo Príncipe Real"],
"languages": ["en", "de"],
"sinceDate": "2 days",
"maxRating": 2,
"requireText": true,
"maxReviewsPerHotel": 0
}
{
"startUrls": [
"https://www.tripadvisor.com/Hotel_Review-g189158-d4509998-Reviews-Memmo_Alfama_Hotel-Lisbon.html",
"https://www.tripadvisor.com/Hotel_Review-g189158-d190364-Reviews-x.html"
],
"languages": ["fr"],
"includeTranslated": false,
"maxReviewsPerHotel": 0
}
TripAdvisor reviews scraper output fields
One row per guest review (charged), plus a free hotel context row and a free status row per hotel and language.
Dataset views in the Apify Console: Overview, Reviews, Complaints, Hotels, Status.
| Field | Type | What it holds |
|---|---|---|
type | string | review | hotel | status |
target | string | The input value (URL, id or name) this row came from |
location_id | string | TripAdvisor's numeric location id (the d<number> in its URLs) |
geo_id | string | TripAdvisor's numeric geo id of the hotel's city (the g<number> in its URLs) |
hotel_name | string | Hotel name as the review page shows it |
language | string | Site language the row was read in (en = tripadvisor.com, de = tripadvisor.de, …) |
review_id | string | TripAdvisor's numeric review id |
original_language | string | Language the review was written in |
translated | boolean | true when the text is a machine translation into the site language |
title | string | Review title |
text | string | Full review text |
rating | number | 1-5 bubbles on review rows; the hotel's overall bubble rating (e.g. 4.7) on hotel rows |
sub_ratings | object | Bubbles per aspect the reviewer rated: value, rooms, location, cleanliness, service, sleep_quality |
review_date | string | Publication date, YYYY-MM-DD |
created_date | string | Date the review was written, YYYY-MM-DD |
stay_date | string | Month of the stay as TripAdvisor records it, YYYY-MM-DD |
trip_type | string | FAMILY | COUPLES | SOLO | BUSINESS | FRIENDS | null |
helpful_votes | integer | Helpful votes the review received |
reviewer_name | string | Reviewer display name |
reviewer_username | string | Reviewer profile handle |
reviewer_verified | boolean | Whether TripAdvisor marks the reviewer as verified |
reviewer_contributions | integer | Reviewer's total contributions on TripAdvisor |
reviewer_helpful_votes | integer | Helpful votes across all of the reviewer's contributions |
reviewer_hometown | string | Reviewer hometown as shown, e.g. "Brooklyn, New York" |
photos | array | Photo URLs attached to the review (1200 px renditions) |
photo_count | integer | How many photos the review carries |
response | string | The property's management response text, if any |
response_date | string | Date of the management response, YYYY-MM-DD |
response_id | string | TripAdvisor's id of the management response |
url | string | Direct URL of the review page (review rows) or of the hotel review page (hotel rows) |
hotel_url | string | The hotel's canonical review page on the site the row was read from |
review_count | integer | Total reviews the hotel has across all languages |
rating_counts | object | Reviews per bubble rating, keys "1"…"5" |
reviews_by_language | object | Reviews per language, e.g. {"en": 1393, "fr": 220} |
ranking | string | TripAdvisor ranking sentence, e.g. "#33 of 372 hotels in Lisbon" |
ranking_position | integer | Rank position in the city |
ranking_of | integer | Number of hotels ranked in the city |
address | string | Street address |
city | string | City |
postal_code | string | Postal code |
country_code | string | ISO country code |
latitude | number | Latitude |
longitude | number | Longitude |
phone | string | Phone as listed |
website | string | Official website as listed |
price_range | string | TripAdvisor price band, e.g. "$$" |
amenities | array | Amenity names TripAdvisor lists |
reviews_listed | integer | Reviews the site lists for the hotel in this language (translations included) |
reviews_fetched | integer | Reviews read in this run for the hotel and language before filters |
status | string | ok | no_reviews | not_found | duplicate | error (status rows) |
reviews | integer | Reviews delivered for this hotel and language (status rows) |
filtered | integer | Reviews dropped by the filters, never charged (status rows) |
pages | integer | Review pages read (status rows) |
total | integer | Reviews the site lists in this language (status rows) |
duplicates | integer | 1 when this target resolved to a hotel another target already covers (status rows) |
error | string | Why a target failed (status rows) |
fetched_at | string | UTC timestamp of the request |
Example row from a real run
Taken from the actor's README — this is the shape your dataset holds.
{
"type": "review",
"target": "https://www.tripadvisor.com/Hotel_Review-g189158-d4509998-Reviews-Memmo_Alfama_Hotel-Lisbon_Lisbon_District_Central_Portugal.html",
"review_id": "1075128384",
"location_id": "4509998",
"hotel_name": "Memmo Alfama Hotel",
"language": "en",
"original_language": "en",
"translated": false,
"title": "A Gem in the Heart of Alfama",
"text": "This place is a gem!\nOn a quiet side street just off the route of the famous tram Electrico #28, this is a gorgeous haven in the heart of Alfama. Our room had a view out over the Tagus River…",
"rating": 5,
"sub_ratings": {"value": 4, "rooms": 4, "location": 5, "cleanliness": 5, "service": 5, "sleep_quality": 5},
"review_date": "2026-08-27",
"created_date": "2026-08-27",
"stay_date": "2026-08-31",
"trip_type": "COUPLES",
"helpful_votes": 0,
"reviewer_name": "Frank S",
"reviewer_username": "992franks",
"reviewer_verified": false,
"reviewer_contributions": 391,
"reviewer_helpful_votes": 169,
"reviewer_hometown": "Brooklyn, New York",
"photos": [],
"photo_count": 0,
"response": "Dear Frank, thank you so much for your incredible review…",
"response_date": null,
"response_id": "974781822",
"url": "https://www.tripadvisor.com/ShowUserReviews-g189158-d4509998-r1075128384-Memmo_Alfama_Hotel-Lisbon_Lisbon_District_Central_Portugal.html",
"hotel_url": "https://www.tripadvisor.com/Hotel_Review-g189158-d4509998-Reviews-Memmo_Alfama_Hotel-Lisbon_Lisbon_District_Central_Portugal.html",
"fetched_at": "2026-08-29T15:20:11+00:00"
}
TripAdvisor reviews scraper in Python, JavaScript and curl
Python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("kestrel/tripadvisor-reviews-scraper").call(run_input={
"locationIds": ["4509998"],
"languages": ["en", "fr"],
"maxRating": 3,
"requireText": True,
"maxReviewsPerHotel": 500,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if row["type"] == "review":
print(row["language"], row["rating"], row["review_date"], row["title"], "-", (row["response"] or "")[:40])
JavaScript (Node)
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('kestrel/tripadvisor-reviews-scraper').call({
hotelNames: ['Memmo Alfama Lisbon', 'The Lumiares Lisbon'],
sinceDate: '30 days',
includeTranslated: false,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const reviews = items.filter(r => r.type === 'review');
console.log(reviews.length, 'reviews;', reviews.filter(r => r.response).length, 'answered by the hotel');
curl
curl -X POST "https://api.apify.com/v2/acts/kestrel~tripadvisor-reviews-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"startUrls": ["https://www.tripadvisor.com/Hotel_Review-g189158-d4509998-Reviews-Memmo_Alfama_Hotel-Lisbon.html"], "maxReviewsPerHotel": 50}'
The same three calls are runnable files in the examples repository: examples/tripadvisor-reviews-scraper.py|.js|.sh.
Limits and honest notes
- Newest first only. TripAdvisor's pages sort by date and expose no rating or helpfulness sort, so
maxRatingreads pages and filters them. A complaints feed on a huge hotel is best combined withsinceDate. - Language counts differ from the total.
review_counton the hotel row is the all-language total (1,977);reviews_listedandtotalare what the site you read lists in its language, translations included (1,456 on the English site, 595 on the German site). Native-language counts are inreviews_by_language. - A translation is a separate row per language. With
languages: ["en", "de"]a German-written review appears once from tripadvisor.de (original) and once from tripadvisor.com (machine-translated).includeTranslated: falsekeeps each review exactly once. - Residential proxy is not optional. TripAdvisor's bot gate refuses every datacenter range; the actor also needs a Firefox-grade TLS fingerprint, which it carries itself. A refused page is rotated and retried, and after six refusals the hotel is reported as an
error— never as "no reviews". - Pages are heavy. About one megabyte per ten reviews, paced at one page per second per session. Two sessions read roughly 20 reviews a second.
- Hotels only. Restaurants, attractions and vacation rentals have different page shapes; give the actor
Hotel_Reviewpages.
FAQ
Does it need a TripAdvisor API key or login?
No. There is no public tripadvisor api for reading reviews (the Content API is for partners and does not return review text); the actor reads the public review pages, which carry the full record.
Can I download TripAdvisor reviews as CSV or Excel?
Yes. Every run writes an Apify dataset; open it in the Console and export tripadvisor reviews CSV, Excel, JSON or XML, or pull it through the API. The reviews and complaints views are ready-made column layouts.
How do I get only TripAdvisor negative reviews?
Set maxRating to 2 (or 3). Reviews above it are dropped before billing. Add requireText: true so every row has something to read, and sinceDate for a rolling window.
Can I get TripAdvisor reviews by location id, URL or name?
Any of the three. Ids are fastest; URLs need no lookup either (only the d<id> in them matters); names go through TripAdvisor's typeahead with a guard against wrong matches.
How many reviews can one hotel return?
All of them, per language: maxReviewsPerHotel: 0 walks every page the site lists. Large hotels have thousands; a sinceDate or a cap keeps a scheduled run small.
Can I get TripAdvisor reviews in multiple languages, and are they translated?
You choose the sites with languages; each site shows reviews written in its language plus machine translations of the others, marked translated: true with the original_language. Untick includeTranslated to keep originals only.
Does it include the TripAdvisor management response?
Yes — the tripadvisor management response is in response, with response_date and response_id when TripAdvisor exposes them.
Can I scrape TripAdvisor reviews without an API?
That is what this is — tripadvisor reviews without API access: the review pages are read directly, no GraphQL, no tokens, no browser. If TripAdvisor changes its pages the actor is fixed, and a daily canary run catches breakage within a day.
Can I use it for hotel sentiment analysis?
Yes — the six sub-ratings, the free text and the trip type per review are the inputs sentiment work needs, and the original_language lets you route each text to the right model.
What do bulk hotel reviews cost?
$0.005 per review, nothing else. Ten hotels × 500 newest reviews = 5,000 rows = $25; the daily feed that follows costs only what is new.
How to use TripAdvisor Reviews Scraper
Ready-made runs you can open and start
Each one is a saved input on the Apify Store — open it, press Start, and it runs with the fields already filled in. All 163 across the suite.
| Ready-made run | What it does |
|---|---|
| TripAdvisor Negative Reviews for Any Hotel | TripAdvisor reviews rated two bubbles or fewer for one Singapore hotel, newest first, with sub-ratings and the management reply - complaints only. |
| Download TripAdvisor Reviews to CSV | The hundred newest TripAdvisor reviews of one Berlin hotel with rating, title, text, sub-ratings, stay date and trip type, exportable as CSV or JSON. |
| TripAdvisor Reviews by Location ID | Four Lisbon hotels by TripAdvisor location id in one run, twenty-five newest reviews each - no lookup step; the ids come from any hotel URL's d-number. |
| TripAdvisor Reviews in Multiple Languages | One Vienna hotel read from the English, German and French TripAdvisor sites, originals only, thirty reviews per language with the language on every row. |
| TripAdvisor Competitor Reviews: Berlin Comp Set | Four Berlin hotels compared on TripAdvisor: rating, review count, rating histogram, six sub-ratings and city ranking per property, twenty reviews each. |
| TripAdvisor Management Response Audit | Critical TripAdvisor reviews of one Paris hotel with the management response beside each one - and an empty field where the hotel never answered. |
| TripAdvisor Hotel Reviews from Business Travellers | Only business-trip TripAdvisor reviews of two Frankfurt hotels, forty per property, with the six sub-ratings corporate travel buyers compare on. |
| Review Monitoring: TripAdvisor, Last 30 Days | Only TripAdvisor reviews from the last thirty days for three US hotels by location id - the run stops at the date cut, so a weekly schedule stays cheap. |
| TripAdvisor Guest Feedback from Family Trips | Eighty newest TripAdvisor reviews written by families about one Dubai resort, other trip types never billed, each with sub-ratings and the stay date. |
| TripAdvisor Ratings with Six Sub-Ratings per Review | Eighty TripAdvisor reviews of one Tokyo hotel, each with the overall bubble rating and the six sub-ratings: which of rooms, service or value drags it. |
| TripAdvisor Reviews Without API Access | TripAdvisor's API is partner-only and returns five reviews. This is the replacement: one hotel URL, forty newest reviews, no key and no contract needed. |
| Hotel Sentiment Analysis Data from TripAdvisor UK | Ninety TripAdvisor UK reviews of one London hotel with full text, rating and six sub-ratings on every row - a labelled corpus for sentiment analysis. |
Related scrapers
Run TripAdvisor Reviews Scraper
The actor lives on the Apify Store, where the pricing tab carries the live per-row price and the input form has every field above: apify.com/kestrel/tripadvisor-reviews-scraper