Important caveat: This guide covers access to publicly available review and listing data only. Before scraping TripAdvisor, review their Terms of Use. In the United States, the Computer Fraud and Abuse Act (CFAA) may apply to unauthorized access. In the EU, the General Data Protection Regulation (GDPR) governs any personal data embedded in reviews. Always consult legal counsel before deploying a scraper at scale.
If you build travel-intelligence dashboards, competitive-review analytics, or sentiment pipelines, you have likely wondered how to scrape TripAdvisor reviews in 2026 without getting blocked. TripAdvisor is one of the largest public sources of hotel and restaurant reviews, but its anti-bot infrastructure has matured significantly. This guide walks through what data is actually public, how TripAdvisor's defenses work, and a production-ready approach using residential proxies and TLS impersonation.
How to Scrape TripAdvisor Reviews in 2026: What's Actually Public
TripAdvisor exposes two main URL patterns for review data:
- /Hotel_Review — e.g.,
https://www.tripadvisor.com/Hotel_Review-g187147-d123456-Reviews-Hotel_Name-Paris_Ile_de_France.html - /Restaurant_Review — e.g.,
https://www.tripadvisor.com/Restaurant_Review-g187147-d123456-Reviews-Restaurant_Name-Paris_Ile_de_France.html
On these pages, the following elements are publicly visible without login:
- Overall rating (1–5 bubbles)
- Individual review title, text, rating, and published date
- Reviewer display name (a pseudonymous handle, not necessarily a real name)
- Review location and contribution count
- Property metadata: address, amenities, price range, category
However, TripAdvisor lazy-loads reviews. The initial HTML response contains only the first 5–10 reviews (or sometimes none — they are fetched via XHR after page load). The remaining reviews are loaded through internal API calls as you scroll or paginate. This means a simple requests.get() will not capture the full review set.
There are two approaches to handle this:
- Render the page with a headless browser (Playwright/Puppeteer) and intercept network calls, or scroll to trigger lazy-loading. This is slow (~3–5 seconds per page) and resource-intensive.
- Call the internal GraphQL endpoint directly, bypassing the DOM entirely. This is faster (~200–500ms per request) and returns structured JSON. This is the approach we recommend for review-analytics pipelines.
TripAdvisor's Anti-Bot Stack: Cloudflare + DataDome
TripAdvisor employs a layered anti-bot defense. Understanding these layers is critical before writing a single line of scraper code.
Cloudflare Bot Management
TripAdvisor sits behind Cloudflare's bot management, which inspects TLS fingerprints, HTTP/2 frame ordering, header sequences, and behavioral signals. Cloudflare's JA3/JA4 fingerprinting identifies clients by their TLS ClientHello — the cryptographic handshake that occurs before any HTTP data is sent. Python's requests library produces a JA3 hash that is instantly recognizable as a non-browser client.
DataDome
On top of Cloudflare, TripAdvisor uses DataDome, a specialized anti-bot solution that adds device fingerprinting, IP reputation scoring, and JavaScript challenges. DataDome is particularly aggressive against datacenter IP ranges. Even if your headers perfectly mimic Chrome, a request from an AWS or DigitalOcean IP block will receive a 403 or a CAPTCHA challenge page within 5–10 requests.
Why Datacenter Proxies Fail
Datacenter IP ranges are published and well-known. DataDome maintains a database of hosting-provider ASNs (Autonomous System Numbers). When a request arrives from an ASN belonging to AWS, Google Cloud, Azure, OVH, or similar, it is flagged immediately — regardless of User-Agent, Accept-Language, or any other header. This is why residential proxies are not optional for TripAdvisor scraping; they are a hard requirement.
| Proxy Type | TripAdvisor Success Rate | Notes |
|---|---|---|
| Datacenter | ~5–10% | Blocked by DataDome within first few requests |
| Mobile | ~85–95% | High trust but expensive; good for low-volume high-value scraping |
| Residential | ~80–90% | Best balance of cost and success for production pipelines |
The Internal GraphQL Endpoint: /data/graphql/ids
When you scroll through reviews on a TripAdvisor listing page, the browser sends a POST request to an internal GraphQL endpoint. The key endpoint is:
POST https://www.tripadvisor.com/data/graphql/ids
This endpoint accepts a GraphQL query body and returns structured JSON containing review nodes, location data, and pagination cursors. The request requires:
- Headers: A valid
Content-Type: application/json, a browser-likeUser-Agent, and critically, anX-Requested-Bytoken (a CSRF-style header that TripAdvisor validates server-side). - Body: A GraphQL query string with variables for the location ID, offset, and limit.
- Cookies: A session cookie (usually
TASessionor similar) that is set on the initial page load.
The X-Requested-By token is typically embedded in the initial HTML response as a JavaScript variable or meta tag. You need to make one initial GET request to the listing page, extract this token, and then use it for subsequent GraphQL POST requests.
Why Geo-Targeted Residential Proxies Are Required
TripAdvisor serves different review sets and localized content based on the visitor's IP geolocation. A request from a US IP may see reviews prioritized by English-language reviewers, while a request from a French IP may prioritize French-language reviews. For comprehensive data collection, you need to rotate through multiple country/city locations.
ProxyHat supports country and city-level geo-targeting via the username field. For example, to route through a London residential IP:
http://user-country-GB-city-london:pass@gate.proxyhat.com:8080
This is essential for capturing localized review content and avoiding pattern detection from a single geographic source.
Python Implementation: curl_cffi + ProxyHat Residential Proxies
Since TripAdvisor's anti-bot stack fingerprints TLS at the protocol level, standard Python HTTP libraries like requests or httpx will fail. The curl_cffi library wraps libcurl with BoringSSL and can impersonate Chrome's TLS fingerprint, including JA3/JA4 hash, HTTP/2 SETTINGS frames, and header order.
Step 1: Install Dependencies
pip install curl_cffi
Step 2: Fetch the Listing Page and Extract the X-Requested-By Token
from curl_cffi import requests
import re, json
# ProxyHat residential proxy with UK geo-targeting
proxy_url = "http://user-country-GB-city-london:pass@gate.proxyhat.com:8080"
listing_url = "https://www.tripadvisor.com/Hotel_Review-g187147-d123456-Reviews-Hotel_Name-Paris.html"
# Impersonate Chrome 120 — curl_cffi matches TLS fingerprint and HTTP/2 settings
response = requests.get(
listing_url,
impersonate="chrome120",
proxies={"http": proxy_url, "https": proxy_url},
timeout=30,
)
html = response.text
# Extract X-Requested-By token from the page
# It is typically in a meta tag or inline JS variable
token_match = re.search(r'"X-Requested-By"\s*:\s*"([^"]+)"', html)
if not token_match:
token_match = re.search(r'data-token="([^"]+)"', html)
x_requested_by = token_match.group(1) if token_match else ""
print(f"Token: {x_requested_by[:20]}...")
Step 3: Post a GraphQL Query for Reviews
graphql_url = "https://www.tripadvisor.com/data/graphql/ids"
# GraphQL query — fetch reviews for a location with offset pagination
query = """
query ReviewsQuery($locationId: Int!, $offset: Int!, $limit: Int!) {
location(locationId: $locationId) {
reviewList(page: { offset: $offset, limit: $limit }) {
totalCount
reviews {
id
title
rating
text
publishedDate
userProfile {
displayName
}
}
}
}
}
"""
variables = {
"locationId": 123456,
"offset": 0,
"limit": 10,
}
payload = [
{
"query": query,
"variables": variables,
}
]
headers = {
"Content-Type": "application/json",
"X-Requested-By": x_requested_by,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "application/json",
"Referer": listing_url,
"Origin": "https://www.tripadvisor.com",
}
# Use a sticky session for continuity — same IP for token + GraphQL
gql_response = requests.post(
graphql_url,
json=payload,
headers=headers,
impersonate="chrome120",
proxies={"http": proxy_url, "https": proxy_url},
timeout=30,
)
data = gql_response.json()
# Parse the first review node
review = data[0]["data"]["location"]["reviewList"]["reviews"][0]
print(f"Title: {review['title']}")
print(f"Rating: {review['rating']}")
print(f"Date: {review['publishedDate']}")
print(f"Text: {review['text'][:200]}...")
Step 4: Node.js Alternative with undici
For Node.js teams, the same pattern works with undici and a TLS impersonation layer, though Node.js does not have a direct equivalent to curl_cffi. Many teams use got with custom TLS options or run a local Playwright instance for the initial token fetch, then switch to direct HTTP for GraphQL calls.
const { request } = require('undici');
const proxyUrl = 'http://user-country-GB-city-london:pass@gate.proxyhat.com:8080';
const graphqlUrl = 'https://www.tripadvisor.com/data/graphql/ids';
async function fetchReviews(token, locationId, offset) {
const body = JSON.stringify([{
query: `query($locationId: Int!, $offset: Int!, $limit: Int!) {
location(locationId: $locationId) {
reviewList(page: { offset: $offset, limit: $limit }) {
reviews { id title rating text publishedDate }
}
}
}`,
variables: { locationId, offset, limit: 10 }
}]);
const res = await request(graphqlUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-By': token,
'Referer': 'https://www.tripadvisor.com',
},
body,
// Route through ProxyHat — use a proxy dispatcher in production
});
const data = await res.body.json();
return data[0].data.location.reviewList.reviews;
}
Rate Limits, Sticky Sessions, and Pagination
TripAdvisor does not publish official rate limits for scraping, but empirical testing reveals consistent patterns:
- ~50–100 listing pages per hour per IP before DataDome starts issuing challenges.
- ~5–10 minute cooldown after a block before the same IP can be reused.
- GraphQL endpoints tend to be slightly more forgiving than full-page loads, but sustained high-volume requests from a single IP will still trigger blocks.
Sticky Sessions for Token Continuity
The X-Requested-By token and session cookies are tied to the IP that fetched the initial page. If you rotate IPs between the initial GET and the GraphQL POST, the token may be rejected. Use ProxyHat's sticky session feature:
# Sticky session — same IP for all requests in this session
proxy_url = "http://user-country-GB-city-london-session-myhotel123:pass@gate.proxyhat.com:8080"
The -session-myhotel123 flag ensures all requests with the same session ID route through the same residential IP. Use a unique session ID per listing to maintain continuity, and rotate to a new session for the next listing.
Backoff Strategy
import time, random
def scrape_with_backoff(listing_ids, proxy_base):
results = []
for idx, loc_id in enumerate(listing_ids):
session_id = f"listing-{loc_id}"
proxy = f"http://user-country-GB-city-london-session-{session_id}:pass@gate.proxyhat.com:8080"
try:
reviews = fetch_reviews_for_location(loc_id, proxy)
results.extend(reviews)
# Random delay: 3–8 seconds between listings
time.sleep(random.uniform(3, 8))
except Exception as e:
print(f"Blocked on {loc_id}: {e}")
# Exponential backoff after a block
backoff = min(60 * (2 ** (idx % 4)), 600)
time.sleep(backoff)
return results
Pagination Offsets
The GraphQL offset parameter controls which page of reviews you fetch. TripAdvisor typically returns 10 reviews per request. For a location with 500 reviews, you need 50 paginated requests. Increase the delay between pagination calls within the same session to avoid triggering behavioral detection:
for offset in range(0, total_reviews, 10):
reviews = fetch_reviews(loc_id, offset, proxy_url)
time.sleep(random.uniform(2, 5)) # 2–5s between pages
Common Mistakes and Edge Cases
- Using
requestsinstead ofcurl_cffi: The TLS fingerprint mismatch causes instant 403s. Always usecurl_cffiwithimpersonate="chrome120"or similar. - Rotating IPs mid-session: The
X-Requested-Bytoken is IP-bound. Use sticky sessions. - Ignoring
RefererandOriginheaders: The GraphQL endpoint validates that requests originate from a TripAdvisor page. Missing these headers triggers blocks. - Scraping too fast: Even with perfect TLS impersonation and residential IPs, requesting 200+ pages per hour per IP will trigger DataDome. Stay within 50–100/hour.
- Not handling truncated review text: TripAdvisor truncates long review text in the API response with an ellipsis. The full text may require a separate request to the review detail page.
- Forgetting to parse the GraphQL response as an array: The endpoint returns a JSON array (batched queries), not a single object. Access
data[0]for the first query result.
ProxyHat Setup and Configuration
Configuring ProxyHat for TripAdvisor scraping is straightforward. All requests route through gate.proxyhat.com on port 8080 for HTTP or 1080 for SOCKS5. Geo-targeting and session flags go directly in the username field.
For TripAdvisor, we recommend:
- Residential proxies with country-level geo-targeting matching your target market.
- Sticky sessions per listing to maintain token continuity.
- City-level targeting when you need reviews from a specific locale (e.g.,
-country-FR-city-parisfor Paris restaurant reviews).
Check out ProxyHat pricing for residential proxy plans, or browse available proxy locations to see supported countries and cities. For broader web-scraping strategies, see our web scraping use case guide. If you are also tracking search rankings, our SERP tracking page covers complementary techniques. Full connection details are in the ProxyHat documentation.
Ethical Scraping and When to Use Official APIs
Scraping TripAdvisor reviews raises both technical and ethical questions. Here are the principles we recommend:
Aggregate Only — No Personal Data Harvesting
Reviews on TripAdvisor are written by pseudonymous users. However, reviewer display names, profile photos, and contribution counts may constitute personal data under GDPR if they can be linked to an identifiable individual. For analytics pipelines:
- Store only aggregate metrics: average rating, review count, sentiment scores, keyword frequency.
- Do not persist reviewer display names unless you have a legitimate legal basis under GDPR (e.g., the reviewer has consented, or you are processing for a lawful business purpose with appropriate safeguards).
- Anonymize or hash reviewer IDs if you need to track repeat reviewers for quality scoring.
GDPR Considerations for EU Reviewers
Under GDPR Article 5, personal data must be processed lawfully, fairly, and transparently. If you scrape reviews written by EU residents, you may be processing personal data. Key considerations:
- Review text may contain incidental personal data (e.g., a reviewer mentioning their full name or contact details).
- Data minimization: collect only what you need for your stated purpose.
- Storage limitation: do not retain personal data longer than necessary.
- If a reviewer requests deletion of their data, you must be able to comply.
When to Use TripAdvisor's Official Content API
TripAdvisor offers an official Content API for commercial partners. If your use case involves:
- Displaying TripAdvisor content on a commercial website or app.
- Real-time review data for a hotel or restaurant's own listing.
- High-volume, reliable data access with SLA guarantees.
...then the official API is the right choice. It provides structured data, official licensing, and no risk of IP blocks. The trade-off is cost (pricing is typically negotiated per use case) and potential restrictions on data retention and redistribution.
For research, competitive analysis, or internal analytics where you only need aggregate review metrics, scraping public data with residential proxies remains a viable approach — provided you respect rate limits, ToS, and data protection laws.
Key Takeaways
- TripAdvisor uses Cloudflare + DataDome for anti-bot defense; datacenter IPs are blocked regardless of headers.
- Reviews are lazy-loaded via an internal GraphQL endpoint (
/data/graphql/ids) requiring anX-Requested-Bytoken extracted from the initial page load.- Use
curl_cffiwith Chrome TLS impersonation — standard Pythonrequestswill fail due to JA3/JA4 fingerprinting.- Residential proxies with country/city geo-targeting and sticky sessions are essential for token continuity and localized data.
- Stay within ~50–100 listings/hour per IP with 3–8 second delays between requests and exponential backoff on blocks.
- Aggregate review data only — avoid persisting reviewer display names or personal data to stay compliant with GDPR.
- For commercial display use cases, consider TripAdvisor's official Content API instead of scraping.
Frequently Asked Questions
What is TripAdvisor review scraping in 2026?
TripAdvisor review scraping in 2026 refers to programmatically collecting publicly visible hotel and restaurant reviews from TripAdvisor listing pages. Because TripAdvisor lazy-loads reviews through an internal GraphQL endpoint and protects its site with Cloudflare and DataDome, scraping now requires TLS fingerprint impersonation (via tools like curl_cffi) and residential proxies to avoid detection. The goal is typically to gather aggregate review metrics — ratings, text, dates, and sentiment — for competitive analysis or travel intelligence.
Why do residential proxies matter for scraping TripAdvisor?
Residential proxies matter because TripAdvisor's anti-bot provider, DataDome, maintains a database of datacenter IP ranges (AWS, Azure, OVH, etc.) and blocks requests from those ASNs within the first few requests — regardless of how well your headers mimic a real browser. Residential IPs are assigned by ISPs to real households, making them indistinguishable from organic user traffic. Combined with TLS impersonation via curl_cffi, residential proxies achieve 80–90% success rates compared to 5–10% for datacenter IPs. Geo-targeting (country/city) also ensures you see localized review content.
Which proxy type works best for TripAdvisor scraping?
Residential proxies offer the best balance of cost and success rate (80–90%) for TripAdvisor scraping. Mobile proxies have even higher trust scores (85–95%) but are significantly more expensive and better suited for low-volume, high-value scraping. Datacenter proxies are essentially useless against DataDome. For production pipelines, use residential proxies with sticky sessions per listing (to maintain X-Requested-By token continuity) and country-level geo-targeting to capture localized reviews. ProxyHat supports all three types through gate.proxyhat.com:8080.
How do you avoid blocks when scraping TripAdvisor reviews?
To avoid blocks: (1) use curl_cffi with Chrome TLS impersonation to match the JA3/JA4 fingerprint of a real browser; (2) route through residential proxies with sticky sessions so the X-Requested-By token and session cookies remain valid; (3) limit request speed to 50–100 listings per hour per IP with 3–8 second random delays; (4) include proper Referer and Origin headers on GraphQL POST requests; (5) implement exponential backoff (starting at 60s, doubling up to 600s) when you receive 403 or CAPTCHA responses; (6) rotate to a new sticky session and geo-location after each listing.
Is scraping TripAdvisor reviews legal?
The legality depends on jurisdiction and use case. In the US, the CFAA may apply to unauthorized access, though public data scraping has some protections. In the EU, GDPR governs any personal data in reviews (reviewer names, profile data). TripAdvisor's Terms of Use also restrict automated access. For internal analytics using only aggregate metrics (average ratings, review counts, sentiment), the legal risk is lower. For commercial redistribution or personal data harvesting, consult legal counsel and consider TripAdvisor's official Content API instead.






