kestrel actors docs

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 datahotel review data you can sort, filter and export.

Run TripAdvisor Reviews Scraper on Apify →

TripAdvisor reviews scraper pricing: what one row costs

EventWhat it isPriceCharged for
reviewReview row$0.005One 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.

FieldTypeDefaultWhat it does
startUrlsarray[]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.
locationIdsarray[]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.
hotelNamesarray[]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.
languagesarray["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.
maxReviewsPerHotelinteger1000 = 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.
maxRatingnumber00 = 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.
tripTypesarray[]Keep only reviews from these trip types: family, couples, solo, business, friends. Empty = all. Filtered reviews are never charged.
sinceDatestring""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.
requireTextbooleanfalseDrop rating-only reviews before billing. TripAdvisor reviews almost always carry text, so this rarely removes much.
includeTranslatedbooleantrueEach 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.
includeHotelRowbooleantrueAlso 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.
sessionsinteger2How many residential proxy sessions (egress IPs) run in parallel. More is faster; each is paced separately. Range 1-16.
perIpnumber1Pace for each session. TripAdvisor serves 1 page/s per IP steadily; raising it causes rotations, not speed. Range 0.1-3.
proxyConfigurationobject{"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.

FieldTypeWhat it holds
typestringreview | hotel | status
targetstringThe input value (URL, id or name) this row came from
location_idstringTripAdvisor's numeric location id (the d<number> in its URLs)
geo_idstringTripAdvisor's numeric geo id of the hotel's city (the g<number> in its URLs)
hotel_namestringHotel name as the review page shows it
languagestringSite language the row was read in (en = tripadvisor.com, de = tripadvisor.de, …)
review_idstringTripAdvisor's numeric review id
original_languagestringLanguage the review was written in
translatedbooleantrue when the text is a machine translation into the site language
titlestringReview title
textstringFull review text
ratingnumber1-5 bubbles on review rows; the hotel's overall bubble rating (e.g. 4.7) on hotel rows
sub_ratingsobjectBubbles per aspect the reviewer rated: value, rooms, location, cleanliness, service, sleep_quality
review_datestringPublication date, YYYY-MM-DD
created_datestringDate the review was written, YYYY-MM-DD
stay_datestringMonth of the stay as TripAdvisor records it, YYYY-MM-DD
trip_typestringFAMILY | COUPLES | SOLO | BUSINESS | FRIENDS | null
helpful_votesintegerHelpful votes the review received
reviewer_namestringReviewer display name
reviewer_usernamestringReviewer profile handle
reviewer_verifiedbooleanWhether TripAdvisor marks the reviewer as verified
reviewer_contributionsintegerReviewer's total contributions on TripAdvisor
reviewer_helpful_votesintegerHelpful votes across all of the reviewer's contributions
reviewer_hometownstringReviewer hometown as shown, e.g. "Brooklyn, New York"
photosarrayPhoto URLs attached to the review (1200 px renditions)
photo_countintegerHow many photos the review carries
responsestringThe property's management response text, if any
response_datestringDate of the management response, YYYY-MM-DD
response_idstringTripAdvisor's id of the management response
urlstringDirect URL of the review page (review rows) or of the hotel review page (hotel rows)
hotel_urlstringThe hotel's canonical review page on the site the row was read from
review_countintegerTotal reviews the hotel has across all languages
rating_countsobjectReviews per bubble rating, keys "1"…"5"
reviews_by_languageobjectReviews per language, e.g. {"en": 1393, "fr": 220}
rankingstringTripAdvisor ranking sentence, e.g. "#33 of 372 hotels in Lisbon"
ranking_positionintegerRank position in the city
ranking_ofintegerNumber of hotels ranked in the city
addressstringStreet address
citystringCity
postal_codestringPostal code
country_codestringISO country code
latitudenumberLatitude
longitudenumberLongitude
phonestringPhone as listed
websitestringOfficial website as listed
price_rangestringTripAdvisor price band, e.g. "$$"
amenitiesarrayAmenity names TripAdvisor lists
reviews_listedintegerReviews the site lists for the hotel in this language (translations included)
reviews_fetchedintegerReviews read in this run for the hotel and language before filters
statusstringok | no_reviews | not_found | duplicate | error (status rows)
reviewsintegerReviews delivered for this hotel and language (status rows)
filteredintegerReviews dropped by the filters, never charged (status rows)
pagesintegerReview pages read (status rows)
totalintegerReviews the site lists in this language (status rows)
duplicatesinteger1 when this target resolved to a hotel another target already covers (status rows)
errorstringWhy a target failed (status rows)
fetched_atstringUTC 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 maxRating reads pages and filters them. A complaints feed on a huge hotel is best combined with sinceDate.
  • Language counts differ from the total. review_count on the hotel row is the all-language total (1,977); reviews_listed and total are 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 in reviews_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: false keeps 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_Review pages.

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 runWhat it does
TripAdvisor Negative Reviews for Any HotelTripAdvisor 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 CSVThe 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 IDFour 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 LanguagesOne 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 SetFour Berlin hotels compared on TripAdvisor: rating, review count, rating histogram, six sub-ratings and city ranking per property, twenty reviews each.
TripAdvisor Management Response AuditCritical 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 TravellersOnly 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 DaysOnly 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 TripsEighty 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 ReviewEighty 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 AccessTripAdvisor'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 UKNinety TripAdvisor UK reviews of one London hotel with full text, rating and six sub-ratings on every row - a labelled corpus for sentiment analysis.

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